@kasuvia/sdk 0.0.1 → 0.0.4

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 (69) hide show
  1. package/README.md +1 -1
  2. package/dist/hooks/index.d.mts +429 -0
  3. package/dist/hooks/index.d.ts +429 -0
  4. package/dist/hooks/index.js +3073 -0
  5. package/dist/hooks/index.js.map +1 -0
  6. package/dist/hooks/index.mjs +2962 -0
  7. package/dist/hooks/index.mjs.map +1 -0
  8. package/dist/index.d.mts +279 -1152
  9. package/dist/index.d.ts +279 -1152
  10. package/dist/index.js +1471 -2208
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +1451 -2107
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/sdk-context-Cy51kEKT.d.mts +565 -0
  15. package/dist/sdk-context-Cy51kEKT.d.ts +565 -0
  16. package/package.json +6 -2
  17. package/src/config/index.ts +10 -91
  18. package/src/constants.ts +13 -0
  19. package/src/context/sdk-context.tsx +70 -0
  20. package/src/graphql/collections.graphql.ts +2 -10
  21. package/src/graphql/products.graphql.ts +215 -65
  22. package/src/graphql/wishlist.graphql.ts +7 -6
  23. package/src/hooks/index.ts +2 -0
  24. package/src/hooks/use-auth.ts +82 -158
  25. package/src/hooks/use-bespoke-availability.ts +25 -8
  26. package/src/hooks/use-cart.ts +222 -119
  27. package/src/hooks/use-cms.ts +179 -86
  28. package/src/hooks/use-collections.ts +52 -15
  29. package/src/hooks/use-consultation-stream.ts +4 -3
  30. package/src/hooks/use-consultations.ts +120 -51
  31. package/src/hooks/use-countries.ts +35 -13
  32. package/src/hooks/use-currencies.ts +26 -13
  33. package/src/hooks/use-google-translate.ts +22 -8
  34. package/src/hooks/use-languages.ts +40 -20
  35. package/src/hooks/use-mobile.ts +23 -0
  36. package/src/hooks/use-order-stream.ts +9 -5
  37. package/src/hooks/use-orders.ts +99 -44
  38. package/src/hooks/use-payment.ts +108 -40
  39. package/src/hooks/use-products.ts +251 -53
  40. package/src/hooks/use-service-booking.ts +152 -90
  41. package/src/hooks/use-states.ts +35 -15
  42. package/src/hooks/use-wishlist.ts +92 -91
  43. package/src/index.ts +27 -28
  44. package/src/services/auth.service.ts +209 -167
  45. package/src/services/bespoke.service.ts +12 -4
  46. package/src/services/cart.service.ts +172 -70
  47. package/src/services/cms.service.ts +70 -35
  48. package/src/services/collection.service.ts +22 -5
  49. package/src/services/config.service.ts +34 -14
  50. package/src/services/consultation.service.ts +72 -18
  51. package/src/services/logistics.service.ts +35 -11
  52. package/src/services/notifications.service.ts +27 -12
  53. package/src/services/order.service.ts +74 -15
  54. package/src/services/payment.service.ts +86 -31
  55. package/src/services/product.service.ts +279 -39
  56. package/src/services/service-booking.service.ts +98 -26
  57. package/src/services/wishlist.service.ts +69 -25
  58. package/src/types/auth/index.ts +27 -4
  59. package/src/types/business/index.ts +7 -2
  60. package/src/types/payments/index.ts +3 -3
  61. package/src/types/services/index.ts +2 -5
  62. package/src/types/store/index.ts +44 -5
  63. package/src/utils/customer.ts +14 -0
  64. package/src/utils/error-handler.ts +10 -5
  65. package/src/utils/storage.ts +93 -0
  66. package/src/utils/validators.ts +85 -0
  67. package/src/client/authClient.ts +0 -135
  68. package/src/client/graphqlClient.ts +0 -53
  69. package/src/client/httpClient.ts +0 -298
package/dist/index.mjs CHANGED
@@ -1,558 +1,42 @@
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;
1
+ // src/context/sdk-context.tsx
2
+ import { createContext, useContext } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ var SdkContext = createContext(null);
5
+ function SdkProvider({ config, accessToken, children }) {
6
+ return /* @__PURE__ */ jsx(SdkContext.Provider, { value: { config, accessToken }, children });
15
7
  }
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;
8
+ function useSdkContext() {
9
+ return useContext(SdkContext);
25
10
  }
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
11
 
86
- // src/utils/sanitize-url.ts
87
- var InvalidBaseURLError = class extends Error {
88
- constructor(message) {
89
- super(message);
90
- this.name = "InvalidBaseURLError";
91
- }
12
+ // src/constants.ts
13
+ var STORAGE_KEYS = {
14
+ ACCESS_TOKEN: "kasuvia_access_token",
15
+ REFRESH_TOKEN: "kasuvia_refresh_token",
16
+ CHECKOUT_STATE: "kasuvia_checkout_state",
17
+ ORDERS_LINKED: "kasuvia_orders_linked",
18
+ STOREFRONT_STATE: "storefront_state_v3"
92
19
  };
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
20
 
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
- }
21
+ // src/types/store/index.ts
22
+ var ServiceTypeEnum = /* @__PURE__ */ ((ServiceTypeEnum2) => {
23
+ ServiceTypeEnum2["APPOINTMENT"] = "appointment";
24
+ ServiceTypeEnum2["PROJECT"] = "project";
25
+ ServiceTypeEnum2["RECURRING"] = "recurring";
26
+ return ServiceTypeEnum2;
27
+ })(ServiceTypeEnum || {});
28
+ var ServiceLocationTypeEnum = /* @__PURE__ */ ((ServiceLocationTypeEnum2) => {
29
+ ServiceLocationTypeEnum2["REMOTE"] = "remote";
30
+ ServiceLocationTypeEnum2["PHYSICAL"] = "physical";
31
+ ServiceLocationTypeEnum2["BOTH"] = "both";
32
+ return ServiceLocationTypeEnum2;
33
+ })(ServiceLocationTypeEnum || {});
34
+ var ServiceRecurringIntervalEnum = /* @__PURE__ */ ((ServiceRecurringIntervalEnum2) => {
35
+ ServiceRecurringIntervalEnum2["WEEKLY"] = "weekly";
36
+ ServiceRecurringIntervalEnum2["MONTHLY"] = "monthly";
37
+ ServiceRecurringIntervalEnum2["YEARLY"] = "yearly";
38
+ return ServiceRecurringIntervalEnum2;
39
+ })(ServiceRecurringIntervalEnum || {});
556
40
 
557
41
  // src/services/cart.service.ts
558
42
  function parseItems(items) {
@@ -561,21 +45,25 @@ function parseItems(items) {
561
45
  variant_attributes: item.variant_attributes && typeof item.variant_attributes === "string" ? JSON.parse(item.variant_attributes) : item.variant_attributes
562
46
  }));
563
47
  }
564
- async function getGuestCart() {
565
- const sid = getGuestSessionId();
566
- if (!sid) return [];
48
+ async function getGuestCart(config, guestSessionId) {
49
+ if (!guestSessionId) return [];
567
50
  try {
568
- const { data } = await storeManagementAxios.get("cart/", {
569
- headers: { "X-Guest-Session": sid }
51
+ const response = await fetch(`${config.backendUrls.store}/cart/`, {
52
+ headers: {
53
+ "X-Storefront-Key": config.storefrontApiKey,
54
+ "X-Business-ID": config.businessId,
55
+ "X-Guest-Session": guestSessionId
56
+ }
570
57
  });
58
+ if (!response.ok) return [];
59
+ const data = await response.json();
571
60
  return parseItems(data.items || []);
572
61
  } catch {
573
62
  return [];
574
63
  }
575
64
  }
576
- async function addToGuestCart(item) {
577
- const sid = getOrCreateGuestSessionId();
578
- if (!sid) return [];
65
+ async function addToGuestCart(config, guestSessionId, item) {
66
+ if (!guestSessionId) return [];
579
67
  const payload = {
580
68
  product_id: item.product_id,
581
69
  product_slug: item.product_slug,
@@ -588,66 +76,132 @@ async function addToGuestCart(item) {
588
76
  custom_measurements: item.custom_measurements,
589
77
  is_bespoke: item.is_bespoke
590
78
  };
591
- const { data } = await storeManagementAxios.post("cart/", payload, {
592
- headers: { "X-Guest-Session": sid }
79
+ const response = await fetch(`${config.backendUrls.store}/cart/`, {
80
+ method: "POST",
81
+ headers: {
82
+ "Content-Type": "application/json",
83
+ "X-Storefront-Key": config.storefrontApiKey,
84
+ "X-Business-ID": config.businessId,
85
+ "X-Guest-Session": guestSessionId
86
+ },
87
+ body: JSON.stringify(payload)
593
88
  });
89
+ if (!response.ok) return [];
90
+ const data = await response.json();
594
91
  return parseItems(data.items || []);
595
92
  }
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
- );
93
+ async function updateGuestCartItemQuantity(config, guestSessionId, itemId, quantity) {
94
+ if (!guestSessionId) return [];
95
+ const response = await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
96
+ method: "PATCH",
97
+ headers: {
98
+ "Content-Type": "application/json",
99
+ "X-Storefront-Key": config.storefrontApiKey,
100
+ "X-Business-ID": config.businessId,
101
+ "X-Guest-Session": guestSessionId
102
+ },
103
+ body: JSON.stringify({ quantity })
104
+ });
105
+ if (!response.ok) return [];
106
+ const data = await response.json();
604
107
  return parseItems(data.items || []);
605
108
  }
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 }
109
+ async function removeFromGuestCart(config, guestSessionId, itemId) {
110
+ if (!guestSessionId) return [];
111
+ await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
112
+ method: "DELETE",
113
+ headers: {
114
+ "X-Storefront-Key": config.storefrontApiKey,
115
+ "X-Business-ID": config.businessId,
116
+ "X-Guest-Session": guestSessionId
117
+ }
611
118
  });
612
- return getGuestCart();
119
+ return getGuestCart(config, guestSessionId);
613
120
  }
614
- async function clearGuestCart() {
615
- const sid = getGuestSessionId();
616
- if (!sid) return;
617
- await storeManagementAxios.delete("cart/clear", {
618
- headers: { "X-Guest-Session": sid }
121
+ async function clearGuestCart(config, guestSessionId) {
122
+ if (!guestSessionId) return;
123
+ await fetch(`${config.backendUrls.store}/cart/clear`, {
124
+ method: "DELETE",
125
+ headers: {
126
+ "X-Storefront-Key": config.storefrontApiKey,
127
+ "X-Business-ID": config.businessId,
128
+ "X-Guest-Session": guestSessionId
129
+ }
619
130
  });
620
131
  }
621
- async function getCart() {
622
- const { data } = await storeManagementAxios.get("cart/");
132
+ async function getCart(config, accessToken) {
133
+ if (!accessToken) {
134
+ return { id: "", items: [], subtotal: 0, total: 0, product_type: "physical" };
135
+ }
136
+ const response = await fetch(`${config.backendUrls.store}/cart/`, {
137
+ headers: {
138
+ "Authorization": `Bearer ${accessToken}`,
139
+ "X-Storefront-Key": config.storefrontApiKey,
140
+ "X-Business-ID": config.businessId
141
+ }
142
+ });
143
+ if (!response.ok) throw new Error("Failed to fetch cart");
144
+ const data = await response.json();
623
145
  const parsedItems = parseItems(data.items || []);
624
146
  return { ...data, items: parsedItems };
625
147
  }
626
- async function addToCart(item) {
627
- const { data } = await storeManagementAxios.post("cart/", item);
148
+ async function addToCart(config, accessToken, item) {
149
+ const response = await fetch(`${config.backendUrls.store}/cart/`, {
150
+ method: "POST",
151
+ headers: {
152
+ "Content-Type": "application/json",
153
+ "Authorization": `Bearer ${accessToken}`,
154
+ "X-Storefront-Key": config.storefrontApiKey,
155
+ "X-Business-ID": config.businessId
156
+ },
157
+ body: JSON.stringify(item)
158
+ });
159
+ if (!response.ok) throw new Error("Failed to add to cart");
160
+ const data = await response.json();
628
161
  const parsedItems = parseItems(data.items || []);
629
162
  return { ...data, items: parsedItems };
630
163
  }
631
- async function updateCartItem(itemId, quantity) {
632
- const { data } = await storeManagementAxios.patch(
633
- `cart/${itemId}`,
634
- { quantity }
635
- );
164
+ async function updateCartItem(config, accessToken, itemId, quantity) {
165
+ const response = await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
166
+ method: "PATCH",
167
+ headers: {
168
+ "Content-Type": "application/json",
169
+ "Authorization": `Bearer ${accessToken}`,
170
+ "X-Storefront-Key": config.storefrontApiKey,
171
+ "X-Business-ID": config.businessId
172
+ },
173
+ body: JSON.stringify({ quantity })
174
+ });
175
+ if (!response.ok) throw new Error("Failed to update cart item");
176
+ const data = await response.json();
636
177
  const parsedItems = parseItems(data.items || []);
637
178
  return { ...data, items: parsedItems };
638
179
  }
639
- async function removeFromCart(itemId) {
640
- await storeManagementAxios.delete(`cart/${itemId}`);
641
- return getCart();
180
+ async function removeFromCart(config, accessToken, itemId) {
181
+ await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
182
+ method: "DELETE",
183
+ headers: {
184
+ "Authorization": `Bearer ${accessToken}`,
185
+ "X-Storefront-Key": config.storefrontApiKey,
186
+ "X-Business-ID": config.businessId
187
+ }
188
+ });
189
+ return getCart(config, accessToken);
642
190
  }
643
- async function clearCart() {
644
- await storeManagementAxios.delete("cart/clear");
191
+ async function clearCart(config, accessToken) {
192
+ await fetch(`${config.backendUrls.store}/cart/clear`, {
193
+ method: "DELETE",
194
+ headers: {
195
+ "Authorization": `Bearer ${accessToken}`,
196
+ "X-Storefront-Key": config.storefrontApiKey,
197
+ "X-Business-ID": config.businessId
198
+ }
199
+ });
645
200
  }
646
- async function mergeGuestCart() {
647
- const sid = getGuestSessionId();
648
- const guestItems = sid ? await getGuestCart() : [];
201
+ async function mergeGuestCart(config, accessToken, guestSessionId) {
202
+ const guestItems = guestSessionId ? await getGuestCart(config, guestSessionId) : [];
649
203
  if (guestItems.length === 0) {
650
- return getCart();
204
+ return getCart(config, accessToken);
651
205
  }
652
206
  const payloadItems = guestItems.map((item) => ({
653
207
  product_id: item.product_id,
@@ -661,19 +215,29 @@ async function mergeGuestCart() {
661
215
  custom_measurements: typeof item.custom_measurements === "string" ? item.custom_measurements : JSON.stringify(item.custom_measurements ?? {}),
662
216
  is_bespoke: item.is_bespoke
663
217
  }));
664
- const { data } = await storeManagementAxios.post(
665
- "cart/merge",
666
- { items: payloadItems },
667
- sid ? { headers: { "X-Guest-Session": sid } } : {}
668
- );
669
- clearGuestSessionId();
218
+ const headers = {
219
+ "Content-Type": "application/json",
220
+ "Authorization": `Bearer ${accessToken}`,
221
+ "X-Storefront-Key": config.storefrontApiKey,
222
+ "X-Business-ID": config.businessId
223
+ };
224
+ if (guestSessionId) {
225
+ headers["X-Guest-Session"] = guestSessionId;
226
+ }
227
+ const response = await fetch(`${config.backendUrls.store}/cart/merge`, {
228
+ method: "POST",
229
+ headers,
230
+ body: JSON.stringify({ items: payloadItems })
231
+ });
232
+ if (!response.ok) throw new Error("Failed to merge guest cart");
233
+ const data = await response.json();
670
234
  return { ...data, items: parseItems(data.items || []) };
671
235
  }
672
- async function mergeGuestCartIfPresent() {
236
+ async function mergeGuestCartIfPresent(config, accessToken, guestSessionId) {
673
237
  try {
674
- const guestItems = await getGuestCart();
238
+ const guestItems = await getGuestCart(config, guestSessionId);
675
239
  if (guestItems.length === 0) return;
676
- await mergeGuestCart();
240
+ await mergeGuestCart(config, accessToken, guestSessionId);
677
241
  } catch (error) {
678
242
  console.warn("[Cart] Failed to merge guest cart:", error);
679
243
  }
@@ -747,88 +311,173 @@ function normaliseStorefrontOrder(raw) {
747
311
  guestName: raw.guest_name
748
312
  };
749
313
  }
750
- async function createOrder(payload) {
751
- const { data } = await storeManagementAxios.post("orders/storefront", payload);
314
+ async function createOrder(config, accessToken, payload) {
315
+ const response = await fetch(`${config.backendUrls.store}/orders/storefront`, {
316
+ method: "POST",
317
+ headers: {
318
+ "Content-Type": "application/json",
319
+ "Authorization": `Bearer ${accessToken}`,
320
+ "X-Storefront-Key": config.storefrontApiKey,
321
+ "X-Business-ID": config.businessId
322
+ },
323
+ body: JSON.stringify(payload)
324
+ });
325
+ if (!response.ok) throw new Error("Failed to create order");
326
+ const data = await response.json();
752
327
  return normaliseStorefrontOrder(data);
753
328
  }
754
- async function findOrder(params) {
755
- const { data } = await publicStoreAxios.get("orders/find/", { params });
329
+ async function findOrder(config, params) {
330
+ const queryParams = new URLSearchParams();
331
+ if (params.email) queryParams.set("email", params.email);
332
+ if (params.order_id) queryParams.set("order_id", params.order_id);
333
+ if (params.guest_token) queryParams.set("guest_token", params.guest_token);
334
+ const response = await fetch(`${config.backendUrls.store}/orders/find/?${queryParams.toString()}`, {
335
+ headers: {
336
+ "X-Storefront-Key": config.storefrontApiKey,
337
+ "X-Business-ID": config.businessId
338
+ }
339
+ });
340
+ if (!response.ok) throw new Error("Failed to find order");
341
+ const data = await response.json();
756
342
  return normaliseStorefrontOrder(data);
757
343
  }
758
- async function findOrderByToken(token) {
759
- const { data } = await publicStoreAxios.get("orders/find/", {
760
- params: { guest_token: token }
344
+ async function findOrderByToken(config, token) {
345
+ const response = await fetch(`${config.backendUrls.store}/orders/find/?guest_token=${token}`, {
346
+ headers: {
347
+ "X-Storefront-Key": config.storefrontApiKey,
348
+ "X-Business-ID": config.businessId
349
+ }
761
350
  });
351
+ if (!response.ok) throw new Error("Failed to find order by token");
352
+ const data = await response.json();
762
353
  return normaliseStorefrontOrder(data);
763
354
  }
764
- async function getOrders(params) {
765
- const { data } = await storeManagementAxios.get("orders/", { params });
355
+ async function getOrders(config, accessToken, params) {
356
+ const queryParams = new URLSearchParams();
357
+ if (params?.email) queryParams.set("email", params.email);
358
+ if (params?.page) queryParams.set("page", params.page.toString());
359
+ if (params?.page_size) queryParams.set("page_size", params.page_size.toString());
360
+ const response = await fetch(`${config.backendUrls.store}/orders/?${queryParams.toString()}`, {
361
+ headers: {
362
+ "Authorization": `Bearer ${accessToken}`,
363
+ "X-Storefront-Key": config.storefrontApiKey,
364
+ "X-Business-ID": config.businessId
365
+ }
366
+ });
367
+ if (!response.ok) throw new Error("Failed to get orders");
368
+ const data = await response.json();
766
369
  const items = Array.isArray(data) ? data : data.items ?? [];
767
370
  return items.map(normaliseStorefrontOrder);
768
371
  }
769
- async function cancelOrder(orderId, reason) {
770
- const { data } = await storeManagementAxios.post(`orders/${orderId}/cancel/`, { reason });
372
+ async function cancelOrder(config, accessToken, orderId, reason) {
373
+ const response = await fetch(`${config.backendUrls.store}/orders/${orderId}/cancel/`, {
374
+ method: "POST",
375
+ headers: {
376
+ "Content-Type": "application/json",
377
+ "Authorization": `Bearer ${accessToken}`,
378
+ "X-Storefront-Key": config.storefrontApiKey,
379
+ "X-Business-ID": config.businessId
380
+ },
381
+ body: JSON.stringify({ reason })
382
+ });
383
+ if (!response.ok) throw new Error("Failed to cancel order");
384
+ const data = await response.json();
771
385
  return normaliseStorefrontOrder(data);
772
386
  }
773
- async function trackOrder(orderId, token) {
774
- const { data } = await publicStoreAxios.get(`orders/track/${orderId}`, {
775
- params: token ? { token } : void 0
387
+ async function trackOrder(config, orderId, token) {
388
+ const queryParams = token ? `?token=${token}` : "";
389
+ const response = await fetch(`${config.backendUrls.store}/orders/track/${orderId}${queryParams}`, {
390
+ headers: {
391
+ "X-Storefront-Key": config.storefrontApiKey,
392
+ "X-Business-ID": config.businessId
393
+ }
776
394
  });
395
+ if (!response.ok) throw new Error("Failed to track order");
396
+ const data = await response.json();
777
397
  return normaliseStorefrontOrder(data);
778
398
  }
779
399
 
780
400
  // 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
401
+ async function loginCustomer(config, payload) {
402
+ const response = await fetch(`${config.backendUrls.auth}/auth/login/customer/`, {
403
+ method: "POST",
404
+ headers: {
405
+ "Content-Type": "application/json",
406
+ "X-Storefront-Key": config.storefrontApiKey,
407
+ "X-Business-ID": config.businessId
408
+ },
409
+ body: JSON.stringify({
410
+ ...payload,
411
+ tenant_id: config.businessId
412
+ })
786
413
  });
787
- tokenStore.setAccessToken(data.access);
788
- tokenStore.setRefreshToken(data.refresh);
789
- resetGraphQLClient();
790
- await mergeGuestCartIfPresent();
414
+ if (!response.ok) {
415
+ throw new Error("Login failed");
416
+ }
417
+ const data = await response.json();
791
418
  return data;
792
419
  }
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
420
+ async function registerCustomer(config, payload) {
421
+ const response = await fetch(`${config.backendUrls.auth}/auth/register/customer/`, {
422
+ method: "POST",
423
+ headers: {
424
+ "Content-Type": "application/json",
425
+ "X-Storefront-Key": config.storefrontApiKey,
426
+ "X-Business-ID": config.businessId
427
+ },
428
+ body: JSON.stringify({
429
+ ...payload,
430
+ tenant_id: config.businessId
431
+ })
798
432
  });
799
- tokenStore.setAccessToken(data.access);
800
- tokenStore.setRefreshToken(data.refresh);
801
- resetGraphQLClient();
802
- await mergeGuestCartIfPresent();
433
+ if (!response.ok) {
434
+ throw new Error("Registration failed");
435
+ }
436
+ const data = await response.json();
803
437
  return data;
804
438
  }
805
- async function refreshToken2(refresh) {
806
- const { data } = await refreshAxios2.post("/auth/token/refresh/", { refresh });
439
+ async function refreshToken(config, refresh) {
440
+ const response = await fetch(`${config.backendUrls.auth}/auth/token/refresh/`, {
441
+ method: "POST",
442
+ headers: {
443
+ "Content-Type": "application/json"
444
+ },
445
+ body: JSON.stringify({ refresh })
446
+ });
447
+ if (!response.ok) {
448
+ throw new Error("Token refresh failed");
449
+ }
450
+ const data = await response.json();
807
451
  return data;
808
452
  }
809
- async function logout() {
810
- const refresh = tokenStore.getRefreshToken();
453
+ async function logout(config, refresh) {
811
454
  const payload = refresh ? { refresh } : {};
812
455
  try {
813
- await authAxios.post("/auth/logout/", payload);
456
+ await fetch(`${config.backendUrls.auth}/auth/logout/`, {
457
+ method: "POST",
458
+ headers: {
459
+ "Content-Type": "application/json"
460
+ },
461
+ body: JSON.stringify(payload)
462
+ });
814
463
  } catch {
815
- } finally {
816
- tokenStore.clearAll();
817
- resetGraphQLClient();
818
464
  }
819
465
  }
820
- async function verifySocialToken(provider, token) {
821
- const config = getRuntimeConfig();
822
- const { data } = await authAxios.post(
823
- `/auth/social/verify/${provider}/`,
824
- {
466
+ async function verifySocialToken(config, provider, token) {
467
+ const response = await fetch(`${config.backendUrls.auth}/auth/social/verify/${provider}/`, {
468
+ method: "POST",
469
+ headers: {
470
+ "Content-Type": "application/json"
471
+ },
472
+ body: JSON.stringify({
825
473
  id_token: token,
826
474
  storefront_key: config.storefrontApiKey
827
- }
828
- );
829
- tokenStore.setAccessToken(data.access);
830
- tokenStore.setRefreshToken(data.refresh);
831
- resetGraphQLClient();
475
+ })
476
+ });
477
+ if (!response.ok) {
478
+ throw new Error("Social token verification failed");
479
+ }
480
+ const data = await response.json();
832
481
  return data;
833
482
  }
834
483
  function parseJwtPayload(token) {
@@ -862,7 +511,7 @@ function mapAuthUserToCustomer(data, provider) {
862
511
  firstname,
863
512
  lastname,
864
513
  phone,
865
- full_name: buildFullName2(firstname, lastname),
514
+ full_name: buildFullName(firstname, lastname),
866
515
  avatar: resolveAvatar(data.profile?.profile_picture),
867
516
  provider: provider ?? resolveProvider(data)
868
517
  };
@@ -870,7 +519,7 @@ function mapAuthUserToCustomer(data, provider) {
870
519
  function buildCustomerFromClaims(claims) {
871
520
  const provider = claims.is_google_auth_enabled ? "google" : claims.is_facebook_auth_enabled ? "facebook" : "email";
872
521
  const jwtFullName = String(claims.full_name ?? claims.name ?? "").trim() || void 0;
873
- const { firstname: splitFirst, lastname: splitLast } = splitFullName2(jwtFullName);
522
+ const { firstname: splitFirst, lastname: splitLast } = splitFullName(jwtFullName);
874
523
  return {
875
524
  id: String(claims.user_id ?? claims.sub ?? ""),
876
525
  email: String(claims.email ?? ""),
@@ -882,86 +531,91 @@ function buildCustomerFromClaims(claims) {
882
531
  provider
883
532
  };
884
533
  }
885
- async function getMe() {
886
- const { data } = await authAxios.get("/auth/profile/");
534
+ async function getMe(config, accessToken) {
535
+ if (!config || !accessToken) {
536
+ const response2 = await fetch("/api/auth/me", { credentials: "include" });
537
+ if (!response2.ok) throw new Error("Failed to fetch profile");
538
+ const data2 = await response2.json();
539
+ return data2.user;
540
+ }
541
+ const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
542
+ headers: {
543
+ "Authorization": `Bearer ${accessToken}`
544
+ }
545
+ });
546
+ if (!response.ok) {
547
+ throw new Error("Failed to fetch profile");
548
+ }
549
+ const data = await response.json();
887
550
  return mapAuthUserToCustomer(data);
888
551
  }
889
- async function getAuthUser() {
890
- const { data } = await authAxios.get("/auth/profile/");
552
+ async function getAuthUser(config, accessToken) {
553
+ if (!config || !accessToken) {
554
+ const response2 = await fetch("/api/auth/me", { credentials: "include" });
555
+ if (!response2.ok) throw new Error("Failed to fetch auth user");
556
+ const data2 = await response2.json();
557
+ return data2.user;
558
+ }
559
+ const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
560
+ headers: {
561
+ "Authorization": `Bearer ${accessToken}`
562
+ }
563
+ });
564
+ if (!response.ok) {
565
+ throw new Error("Failed to fetch auth user");
566
+ }
567
+ const data = await response.json();
891
568
  return data;
892
569
  }
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
- }
570
+ async function updateProfile(configOrPayload, accessTokenOrPayload, payloadParam) {
571
+ const isArg1Config = typeof configOrPayload === "object" && configOrPayload !== null && "businessId" in configOrPayload;
572
+ if (!isArg1Config) {
573
+ const payload2 = configOrPayload;
574
+ const response2 = await fetch("/api/auth/profile", {
575
+ method: "PUT",
576
+ headers: { "Content-Type": "application/json" },
577
+ credentials: "include",
578
+ body: JSON.stringify(payload2)
579
+ });
580
+ if (!response2.ok) throw new Error("Failed to update profile");
581
+ return response2.json();
922
582
  }
923
- throw lastError;
583
+ const config = configOrPayload;
584
+ const accessToken = accessTokenOrPayload;
585
+ const payload = payloadParam;
586
+ const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
587
+ method: "PUT",
588
+ headers: {
589
+ "Content-Type": "application/json",
590
+ "Authorization": `Bearer ${accessToken}`
591
+ },
592
+ body: JSON.stringify(payload)
593
+ });
594
+ if (!response.ok) {
595
+ throw new Error("Failed to update profile");
596
+ }
597
+ const data = await response.json();
598
+ return mapAuthUserToCustomer(data);
924
599
  }
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();
600
+ async function silentRefresh(config, refresh) {
601
+ try {
602
+ const data = await refreshToken(config, refresh);
603
+ if (!data.access || !data.refresh) {
949
604
  return null;
950
- } finally {
951
- refreshPromise = null;
952
605
  }
953
- })();
954
- return refreshPromise;
955
- }
956
- function storeTokens(access, refresh, remember = true) {
957
- tokenStore.setAccessToken(access);
958
- tokenStore.setRefreshToken(refresh, remember);
606
+ const claims = parseJwtPayload(data.access);
607
+ const user = buildCustomerFromClaims(claims);
608
+ const provider = user.provider;
609
+ return { user, provider, newAccessToken: data.access, newRefreshToken: data.refresh };
610
+ } catch {
611
+ return null;
612
+ }
959
613
  }
960
- function buildFullName2(firstname, lastname) {
614
+ function buildFullName(firstname, lastname) {
961
615
  if (firstname && lastname) return `${firstname} ${lastname}`;
962
616
  return firstname || lastname || "";
963
617
  }
964
- function splitFullName2(fullName) {
618
+ function splitFullName(fullName) {
965
619
  if (!fullName) return { firstname: "", lastname: "" };
966
620
  const parts = fullName.trim().split(/\s+/);
967
621
  if (parts.length === 1) {
@@ -972,8 +626,39 @@ function splitFullName2(fullName) {
972
626
  lastname: parts.slice(1).join(" ")
973
627
  };
974
628
  }
629
+ function storeTokens(accessToken, refreshToken2) {
630
+ if (typeof window !== "undefined") {
631
+ localStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, accessToken);
632
+ localStorage.setItem(STORAGE_KEYS.REFRESH_TOKEN, refreshToken2);
633
+ }
634
+ }
635
+ function clearTokens() {
636
+ if (typeof window !== "undefined") {
637
+ localStorage.removeItem(STORAGE_KEYS.ACCESS_TOKEN);
638
+ localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
639
+ }
640
+ }
641
+ function getStoredTokens() {
642
+ if (typeof window === "undefined") {
643
+ return { accessToken: null, refreshToken: null };
644
+ }
645
+ return {
646
+ accessToken: localStorage.getItem(STORAGE_KEYS.ACCESS_TOKEN),
647
+ refreshToken: localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN)
648
+ };
649
+ }
975
650
 
976
651
  // src/services/product.service.ts
652
+ import { GraphQLClient } from "graphql-request";
653
+ function createGraphQLClient(config) {
654
+ const headers = {
655
+ "Content-Type": "application/json",
656
+ "Accept": "application/json",
657
+ "X-Storefront-Key": config.storefrontApiKey,
658
+ "X-Business-ID": config.businessId
659
+ };
660
+ return new GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
661
+ }
977
662
  var GET_STOREFRONT_PRODUCTS = `
978
663
  query GetStorefrontProducts($page: Int!, $pageSize: Int!, $collectionSlug: String, $search: String) {
979
664
  storefront_products(page: $page, pageSize: $pageSize, collectionSlug: $collectionSlug, search: $search) {
@@ -990,7 +675,7 @@ var GET_STOREFRONT_PRODUCTS = `
990
675
  is_bespoke
991
676
  base_price
992
677
  currency
993
- images { url alt id }
678
+ images
994
679
  tags
995
680
  custom_fields { label unit required }
996
681
  is_published
@@ -1013,7 +698,7 @@ var GET_STOREFRONT_PRODUCTS = `
1013
698
  sku
1014
699
  attributes
1015
700
  price
1016
- images { url alt id }
701
+ images
1017
702
  weight_kg
1018
703
  is_active
1019
704
  inventory {
@@ -1040,7 +725,7 @@ var GET_STOREFRONT_PRODUCTS = `
1040
725
  name
1041
726
  slug
1042
727
  description
1043
- image { url alt id }
728
+ image
1044
729
  collection_type
1045
730
  rules
1046
731
  status
@@ -1071,7 +756,7 @@ var GET_STOREFRONT_PRODUCT_BY_SLUG = `
1071
756
  is_bespoke
1072
757
  base_price
1073
758
  currency
1074
- images { url alt id }
759
+ images
1075
760
  tags
1076
761
  custom_fields { label unit required }
1077
762
  is_published
@@ -1094,7 +779,7 @@ var GET_STOREFRONT_PRODUCT_BY_SLUG = `
1094
779
  sku
1095
780
  attributes
1096
781
  price
1097
- images { url alt id }
782
+ images
1098
783
  weight_kg
1099
784
  is_active
1100
785
  inventory {
@@ -1121,7 +806,7 @@ var GET_STOREFRONT_PRODUCT_BY_SLUG = `
1121
806
  name
1122
807
  slug
1123
808
  description
1124
- image { url alt id }
809
+ image
1125
810
  collection_type
1126
811
  rules
1127
812
  status
@@ -1148,7 +833,7 @@ var GET_STOREFRONT_LATEST = `
1148
833
  is_bespoke
1149
834
  base_price
1150
835
  currency
1151
- images { url alt id }
836
+ images
1152
837
  tags
1153
838
  custom_fields { label unit required }
1154
839
  is_published
@@ -1171,7 +856,7 @@ var GET_STOREFRONT_LATEST = `
1171
856
  sku
1172
857
  attributes
1173
858
  price
1174
- images { url alt id }
859
+ images
1175
860
  weight_kg
1176
861
  is_active
1177
862
  inventory {
@@ -1198,7 +883,7 @@ var GET_STOREFRONT_LATEST = `
1198
883
  name
1199
884
  slug
1200
885
  description
1201
- image { url alt id }
886
+ image
1202
887
  collection_type
1203
888
  rules
1204
889
  status
@@ -1230,7 +915,7 @@ var GET_STOREFRONT_POPULAR = `
1230
915
  is_bespoke
1231
916
  base_price
1232
917
  currency
1233
- images { url alt id }
918
+ images
1234
919
  tags
1235
920
  custom_fields { label unit required }
1236
921
  is_published
@@ -1253,7 +938,7 @@ var GET_STOREFRONT_POPULAR = `
1253
938
  sku
1254
939
  attributes
1255
940
  price
1256
- images { url alt id }
941
+ images
1257
942
  weight_kg
1258
943
  is_active
1259
944
  inventory {
@@ -1280,7 +965,7 @@ var GET_STOREFRONT_POPULAR = `
1280
965
  name
1281
966
  slug
1282
967
  description
1283
- image { url alt id }
968
+ image
1284
969
  collection_type
1285
970
  rules
1286
971
  status
@@ -1312,7 +997,7 @@ var GET_STOREFRONT_FEATURED = `
1312
997
  is_bespoke
1313
998
  base_price
1314
999
  currency
1315
- images { url alt id }
1000
+ images
1316
1001
  tags
1317
1002
  custom_fields { label unit required }
1318
1003
  is_published
@@ -1335,7 +1020,7 @@ var GET_STOREFRONT_FEATURED = `
1335
1020
  sku
1336
1021
  attributes
1337
1022
  price
1338
- images { url alt id }
1023
+ images
1339
1024
  weight_kg
1340
1025
  is_active
1341
1026
  inventory {
@@ -1362,7 +1047,7 @@ var GET_STOREFRONT_FEATURED = `
1362
1047
  name
1363
1048
  slug
1364
1049
  description
1365
- image { url alt id }
1050
+ image
1366
1051
  collection_type
1367
1052
  rules
1368
1053
  status
@@ -1394,7 +1079,180 @@ var GET_STOREFRONT_NEW = `
1394
1079
  is_bespoke
1395
1080
  base_price
1396
1081
  currency
1397
- images { url alt id }
1082
+ sale_price
1083
+ sale_start
1084
+ sale_end
1085
+ images
1086
+ tags
1087
+ custom_fields { label unit required }
1088
+ is_published
1089
+ is_featured
1090
+ is_popular
1091
+ is_new
1092
+ is_temporary
1093
+ digital_file_key
1094
+ download_limit
1095
+ download_expires_at
1096
+ weight_kg
1097
+ length_cm
1098
+ width_cm
1099
+ height_cm
1100
+ created_at
1101
+ updated_at
1102
+ variants {
1103
+ id
1104
+ product_id
1105
+ sku
1106
+ attributes
1107
+ price
1108
+ images
1109
+ weight_kg
1110
+ is_active
1111
+ inventory {
1112
+ id
1113
+ product_id
1114
+ variant_id
1115
+ quantity
1116
+ reserved
1117
+ reorder_point
1118
+ reorder_quantity
1119
+ track_quantity
1120
+ allow_backorder
1121
+ available
1122
+ is_in_stock
1123
+ is_low_stock
1124
+ updated_at
1125
+ }
1126
+ created_at
1127
+ updated_at
1128
+ }
1129
+ collections {
1130
+ id
1131
+ business_id
1132
+ name
1133
+ slug
1134
+ description
1135
+ image
1136
+ collection_type
1137
+ rules
1138
+ status
1139
+ sort_order
1140
+ created_at
1141
+ updated_at
1142
+ }
1143
+ }
1144
+ total
1145
+ page
1146
+ page_size
1147
+ total_pages
1148
+ }
1149
+ }
1150
+ `;
1151
+ var GET_STOREFRONT_ON_SALE = `
1152
+ query GetStorefrontOnSale($page: Int!, $pageSize: Int!) {
1153
+ storefront_on_sale(page: $page, pageSize: $pageSize) {
1154
+ items {
1155
+ id
1156
+ business_id
1157
+ name
1158
+ slug
1159
+ description
1160
+ brand
1161
+ product_type
1162
+ requires_shipping
1163
+ is_consumable
1164
+ is_bespoke
1165
+ base_price
1166
+ currency
1167
+ sale_price
1168
+ sale_start
1169
+ sale_end
1170
+ images
1171
+ tags
1172
+ custom_fields { label unit required }
1173
+ is_published
1174
+ is_featured
1175
+ is_popular
1176
+ is_new
1177
+ is_temporary
1178
+ digital_file_key
1179
+ download_limit
1180
+ download_expires_at
1181
+ weight_kg
1182
+ length_cm
1183
+ width_cm
1184
+ height_cm
1185
+ created_at
1186
+ updated_at
1187
+ variants {
1188
+ id
1189
+ product_id
1190
+ sku
1191
+ attributes
1192
+ price
1193
+ images
1194
+ weight_kg
1195
+ is_active
1196
+ inventory {
1197
+ id
1198
+ product_id
1199
+ variant_id
1200
+ quantity
1201
+ reserved
1202
+ reorder_point
1203
+ reorder_quantity
1204
+ track_quantity
1205
+ allow_backorder
1206
+ available
1207
+ is_in_stock
1208
+ is_low_stock
1209
+ updated_at
1210
+ }
1211
+ created_at
1212
+ updated_at
1213
+ }
1214
+ collections {
1215
+ id
1216
+ business_id
1217
+ name
1218
+ slug
1219
+ description
1220
+ image
1221
+ collection_type
1222
+ rules
1223
+ status
1224
+ sort_order
1225
+ created_at
1226
+ updated_at
1227
+ }
1228
+ }
1229
+ total
1230
+ page
1231
+ page_size
1232
+ total_pages
1233
+ }
1234
+ }
1235
+ `;
1236
+ var GET_STOREFRONT_LOW_STOCK = `
1237
+ query GetStorefrontLowStock($page: Int!, $pageSize: Int!) {
1238
+ storefront_low_stock(page: $page, pageSize: $pageSize) {
1239
+ items {
1240
+ id
1241
+ business_id
1242
+ name
1243
+ slug
1244
+ description
1245
+ brand
1246
+ product_type
1247
+ requires_shipping
1248
+ is_consumable
1249
+ is_bespoke
1250
+ base_price
1251
+ currency
1252
+ sale_price
1253
+ sale_start
1254
+ sale_end
1255
+ images
1398
1256
  tags
1399
1257
  custom_fields { label unit required }
1400
1258
  is_published
@@ -1417,7 +1275,7 @@ var GET_STOREFRONT_NEW = `
1417
1275
  sku
1418
1276
  attributes
1419
1277
  price
1420
- images { url alt id }
1278
+ images
1421
1279
  weight_kg
1422
1280
  is_active
1423
1281
  inventory {
@@ -1444,7 +1302,7 @@ var GET_STOREFRONT_NEW = `
1444
1302
  name
1445
1303
  slug
1446
1304
  description
1447
- image { url alt id }
1305
+ image
1448
1306
  collection_type
1449
1307
  rules
1450
1308
  status
@@ -1476,7 +1334,7 @@ var GET_STOREFRONT_RECOMMENDED = `
1476
1334
  is_bespoke
1477
1335
  base_price
1478
1336
  currency
1479
- images { url alt id }
1337
+ images
1480
1338
  tags
1481
1339
  custom_fields { label unit required }
1482
1340
  is_published
@@ -1499,7 +1357,7 @@ var GET_STOREFRONT_RECOMMENDED = `
1499
1357
  sku
1500
1358
  attributes
1501
1359
  price
1502
- images { url alt id }
1360
+ images
1503
1361
  weight_kg
1504
1362
  is_active
1505
1363
  inventory {
@@ -1526,7 +1384,7 @@ var GET_STOREFRONT_RECOMMENDED = `
1526
1384
  name
1527
1385
  slug
1528
1386
  description
1529
- image { url alt id }
1387
+ image
1530
1388
  collection_type
1531
1389
  rules
1532
1390
  status
@@ -1542,8 +1400,8 @@ var GET_STOREFRONT_RECOMMENDED = `
1542
1400
  }
1543
1401
  }
1544
1402
  `;
1545
- async function getStorefrontProducts(params) {
1546
- const client = getGraphQLClient();
1403
+ async function getStorefrontProducts(config, params) {
1404
+ const client = createGraphQLClient(config);
1547
1405
  const variables = {
1548
1406
  page: params?.page || 1,
1549
1407
  pageSize: params?.pageSize || 20,
@@ -1553,13 +1411,13 @@ async function getStorefrontProducts(params) {
1553
1411
  const data = await client.request(GET_STOREFRONT_PRODUCTS, variables);
1554
1412
  return data.storefront_products;
1555
1413
  }
1556
- async function getStorefrontProductBySlug(slug) {
1557
- const client = getGraphQLClient();
1414
+ async function getStorefrontProductBySlug(config, slug) {
1415
+ const client = createGraphQLClient(config);
1558
1416
  const data = await client.request(GET_STOREFRONT_PRODUCT_BY_SLUG, { slug });
1559
1417
  return data.storefront_product_by_slug;
1560
1418
  }
1561
- async function getLatestProducts(params) {
1562
- const client = getGraphQLClient();
1419
+ async function getLatestProducts(config, params) {
1420
+ const client = createGraphQLClient(config);
1563
1421
  const variables = {
1564
1422
  page: params?.page || 1,
1565
1423
  pageSize: params?.pageSize || 4
@@ -1567,8 +1425,8 @@ async function getLatestProducts(params) {
1567
1425
  const data = await client.request(GET_STOREFRONT_LATEST, variables);
1568
1426
  return data.storefront_latest;
1569
1427
  }
1570
- async function getPopularProducts(params) {
1571
- const client = getGraphQLClient();
1428
+ async function getPopularProducts(config, params) {
1429
+ const client = createGraphQLClient(config);
1572
1430
  const variables = {
1573
1431
  page: params?.page || 1,
1574
1432
  pageSize: params?.pageSize || 4
@@ -1576,8 +1434,8 @@ async function getPopularProducts(params) {
1576
1434
  const data = await client.request(GET_STOREFRONT_POPULAR, variables);
1577
1435
  return data.storefront_popular;
1578
1436
  }
1579
- async function getFeaturedProducts(params) {
1580
- const client = getGraphQLClient();
1437
+ async function getFeaturedProducts(config, params) {
1438
+ const client = createGraphQLClient(config);
1581
1439
  const variables = {
1582
1440
  page: params?.page || 1,
1583
1441
  pageSize: params?.pageSize || 4
@@ -1585,8 +1443,8 @@ async function getFeaturedProducts(params) {
1585
1443
  const data = await client.request(GET_STOREFRONT_FEATURED, variables);
1586
1444
  return data.storefront_featured;
1587
1445
  }
1588
- async function getNewProducts(params) {
1589
- const client = getGraphQLClient();
1446
+ async function getNewProducts(config, params) {
1447
+ const client = createGraphQLClient(config);
1590
1448
  const variables = {
1591
1449
  page: params?.page || 1,
1592
1450
  pageSize: params?.pageSize || 4
@@ -1594,8 +1452,26 @@ async function getNewProducts(params) {
1594
1452
  const data = await client.request(GET_STOREFRONT_NEW, variables);
1595
1453
  return data.storefront_new;
1596
1454
  }
1597
- async function getRecommendedProducts(params) {
1598
- const client = getGraphQLClient();
1455
+ async function getOnSaleProducts(config, params) {
1456
+ const client = createGraphQLClient(config);
1457
+ const variables = {
1458
+ page: params?.page || 1,
1459
+ pageSize: params?.pageSize || 4
1460
+ };
1461
+ const data = await client.request(GET_STOREFRONT_ON_SALE, variables);
1462
+ return data.storefront_on_sale;
1463
+ }
1464
+ async function getLowStockProducts(config, params) {
1465
+ const client = createGraphQLClient(config);
1466
+ const variables = {
1467
+ page: params?.page || 1,
1468
+ pageSize: params?.pageSize || 4
1469
+ };
1470
+ const data = await client.request(GET_STOREFRONT_LOW_STOCK, variables);
1471
+ return data.storefront_low_stock;
1472
+ }
1473
+ async function getRecommendedProducts(config, params) {
1474
+ const client = createGraphQLClient(config);
1599
1475
  const variables = {
1600
1476
  page: params?.page || 1,
1601
1477
  pageSize: params?.pageSize || 4,
@@ -1606,6 +1482,7 @@ async function getRecommendedProducts(params) {
1606
1482
  }
1607
1483
 
1608
1484
  // src/services/collection.service.ts
1485
+ import { GraphQLClient as GraphQLClient2 } from "graphql-request";
1609
1486
  var GET_STOREFRONT_COLLECTIONS = `
1610
1487
  query GetStorefrontCollections($page: Int!, $pageSize: Int!) {
1611
1488
  storefront_collections(page: $page, pageSize: $pageSize) {
@@ -1615,7 +1492,7 @@ var GET_STOREFRONT_COLLECTIONS = `
1615
1492
  name
1616
1493
  slug
1617
1494
  description
1618
- image { url alt id }
1495
+ image
1619
1496
  collection_type
1620
1497
  rules
1621
1498
  status
@@ -1638,7 +1515,7 @@ var GET_STOREFRONT_COLLECTION_BY_SLUG = `
1638
1515
  name
1639
1516
  slug
1640
1517
  description
1641
- image { url alt id }
1518
+ image
1642
1519
  collection_type
1643
1520
  rules
1644
1521
  status
@@ -1648,8 +1525,17 @@ var GET_STOREFRONT_COLLECTION_BY_SLUG = `
1648
1525
  }
1649
1526
  }
1650
1527
  `;
1651
- async function getStorefrontCollections(params) {
1652
- const client = getGraphQLClient();
1528
+ function createGraphQLClient2(config) {
1529
+ const headers = {
1530
+ "Content-Type": "application/json",
1531
+ "Accept": "application/json",
1532
+ "X-Storefront-Key": config.storefrontApiKey,
1533
+ "X-Business-ID": config.businessId
1534
+ };
1535
+ return new GraphQLClient2(`${config.backendUrls.store}/graphql`, { headers });
1536
+ }
1537
+ async function getStorefrontCollections(config, params) {
1538
+ const client = createGraphQLClient2(config);
1653
1539
  const variables = {
1654
1540
  page: params?.page || 1,
1655
1541
  pageSize: params?.pageSize || 20
@@ -1657,16 +1543,17 @@ async function getStorefrontCollections(params) {
1657
1543
  const data = await client.request(GET_STOREFRONT_COLLECTIONS, variables);
1658
1544
  return data.storefront_collections;
1659
1545
  }
1660
- async function getStorefrontCollectionBySlug(slug) {
1661
- const client = getGraphQLClient();
1546
+ async function getStorefrontCollectionBySlug(config, slug) {
1547
+ const client = createGraphQLClient2(config);
1662
1548
  const data = await client.request(GET_STOREFRONT_COLLECTION_BY_SLUG, { slug });
1663
1549
  return data.storefront_collection_by_slug;
1664
1550
  }
1665
1551
 
1666
1552
  // src/services/wishlist.service.ts
1667
- var GET_WISHLIST = `
1668
- query GetWishlist($page: Int!, $pageSize: Int!) {
1669
- wishlist(page: $page, pageSize: $pageSize) {
1553
+ import { GraphQLClient as GraphQLClient3 } from "graphql-request";
1554
+ var GET_STOREFRONT_WISHLIST = `
1555
+ query GetStorefrontWishlist($page: Int!, $pageSize: Int!) {
1556
+ storefront_wishlist(page: $page, pageSize: $pageSize) {
1670
1557
  items {
1671
1558
  id
1672
1559
  product_id
@@ -1675,6 +1562,7 @@ var GET_WISHLIST = `
1675
1562
  product_name
1676
1563
  product_slug
1677
1564
  product_price
1565
+ currency
1678
1566
  product_image
1679
1567
  }
1680
1568
  total
@@ -1684,79 +1572,136 @@ var GET_WISHLIST = `
1684
1572
  }
1685
1573
  }
1686
1574
  `;
1687
- var CHECK_IN_WISHLIST = `
1688
- query CheckInWishlist($productId: String!) {
1689
- check_in_wishlist(productId: $productId) {
1575
+ var CHECK_IN_STOREFRONT_WISHLIST = `
1576
+ query CheckInStorefrontWishlist($productId: String!) {
1577
+ check_in_storefront_wishlist(productId: $productId) {
1690
1578
  in_wishlist
1691
1579
  }
1692
1580
  }
1693
1581
  `;
1694
- async function getWishlist(params) {
1695
- const client = getGraphQLClient();
1582
+ function createGraphQLClient3(config, accessToken) {
1583
+ const headers = {
1584
+ "Content-Type": "application/json",
1585
+ "Accept": "application/json",
1586
+ "X-Storefront-Key": config.storefrontApiKey,
1587
+ "X-Business-ID": config.businessId
1588
+ };
1589
+ if (accessToken) {
1590
+ headers["Authorization"] = `Bearer ${accessToken}`;
1591
+ }
1592
+ return new GraphQLClient3(`${config.backendUrls.store}/graphql`, { headers });
1593
+ }
1594
+ async function getWishlist(config, accessToken, params) {
1595
+ const client = createGraphQLClient3(config, accessToken);
1696
1596
  const variables = {
1697
1597
  page: params?.page || 1,
1698
1598
  pageSize: params?.pageSize || 20
1699
1599
  };
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
1600
+ const data = await client.request(GET_STOREFRONT_WISHLIST, variables);
1601
+ return data.storefront_wishlist;
1602
+ }
1603
+ async function checkInWishlist(config, accessToken, productId) {
1604
+ const client = createGraphQLClient3(config, accessToken);
1605
+ const data = await client.request(CHECK_IN_STOREFRONT_WISHLIST, { productId });
1606
+ return data.check_in_storefront_wishlist;
1607
+ }
1608
+ async function addToWishlist(config, accessToken, productId, notes) {
1609
+ const response = await fetch(`${config.backendUrls.store}/wishlist/`, {
1610
+ method: "POST",
1611
+ headers: {
1612
+ "Content-Type": "application/json",
1613
+ "Authorization": `Bearer ${accessToken}`,
1614
+ "X-Storefront-Key": config.storefrontApiKey,
1615
+ "X-Business-ID": config.businessId
1616
+ },
1617
+ body: JSON.stringify({
1618
+ product_id: productId,
1619
+ notes: notes || void 0
1620
+ })
1712
1621
  });
1713
- return data;
1622
+ if (!response.ok) throw new Error("Failed to add to wishlist");
1623
+ return response.json();
1714
1624
  }
1715
- async function removeFromWishlist(itemId) {
1716
- await storeManagementAxios.delete(`wishlist/${itemId}`);
1625
+ async function removeFromWishlist(config, accessToken, itemId) {
1626
+ const response = await fetch(`${config.backendUrls.store}/wishlist/${itemId}`, {
1627
+ method: "DELETE",
1628
+ headers: {
1629
+ "Authorization": `Bearer ${accessToken}`,
1630
+ "X-Storefront-Key": config.storefrontApiKey,
1631
+ "X-Business-ID": config.businessId
1632
+ }
1633
+ });
1634
+ if (!response.ok) throw new Error("Failed to remove from wishlist");
1717
1635
  }
1718
- async function removeProductFromWishlist(productId) {
1719
- await storeManagementAxios.delete(`wishlist/product/${productId}`);
1636
+ async function removeProductFromWishlist(config, accessToken, productId) {
1637
+ const response = await fetch(`${config.backendUrls.store}/wishlist/product/${productId}`, {
1638
+ method: "DELETE",
1639
+ headers: {
1640
+ "Authorization": `Bearer ${accessToken}`,
1641
+ "X-Storefront-Key": config.storefrontApiKey,
1642
+ "X-Business-ID": config.businessId
1643
+ }
1644
+ });
1645
+ if (!response.ok) throw new Error("Failed to remove product from wishlist");
1720
1646
  }
1721
1647
 
1722
1648
  // src/services/payment.service.ts
1723
- async function createDedicatedAccount(request) {
1649
+ async function createDedicatedAccount(config, accessToken, request) {
1724
1650
  const isValidUUID = (str) => {
1725
1651
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1726
1652
  return uuidRegex.test(str);
1727
1653
  };
1728
- const { data } = await paymentAxios.post(
1729
- "payments/dedicated-account",
1730
- {
1654
+ const response = await fetch(`${config.backendUrls.payment}/payments/dedicated-account`, {
1655
+ method: "POST",
1656
+ headers: {
1657
+ "Content-Type": "application/json",
1658
+ "Authorization": `Bearer ${accessToken}`,
1659
+ "X-Storefront-Key": config.storefrontApiKey,
1660
+ "X-Business-ID": config.businessId
1661
+ },
1662
+ body: JSON.stringify({
1731
1663
  order_id: request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0,
1732
1664
  amount: request.amount,
1733
1665
  customer_email: request.customer_email,
1734
1666
  customer_name: request.customer_name,
1735
1667
  currency: request.currency,
1736
1668
  idempotency_key: request.idempotency_key
1737
- }
1738
- );
1669
+ })
1670
+ });
1671
+ if (!response.ok) throw new Error("Failed to create dedicated account");
1672
+ const data = await response.json();
1739
1673
  return data;
1740
1674
  }
1741
- async function initiatePayment(request) {
1675
+ async function initiatePayment(config, accessToken, request) {
1742
1676
  const isValidUUID = (str) => {
1743
1677
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1744
1678
  return uuidRegex.test(str);
1745
1679
  };
1746
1680
  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 ?? "",
1681
+ const response = await fetch(`${config.backendUrls.payment}/payments/storefront/initiate`, {
1682
+ method: "POST",
1683
+ headers: {
1684
+ "Content-Type": "application/json",
1685
+ "Authorization": `Bearer ${accessToken}`,
1686
+ "X-Storefront-Key": config.storefrontApiKey,
1687
+ "X-Business-ID": config.businessId
1688
+ },
1689
+ body: JSON.stringify({
1690
+ amount: request.amount,
1691
+ currency: request.currency,
1755
1692
  order_id: validOrderId,
1756
- ...request.metadata ?? {}
1757
- },
1758
- idempotency_key: request.idempotency_key
1693
+ quote_id: request.quote_id,
1694
+ metadata_json: {
1695
+ customer_email: request.customer_email,
1696
+ customer_name: request.customer_name ?? "",
1697
+ order_id: validOrderId,
1698
+ ...request.metadata ?? {}
1699
+ },
1700
+ idempotency_key: request.idempotency_key
1701
+ })
1759
1702
  });
1703
+ if (!response.ok) throw new Error("Failed to initiate payment");
1704
+ const data = await response.json();
1760
1705
  return {
1761
1706
  id: data.id,
1762
1707
  gateway_ref: data.gateway_ref,
@@ -1765,20 +1710,53 @@ async function initiatePayment(request) {
1765
1710
  checkout_url: data.metadata_json?.checkout_url ?? ""
1766
1711
  };
1767
1712
  }
1768
- async function requestQuote(amount) {
1769
- const { data } = await paymentAxios.post("payments/quote", { amount });
1713
+ async function requestQuote(config, amount) {
1714
+ const response = await fetch(`${config.backendUrls.payment}/payments/quote`, {
1715
+ method: "POST",
1716
+ headers: {
1717
+ "Content-Type": "application/json",
1718
+ "X-Storefront-Key": config.storefrontApiKey,
1719
+ "X-Business-ID": config.businessId
1720
+ },
1721
+ body: JSON.stringify({ amount })
1722
+ });
1723
+ if (!response.ok) throw new Error("Failed to request quote");
1724
+ const data = await response.json();
1770
1725
  return data;
1771
1726
  }
1772
- async function verifyTransaction(reference) {
1773
- const { data } = await paymentAxios.post(
1774
- `payments/verify/${reference}`
1775
- );
1727
+ async function verifyTransaction(configOrReference, reference) {
1728
+ if (typeof configOrReference === "string") {
1729
+ const ref2 = configOrReference;
1730
+ const response2 = await fetch(`/api/payments/verify/${ref2}`, {
1731
+ method: "POST",
1732
+ headers: { "Content-Type": "application/json" }
1733
+ });
1734
+ if (!response2.ok) throw new Error("Failed to verify transaction");
1735
+ return response2.json();
1736
+ }
1737
+ const config = configOrReference;
1738
+ const ref = reference || "";
1739
+ const response = await fetch(`${config.backendUrls.payment}/payments/verify/${ref}`, {
1740
+ method: "POST",
1741
+ headers: {
1742
+ "Content-Type": "application/json",
1743
+ "X-Storefront-Key": config.storefrontApiKey,
1744
+ "X-Business-ID": config.businessId
1745
+ }
1746
+ });
1747
+ if (!response.ok) throw new Error("Failed to verify transaction");
1748
+ const data = await response.json();
1776
1749
  return data;
1777
1750
  }
1778
- async function getTransactionStatus(transactionId) {
1779
- const { data } = await paymentAxios.get(
1780
- `payments/transactions/${transactionId}`
1781
- );
1751
+ async function getTransactionStatus(config, transactionId) {
1752
+ const response = await fetch(`${config.backendUrls.payment}/payments/transactions/${transactionId}`, {
1753
+ headers: {
1754
+ "X-Storefront-Key": config.storefrontApiKey,
1755
+ "X-Business-ID": config.businessId
1756
+ }
1757
+ });
1758
+ if (!response.ok) throw new Error("Failed to get transaction status");
1759
+ const data = await response.json();
1782
1760
  return data;
1783
1761
  }
1784
1762
  var paymentService = {
@@ -1790,28 +1768,81 @@ var paymentService = {
1790
1768
  };
1791
1769
 
1792
1770
  // 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;
1771
+ async function createConsultation(config, accessToken, payload) {
1772
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
1773
+ method: "POST",
1774
+ headers: {
1775
+ "Content-Type": "application/json",
1776
+ "Authorization": `Bearer ${accessToken}`,
1777
+ "X-Storefront-Key": config.storefrontApiKey,
1778
+ "X-Business-ID": config.businessId
1779
+ },
1780
+ body: JSON.stringify(payload)
1781
+ });
1782
+ if (!response.ok) throw new Error("Failed to create consultation");
1783
+ return response.json();
1800
1784
  }
1801
- async function getConsultation(id) {
1802
- const { data } = await storeManagementAxios.get(`social/consultations/${id}`);
1803
- return data;
1785
+ async function getConsultations(config, accessToken) {
1786
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
1787
+ headers: {
1788
+ "Authorization": `Bearer ${accessToken}`,
1789
+ "X-Storefront-Key": config.storefrontApiKey,
1790
+ "X-Business-ID": config.businessId
1791
+ }
1792
+ });
1793
+ if (!response.ok) throw new Error("Failed to get consultations");
1794
+ return response.json();
1804
1795
  }
1805
- async function sendMessage(id, payload) {
1806
- await storeManagementAxios.post(`social/consultations/${id}/messages`, payload);
1796
+ async function getConsultation(config, accessToken, id) {
1797
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}`, {
1798
+ headers: {
1799
+ "Authorization": `Bearer ${accessToken}`,
1800
+ "X-Storefront-Key": config.storefrontApiKey,
1801
+ "X-Business-ID": config.businessId
1802
+ }
1803
+ });
1804
+ if (!response.ok) throw new Error("Failed to get consultation");
1805
+ return response.json();
1807
1806
  }
1808
- async function acceptQuote(id, payload) {
1809
- const { data } = await storeManagementAxios.post(`social/consultations/${id}/accept-quote`, payload);
1810
- return data;
1807
+ async function sendMessage(config, accessToken, id, payload) {
1808
+ await fetch(`${config.backendUrls.store}/social/consultations/${id}/messages`, {
1809
+ method: "POST",
1810
+ headers: {
1811
+ "Content-Type": "application/json",
1812
+ "Authorization": `Bearer ${accessToken}`,
1813
+ "X-Storefront-Key": config.storefrontApiKey,
1814
+ "X-Business-ID": config.businessId
1815
+ },
1816
+ body: JSON.stringify(payload)
1817
+ });
1811
1818
  }
1812
- async function rejectQuote(id, reason) {
1813
- const { data } = await storeManagementAxios.post(`social/consultations/${id}/reject-quote`, { reason });
1814
- return data;
1819
+ async function acceptQuote(config, accessToken, id, payload) {
1820
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/accept-quote`, {
1821
+ method: "POST",
1822
+ headers: {
1823
+ "Content-Type": "application/json",
1824
+ "Authorization": `Bearer ${accessToken}`,
1825
+ "X-Storefront-Key": config.storefrontApiKey,
1826
+ "X-Business-ID": config.businessId
1827
+ },
1828
+ body: JSON.stringify(payload)
1829
+ });
1830
+ if (!response.ok) throw new Error("Failed to accept quote");
1831
+ return response.json();
1832
+ }
1833
+ async function rejectQuote(config, accessToken, id, reason) {
1834
+ const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/reject-quote`, {
1835
+ method: "POST",
1836
+ headers: {
1837
+ "Content-Type": "application/json",
1838
+ "Authorization": `Bearer ${accessToken}`,
1839
+ "X-Storefront-Key": config.storefrontApiKey,
1840
+ "X-Business-ID": config.businessId
1841
+ },
1842
+ body: JSON.stringify({ reason })
1843
+ });
1844
+ if (!response.ok) throw new Error("Failed to reject quote");
1845
+ return response.json();
1815
1846
  }
1816
1847
  var consultationService = {
1817
1848
  createConsultation,
@@ -1823,20 +1854,41 @@ var consultationService = {
1823
1854
  };
1824
1855
 
1825
1856
  // 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;
1857
+ async function getShippingRates(config, payload) {
1858
+ const response = await fetch(`${config.backendUrls.store}/logistics/shipping/rates`, {
1859
+ method: "POST",
1860
+ headers: {
1861
+ "Content-Type": "application/json",
1862
+ "X-Storefront-Key": config.storefrontApiKey,
1863
+ "X-Business-ID": config.businessId
1864
+ },
1865
+ body: JSON.stringify(payload)
1866
+ });
1867
+ if (!response.ok) throw new Error("Failed to get shipping rates");
1868
+ return response.json();
1832
1869
  }
1833
- async function getSellerShippingAddress() {
1834
- const { data } = await storeManagementAxios.get("logistics/shipping-address");
1835
- return data;
1870
+ async function getSellerShippingAddress(config) {
1871
+ const response = await fetch(`${config.backendUrls.store}/logistics/shipping-address`, {
1872
+ headers: {
1873
+ "X-Storefront-Key": config.storefrontApiKey,
1874
+ "X-Business-ID": config.businessId
1875
+ }
1876
+ });
1877
+ if (!response.ok) throw new Error("Failed to get seller shipping address");
1878
+ return response.json();
1836
1879
  }
1837
- async function validateShippingAddress(payload) {
1838
- const { data } = await storeManagementAxios.post("logistics/shipping-address/validate", payload);
1839
- return data;
1880
+ async function validateShippingAddress(config, payload) {
1881
+ const response = await fetch(`${config.backendUrls.store}/logistics/shipping-address/validate`, {
1882
+ method: "POST",
1883
+ headers: {
1884
+ "Content-Type": "application/json",
1885
+ "X-Storefront-Key": config.storefrontApiKey,
1886
+ "X-Business-ID": config.businessId
1887
+ },
1888
+ body: JSON.stringify(payload)
1889
+ });
1890
+ if (!response.ok) throw new Error("Failed to validate shipping address");
1891
+ return response.json();
1840
1892
  }
1841
1893
  var logisticsService = {
1842
1894
  getShippingRates,
@@ -1845,54 +1897,124 @@ var logisticsService = {
1845
1897
  };
1846
1898
 
1847
1899
  // src/services/bespoke.service.ts
1848
- async function checkAvailability(product_id) {
1849
- const { data } = await storeManagementAxios.get(`bespoke/availability/${product_id}`);
1850
- return data;
1900
+ async function checkAvailability(config, product_id) {
1901
+ const response = await fetch(`${config.backendUrls.store}/bespoke/availability/${product_id}`, {
1902
+ headers: {
1903
+ "X-Storefront-Key": config.storefrontApiKey,
1904
+ "X-Business-ID": config.businessId
1905
+ }
1906
+ });
1907
+ if (!response.ok) throw new Error("Failed to check bespoke availability");
1908
+ return response.json();
1851
1909
  }
1852
1910
  var bespokeService = {
1853
1911
  checkAvailability
1854
1912
  };
1855
1913
 
1856
1914
  // 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 } }
1915
+ async function getAvailableSlots(config, product_id, date_from, date_to) {
1916
+ const response = await fetch(
1917
+ `${config.backendUrls.store}/service/available-slots/${product_id}?date_from=${date_from}&date_to=${date_to}`,
1918
+ {
1919
+ headers: {
1920
+ "X-Storefront-Key": config.storefrontApiKey,
1921
+ "X-Business-ID": config.businessId
1922
+ }
1923
+ }
1861
1924
  );
1862
- return data;
1863
- }
1864
- async function bookAppointment(payload) {
1865
- const { data } = await storeManagementAxios.post("service/appointments/", payload);
1866
- return data;
1925
+ if (!response.ok) throw new Error("Failed to get available slots");
1926
+ return response.json();
1927
+ }
1928
+ async function bookAppointment(config, accessToken, payload) {
1929
+ const response = await fetch(`${config.backendUrls.store}/service/appointments/`, {
1930
+ method: "POST",
1931
+ headers: {
1932
+ "Content-Type": "application/json",
1933
+ "Authorization": `Bearer ${accessToken}`,
1934
+ "X-Storefront-Key": config.storefrontApiKey,
1935
+ "X-Business-ID": config.businessId
1936
+ },
1937
+ body: JSON.stringify(payload)
1938
+ });
1939
+ if (!response.ok) throw new Error("Failed to book appointment");
1940
+ return response.json();
1867
1941
  }
1868
- async function getAppointments() {
1869
- const { data } = await storeManagementAxios.get("service/bookings/my");
1870
- return data;
1942
+ async function getAppointments(config, accessToken) {
1943
+ const response = await fetch(`${config.backendUrls.store}/service/bookings/my`, {
1944
+ headers: {
1945
+ "Authorization": `Bearer ${accessToken}`,
1946
+ "X-Storefront-Key": config.storefrontApiKey,
1947
+ "X-Business-ID": config.businessId
1948
+ }
1949
+ });
1950
+ if (!response.ok) throw new Error("Failed to get appointments");
1951
+ return response.json();
1871
1952
  }
1872
- async function getAppointment(id) {
1873
- const { data } = await storeManagementAxios.get(`service/bookings/${id}`);
1874
- return data;
1953
+ async function getAppointment(config, accessToken, id) {
1954
+ const response = await fetch(`${config.backendUrls.store}/service/bookings/${id}`, {
1955
+ headers: {
1956
+ "Authorization": `Bearer ${accessToken}`,
1957
+ "X-Storefront-Key": config.storefrontApiKey,
1958
+ "X-Business-ID": config.businessId
1959
+ }
1960
+ });
1961
+ if (!response.ok) throw new Error("Failed to get appointment");
1962
+ return response.json();
1875
1963
  }
1876
- async function cancelAppointment(id) {
1877
- await storeManagementAxios.delete(`service/bookings/${id}`);
1964
+ async function cancelAppointment(config, accessToken, id) {
1965
+ await fetch(`${config.backendUrls.store}/service/bookings/${id}`, {
1966
+ method: "DELETE",
1967
+ headers: {
1968
+ "Authorization": `Bearer ${accessToken}`,
1969
+ "X-Storefront-Key": config.storefrontApiKey,
1970
+ "X-Business-ID": config.businessId
1971
+ }
1972
+ });
1878
1973
  }
1879
- async function getDeliverables(order_id) {
1880
- const { data } = await storeManagementAxios.get(`service/projects/${order_id}/deliverables/`);
1881
- return data;
1974
+ async function getDeliverables(config, accessToken, order_id) {
1975
+ const response = await fetch(`${config.backendUrls.store}/service/projects/${order_id}/deliverables/`, {
1976
+ headers: {
1977
+ "Authorization": `Bearer ${accessToken}`,
1978
+ "X-Storefront-Key": config.storefrontApiKey,
1979
+ "X-Business-ID": config.businessId
1980
+ }
1981
+ });
1982
+ if (!response.ok) throw new Error("Failed to get deliverables");
1983
+ return response.json();
1882
1984
  }
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 }
1985
+ async function approveDeliverable(config, accessToken, order_id, deliverable_id) {
1986
+ const response = await fetch(
1987
+ `${config.backendUrls.store}/service/projects/${order_id}/deliverables/${deliverable_id}/approve`,
1988
+ {
1989
+ method: "POST",
1990
+ headers: {
1991
+ "Content-Type": "application/json",
1992
+ "Authorization": `Bearer ${accessToken}`,
1993
+ "X-Storefront-Key": config.storefrontApiKey,
1994
+ "X-Business-ID": config.businessId
1995
+ },
1996
+ body: JSON.stringify({ approved: true })
1997
+ }
1887
1998
  );
1888
- return data;
1999
+ if (!response.ok) throw new Error("Failed to approve deliverable");
2000
+ return response.json();
1889
2001
  }
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 }
2002
+ async function requestRevision(config, accessToken, order_id, deliverable_id, feedback) {
2003
+ const response = await fetch(
2004
+ `${config.backendUrls.store}/service/projects/${order_id}/deliverables/${deliverable_id}/revision`,
2005
+ {
2006
+ method: "POST",
2007
+ headers: {
2008
+ "Content-Type": "application/json",
2009
+ "Authorization": `Bearer ${accessToken}`,
2010
+ "X-Storefront-Key": config.storefrontApiKey,
2011
+ "X-Business-ID": config.businessId
2012
+ },
2013
+ body: JSON.stringify({ approved: false, feedback })
2014
+ }
1894
2015
  );
1895
- return data;
2016
+ if (!response.ok) throw new Error("Failed to request revision");
2017
+ return response.json();
1896
2018
  }
1897
2019
  var serviceBookingService = {
1898
2020
  getAvailableSlots,
@@ -1906,19 +2028,31 @@ var serviceBookingService = {
1906
2028
  };
1907
2029
 
1908
2030
  // 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;
2031
+ async function sendContactEmail(config, payload) {
2032
+ const response = await fetch(`${config.backendUrls.notifications}/contact/send-contact-email`, {
2033
+ method: "POST",
2034
+ headers: {
2035
+ "Content-Type": "application/json",
2036
+ "X-Storefront-Key": config.storefrontApiKey,
2037
+ "X-Business-ID": config.businessId
2038
+ },
2039
+ body: JSON.stringify(payload)
2040
+ });
2041
+ if (!response.ok) throw new Error("Failed to send contact email");
2042
+ return response.json();
2043
+ }
2044
+ async function sendContactConfirmation(config, payload) {
2045
+ const response = await fetch(`${config.backendUrls.notifications}/contact/send-contact-confirmation`, {
2046
+ method: "POST",
2047
+ headers: {
2048
+ "Content-Type": "application/json",
2049
+ "X-Storefront-Key": config.storefrontApiKey,
2050
+ "X-Business-ID": config.businessId
2051
+ },
2052
+ body: JSON.stringify(payload)
2053
+ });
2054
+ if (!response.ok) throw new Error("Failed to send contact confirmation");
2055
+ return response.json();
1922
2056
  }
1923
2057
  var notificationsService = {
1924
2058
  sendContactEmail,
@@ -1939,17 +2073,35 @@ async function googleTranslate(text, target, source = "en") {
1939
2073
  }
1940
2074
 
1941
2075
  // src/services/config.service.ts
1942
- async function getSupportedLanguages() {
1943
- const { data } = await paymentAxios.get("/config/supported-languages");
1944
- return data;
2076
+ async function getSupportedLanguages(config) {
2077
+ const response = await fetch(`${config.backendUrls.payment}/config/supported-languages`, {
2078
+ headers: {
2079
+ "X-Storefront-Key": config.storefrontApiKey,
2080
+ "X-Business-ID": config.businessId
2081
+ }
2082
+ });
2083
+ if (!response.ok) throw new Error("Failed to get supported languages");
2084
+ return response.json();
1945
2085
  }
1946
- async function getSupportedCurrencies() {
1947
- const { data } = await paymentAxios.get("/config/supported-currencies");
1948
- return data;
2086
+ async function getSupportedCurrencies(config) {
2087
+ const response = await fetch(`${config.backendUrls.payment}/config/supported-currencies`, {
2088
+ headers: {
2089
+ "X-Storefront-Key": config.storefrontApiKey,
2090
+ "X-Business-ID": config.businessId
2091
+ }
2092
+ });
2093
+ if (!response.ok) throw new Error("Failed to get supported currencies");
2094
+ return response.json();
1949
2095
  }
1950
- async function getBusinessConfig() {
1951
- const { data } = await publicStoreAxios.get("business/profile");
1952
- return data;
2096
+ async function getBusinessConfig(config) {
2097
+ const response = await fetch(`${config.backendUrls.auth}/internal/businesses/${config.businessId}/`, {
2098
+ headers: {
2099
+ "X-Storefront-Key": config.storefrontApiKey,
2100
+ "X-Business-ID": config.businessId
2101
+ }
2102
+ });
2103
+ if (!response.ok) throw new Error("Failed to get business config");
2104
+ return response.json();
1953
2105
  }
1954
2106
  var configService = {
1955
2107
  getSupportedLanguages,
@@ -1958,1194 +2110,454 @@ var configService = {
1958
2110
  };
1959
2111
 
1960
2112
  // 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`,
2113
+ async function listCmsEntries(config, modelSlug, params) {
2114
+ const queryParams = new URLSearchParams();
2115
+ queryParams.set("page", (params?.page || 1).toString());
2116
+ queryParams.set("page_size", (params?.page_size || 50).toString());
2117
+ const response = await fetch(
2118
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries?${queryParams.toString()}`,
1966
2119
  {
1967
- params: {
1968
- page: params?.page || 1,
1969
- page_size: params?.page_size || 50
2120
+ headers: {
2121
+ "X-Storefront-Key": config.storefrontApiKey,
2122
+ "X-Business-ID": config.businessId
1970
2123
  }
1971
2124
  }
1972
2125
  );
1973
- return response.data;
2126
+ if (!response.ok) throw new Error("Failed to list CMS entries");
2127
+ return response.json();
1974
2128
  }
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
2129
+ async function getCmsEntry(config, modelSlug, entryId) {
2130
+ const response = await fetch(
2131
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
2132
+ {
2133
+ headers: {
2134
+ "X-Storefront-Key": config.storefrontApiKey,
2135
+ "X-Business-ID": config.businessId
2136
+ }
2137
+ }
1989
2138
  );
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
2139
+ if (!response.ok) throw new Error("Failed to get CMS entry");
2140
+ return response.json();
2141
+ }
2142
+ async function createCmsEntry(config, accessToken, modelSlug, params) {
2143
+ const response = await fetch(
2144
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries`,
2145
+ {
2146
+ method: "POST",
2147
+ headers: {
2148
+ "Content-Type": "application/json",
2149
+ "Authorization": `Bearer ${accessToken}`,
2150
+ "X-Storefront-Key": config.storefrontApiKey,
2151
+ "X-Business-ID": config.businessId
2152
+ },
2153
+ body: JSON.stringify(params)
2154
+ }
1998
2155
  );
1999
- return response.data;
2156
+ if (!response.ok) throw new Error("Failed to create CMS entry");
2157
+ return response.json();
2000
2158
  }
2001
- async function deleteCmsEntry(modelSlug, entryId) {
2002
- const config = getRuntimeConfig();
2003
- const { businessId } = config;
2004
- await cmsAxios.delete(
2005
- `/sdk/${businessId}/${modelSlug}/entries/${entryId}`
2159
+ async function updateCmsEntry(config, accessToken, modelSlug, entryId, params) {
2160
+ const response = await fetch(
2161
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
2162
+ {
2163
+ method: "PUT",
2164
+ headers: {
2165
+ "Content-Type": "application/json",
2166
+ "Authorization": `Bearer ${accessToken}`,
2167
+ "X-Storefront-Key": config.storefrontApiKey,
2168
+ "X-Business-ID": config.businessId
2169
+ },
2170
+ body: JSON.stringify(params)
2171
+ }
2006
2172
  );
2173
+ if (!response.ok) throw new Error("Failed to update CMS entry");
2174
+ return response.json();
2007
2175
  }
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
- }
2176
+ async function deleteCmsEntry(config, accessToken, modelSlug, entryId) {
2177
+ const response = await fetch(
2178
+ `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
2179
+ {
2180
+ method: "DELETE",
2181
+ headers: {
2182
+ "Authorization": `Bearer ${accessToken}`,
2183
+ "X-Storefront-Key": config.storefrontApiKey,
2184
+ "X-Business-ID": config.businessId
2048
2185
  }
2049
2186
  }
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
- };
2187
+ );
2188
+ if (!response.ok) throw new Error("Failed to delete CMS entry");
2129
2189
  }
2130
2190
 
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
- });
2191
+ // src/utils/cache.ts
2192
+ var CACHE_TIERS = {
2193
+ none: { staleTime: 0, gcTime: 0 },
2194
+ infinity: { staleTime: Infinity, gcTime: 0 },
2195
+ low: { staleTime: 1e3 * 30, gcTime: 1e3 * 60 },
2196
+ // 30s / 1m
2197
+ medium: { staleTime: 1e3 * 60 * 5, gcTime: 1e3 * 60 * 10 },
2198
+ // 5m / 10m
2199
+ high: { staleTime: 1e3 * 60 * 30, gcTime: 1e3 * 60 * 60 }
2200
+ // 30m / 1h
2201
+ };
2202
+ var isDevelopment = true;
2203
+ function setEnvironmentMode(development) {
2204
+ isDevelopment = development;
2178
2205
  }
2206
+ var getCacheTier = (tier) => {
2207
+ if (isDevelopment) return CACHE_TIERS.none;
2208
+ return CACHE_TIERS[tier];
2209
+ };
2179
2210
 
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
- });
2211
+ // src/utils/logger.ts
2212
+ var isDevelopment2 = true;
2213
+ function setLoggerEnvironmentMode(development) {
2214
+ isDevelopment2 = development;
2258
2215
  }
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"] });
2216
+ var logger = {
2217
+ log: (...args) => {
2218
+ if (isDevelopment2) {
2219
+ console.log(...args);
2266
2220
  }
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"] });
2221
+ },
2222
+ warn: (...args) => {
2223
+ if (isDevelopment2) {
2224
+ console.warn(...args);
2276
2225
  }
2277
- });
2278
- }
2279
- function useUpdateProfile() {
2280
- const queryClient = useQueryClient3();
2281
- return useMutation3({
2282
- mutationFn: updateProfile,
2283
- onSuccess: () => {
2284
- queryClient.invalidateQueries({ queryKey: ["auth-user"] });
2226
+ },
2227
+ /**
2228
+ * Logs a warning to the console in development only.
2229
+ * Alias for warn() for Python logging compatibility.
2230
+ * In production, this is a no-op.
2231
+ */
2232
+ warning: (...args) => {
2233
+ if (isDevelopment2) {
2234
+ console.warn(...args);
2285
2235
  }
2286
- });
2287
- }
2288
- function useLogout() {
2289
- const queryClient = useQueryClient3();
2290
- return useMutation3({
2291
- mutationFn: logout,
2292
- onSuccess: () => {
2293
- queryClient.clear();
2236
+ },
2237
+ error: (...args) => {
2238
+ if (isDevelopment2) {
2239
+ console.error(...args);
2294
2240
  }
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();
2241
+ },
2242
+ info: (...args) => {
2243
+ if (isDevelopment2) {
2244
+ console.info(...args);
2314
2245
  }
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);
2246
+ },
2247
+ createScope: (scope) => ({
2248
+ log: (...args) => {
2249
+ if (isDevelopment2) {
2250
+ console.log(`[${scope}]`, ...args);
2251
+ }
2532
2252
  },
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);
2253
+ warn: (...args) => {
2254
+ if (isDevelopment2) {
2255
+ console.warn(`[${scope}]`, ...args);
2256
+ }
2544
2257
  },
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);
2258
+ warning: (...args) => {
2259
+ if (isDevelopment2) {
2260
+ console.warn(`[${scope}]`, ...args);
2261
+ }
2556
2262
  },
2557
- onSuccess: () => {
2558
- queryClient.invalidateQueries({ queryKey: wishlistKeys.all });
2559
- queryClient.invalidateQueries({ queryKey: ["wishlist", "check"] });
2263
+ error: (...args) => {
2264
+ if (isDevelopment2) {
2265
+ console.error(`[${scope}]`, ...args);
2266
+ }
2267
+ },
2268
+ info: (...args) => {
2269
+ if (isDevelopment2) {
2270
+ console.info(`[${scope}]`, ...args);
2271
+ }
2560
2272
  }
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
- }
2273
+ })
2274
+ };
2573
2275
 
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
- });
2276
+ // src/utils/sanitize-url.ts
2277
+ var InvalidBaseURLError = class extends Error {
2278
+ constructor(message) {
2279
+ super(message);
2280
+ this.name = "InvalidBaseURLError";
2281
+ }
2282
+ };
2283
+ var ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:", "ws:", "wss:"]);
2284
+ function sanitizeBaseUrl(url, name = "URL") {
2285
+ if (url == null) {
2286
+ throw new InvalidBaseURLError(`${name} is not set`);
2287
+ }
2288
+ const cleaned0 = url.trim();
2289
+ if (!cleaned0) {
2290
+ throw new InvalidBaseURLError(`${name} is empty`);
2291
+ }
2292
+ const cleaned = cleaned0.replace(/\/+$/, "");
2293
+ let parsed;
2294
+ try {
2295
+ parsed = new URL(cleaned);
2296
+ } catch {
2297
+ throw new InvalidBaseURLError(
2298
+ `${name} must start with http://, https://, ws://, or wss://, got: ${url}`
2299
+ );
2300
+ }
2301
+ if (!ALLOWED_SCHEMES.has(parsed.protocol)) {
2302
+ throw new InvalidBaseURLError(
2303
+ `${name} must start with http://, https://, ws://, or wss://, got: ${url}`
2304
+ );
2305
+ }
2306
+ if (!parsed.hostname) {
2307
+ throw new InvalidBaseURLError(`${name} is missing a host: ${url}`);
2308
+ }
2309
+ if (parsed.search || parsed.hash) {
2310
+ throw new InvalidBaseURLError(
2311
+ `${name} should not contain a query or fragment: ${url}`
2312
+ );
2313
+ }
2314
+ return cleaned;
2638
2315
  }
2639
2316
 
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
- });
2317
+ // src/utils/customer.ts
2318
+ function buildFullName2(firstname, lastname) {
2319
+ const name = [firstname, lastname].filter(Boolean).join(" ").trim();
2320
+ return name || void 0;
2647
2321
  }
2648
- function useConsultation(id) {
2649
- return useQuery13({
2650
- queryKey: ["consultation", id],
2651
- queryFn: () => consultationService.getConsultation(id),
2652
- enabled: !!id
2653
- });
2322
+ function splitFullName2(fullName) {
2323
+ if (!fullName?.trim()) return { firstname: "", lastname: "" };
2324
+ const parts = fullName.trim().split(/\s+/);
2325
+ return {
2326
+ firstname: parts[0] ?? "",
2327
+ lastname: parts.slice(1).join(" ")
2328
+ };
2654
2329
  }
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
- });
2330
+ function getCustomerDisplayName(user) {
2331
+ const fromParts = buildFullName2(user.firstname, user.lastname);
2332
+ return fromParts || user.full_name || user.email.split("@")[0];
2663
2333
  }
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
- });
2334
+ function getStorefrontUrl(businessId, customDomain) {
2335
+ if (customDomain && customDomain.trim()) {
2336
+ const cleanDomain = customDomain.trim().replace(/^https?:\/\//, "");
2337
+ return `https://${cleanDomain}`;
2338
+ }
2339
+ const cleanBid = (businessId || "store").toLowerCase().trim();
2340
+ return `https://${cleanBid}.kasuvia.com`;
2672
2341
  }
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
- });
2342
+
2343
+ // src/utils/checkout.ts
2344
+ function buildDeliveryAddress(customer, location) {
2345
+ return {
2346
+ first_name: customer.first_name,
2347
+ last_name: customer.last_name,
2348
+ phone: customer.phone,
2349
+ ...location
2350
+ };
2681
2351
  }
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
- });
2352
+ function getCheckoutCustomerName(customer) {
2353
+ return buildFullName2(customer.first_name, customer.last_name) ?? customer.email.split("@")[0];
2690
2354
  }
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 };
2355
+ function enrichCompletedOrder(order, options) {
2356
+ const customerName = getCheckoutCustomerName(options.customer);
2357
+ return {
2358
+ ...order,
2359
+ customerName: order.customerName || customerName,
2360
+ customerEmail: order.customerEmail || options.customer.email,
2361
+ shippingAddress: order.shippingAddress ?? (options.productType === "physical" && options.location ? buildDeliveryAddress(options.customer, options.location) : void 0),
2362
+ bespokeBrief: order.bespokeBrief ?? options.bespokeBrief
2363
+ };
2777
2364
  }
2778
2365
 
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;
2366
+ // src/utils/error-handler.ts
2367
+ function getErrorMessage(error, fallback = "Something went wrong") {
2368
+ if (error instanceof Error) {
2369
+ return error.message;
2370
+ }
2371
+ if (error instanceof Response) {
2372
+ return `HTTP ${error.status}: ${error.statusText}`;
2373
+ }
2374
+ if (typeof error === "object" && error !== null) {
2375
+ const err = error;
2376
+ return err.detail || err.message || fallback;
2377
+ }
2378
+ return fallback;
2881
2379
  }
2882
2380
 
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;
2381
+ // src/utils/storage.ts
2382
+ function getPrefixedKey(businessId, key) {
2383
+ const cleanKey = key.startsWith("kasuvia_") ? key.substring(5) : key;
2384
+ return businessId ? `kasuvia-sf-${businessId}-${cleanKey}` : `kasuvia-sf-anon-${cleanKey}`;
2891
2385
  }
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(() => {
2386
+ var sessionStore = {
2387
+ get: (businessIdOrKey, key) => {
2388
+ if (typeof window === "undefined") return null;
2389
+ const bId = key ? businessIdOrKey : "";
2390
+ const k = key || businessIdOrKey;
2391
+ return sessionStorage.getItem(getPrefixedKey(bId, k));
2392
+ },
2393
+ set: (businessIdOrKey, keyOrVal, val) => {
2911
2394
  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(() => {
2395
+ const bId = val !== void 0 ? businessIdOrKey : "";
2396
+ const k = val !== void 0 ? keyOrVal : businessIdOrKey;
2397
+ const v = val !== void 0 ? val : keyOrVal;
2398
+ sessionStorage.setItem(getPrefixedKey(bId, k), v);
2399
+ },
2400
+ remove: (businessIdOrKey, key) => {
2924
2401
  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;
2402
+ const bId = key ? businessIdOrKey : "";
2403
+ const k = key || businessIdOrKey;
2404
+ sessionStorage.removeItem(getPrefixedKey(bId, k));
2405
+ },
2406
+ getJSON: (businessIdOrKey, key) => {
2407
+ if (typeof window === "undefined") return null;
2408
+ const bId = key ? businessIdOrKey : "";
2409
+ const k = key || businessIdOrKey;
2410
+ const value = sessionStorage.getItem(getPrefixedKey(bId, k));
2411
+ if (!value) return null;
2412
+ try {
2413
+ return JSON.parse(value);
2414
+ } catch {
2415
+ return null;
2952
2416
  }
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(() => {
2417
+ },
2418
+ setJSON: (businessIdOrKey, keyOrVal, val) => {
2964
2419
  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);
2420
+ const bId = val !== void 0 ? businessIdOrKey : "";
2421
+ const k = val !== void 0 ? keyOrVal : businessIdOrKey;
2422
+ const v = val !== void 0 ? val : keyOrVal;
2423
+ sessionStorage.setItem(getPrefixedKey(bId, k), JSON.stringify(v));
2424
+ }
2425
+ };
2426
+ var localStore = {
2427
+ get: (businessIdOrKey, key) => {
2428
+ if (typeof window === "undefined") return null;
2429
+ const bId = key ? businessIdOrKey : "";
2430
+ const k = key || businessIdOrKey;
2431
+ return localStorage.getItem(getPrefixedKey(bId, k));
2432
+ },
2433
+ set: (businessIdOrKey, keyOrVal, val) => {
2434
+ if (typeof window === "undefined") return;
2435
+ const bId = val !== void 0 ? businessIdOrKey : "";
2436
+ const k = val !== void 0 ? keyOrVal : businessIdOrKey;
2437
+ const v = val !== void 0 ? val : keyOrVal;
2438
+ localStorage.setItem(getPrefixedKey(bId, k), v);
2439
+ },
2440
+ remove: (businessIdOrKey, key) => {
2441
+ if (typeof window === "undefined") return;
2442
+ const bId = key ? businessIdOrKey : "";
2443
+ const k = key || businessIdOrKey;
2444
+ localStorage.removeItem(getPrefixedKey(bId, k));
2445
+ },
2446
+ getJSON: (businessIdOrKey, key) => {
2447
+ if (typeof window === "undefined") return null;
2448
+ const bId = key ? businessIdOrKey : "";
2449
+ const k = key || businessIdOrKey;
2450
+ const value = localStorage.getItem(getPrefixedKey(bId, k));
2451
+ if (!value) return null;
2452
+ try {
2453
+ return JSON.parse(value);
2454
+ } catch {
2455
+ return null;
2998
2456
  }
2999
- }, [appLang, isLoaded, changeLanguage]);
3000
- return { isLoaded };
3001
- }
2457
+ },
2458
+ setJSON: (businessIdOrKey, keyOrVal, val) => {
2459
+ if (typeof window === "undefined") return;
2460
+ const bId = val !== void 0 ? businessIdOrKey : "";
2461
+ const k = val !== void 0 ? keyOrVal : businessIdOrKey;
2462
+ const v = val !== void 0 ? val : keyOrVal;
2463
+ localStorage.setItem(getPrefixedKey(bId, k), JSON.stringify(v));
2464
+ }
2465
+ };
3002
2466
 
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
- });
2467
+ // src/utils/validators.ts
2468
+ function validateEmail(email) {
2469
+ if (!email || email.trim() === "") {
2470
+ return "Email is required";
2471
+ }
2472
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2473
+ if (!emailRegex.test(email)) {
2474
+ return "Please enter a valid email address";
2475
+ }
2476
+ return null;
3045
2477
  }
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
- };
2478
+ function validatePassword(password) {
2479
+ if (!password || password.trim() === "") {
2480
+ return "Password is required";
2481
+ }
2482
+ if (password.length < 8) {
2483
+ return "Password must be at least 8 characters";
2484
+ }
2485
+ if (password.length > 72) {
2486
+ return "Password cannot exceed 72 characters";
2487
+ }
2488
+ if (!/[A-Z]/.test(password)) {
2489
+ return "Password must contain at least one uppercase letter";
2490
+ }
2491
+ if (!/[a-z]/.test(password)) {
2492
+ return "Password must contain at least one lowercase letter";
2493
+ }
2494
+ if (!/[0-9]/.test(password)) {
2495
+ return "Password must contain at least one number";
2496
+ }
2497
+ return null;
3064
2498
  }
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
- };
2499
+ function validateName(name, fieldName = "Name") {
2500
+ if (!name || name.trim() === "") {
2501
+ return `${fieldName} is required`;
2502
+ }
2503
+ if (name.trim().length < 2) {
2504
+ return `${fieldName} must be at least 2 characters`;
2505
+ }
2506
+ if (name.trim().length > 50) {
2507
+ return `${fieldName} cannot exceed 50 characters`;
2508
+ }
2509
+ const nameRegex = /^[a-zA-Z\s\-'\u00C0-\u017F]+$/;
2510
+ if (!nameRegex.test(name.trim())) {
2511
+ return `${fieldName} can only contain letters, spaces, hyphens, and apostrophes`;
2512
+ }
2513
+ return null;
3077
2514
  }
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
- };
2515
+ function validateRequired(value, fieldName) {
2516
+ if (!value || value.trim() === "") {
2517
+ return `${fieldName} is required`;
2518
+ }
2519
+ return null;
3091
2520
  }
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
- };
2521
+ function validateConfirmPassword(password, confirmPassword) {
2522
+ if (!confirmPassword) return null;
2523
+ if (confirmPassword !== password) {
2524
+ return "Passwords do not match";
2525
+ }
2526
+ return null;
3106
2527
  }
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
- };
2528
+ function validateMessage(message) {
2529
+ if (!message || message.trim() === "") {
2530
+ return "Message is required";
2531
+ }
2532
+ if (message.trim().length < 10) {
2533
+ return "Message must be at least 10 characters";
2534
+ }
2535
+ return null;
3121
2536
  }
3122
2537
  export {
3123
- AuthCtx,
3124
- AuthProvider,
3125
- CartCtx,
3126
- CartProvider,
3127
2538
  InvalidBaseURLError,
2539
+ STORAGE_KEYS,
2540
+ SdkProvider,
2541
+ ServiceLocationTypeEnum,
2542
+ ServiceRecurringIntervalEnum,
2543
+ ServiceTypeEnum,
3128
2544
  acceptQuote,
3129
2545
  addToCart,
3130
2546
  addToGuestCart,
3131
2547
  addToWishlist,
3132
2548
  approveDeliverable,
3133
- authAxios,
3134
2549
  bespokeService,
3135
2550
  bookAppointment,
3136
2551
  buildDeliveryAddress,
3137
- buildFullName,
2552
+ buildFullName2 as buildFullName,
3138
2553
  cancelAppointment,
3139
2554
  cancelOrder,
3140
2555
  checkAvailability,
3141
2556
  checkInWishlist,
3142
2557
  clearCart,
3143
2558
  clearGuestCart,
3144
- clearGuestSessionId,
3145
- cmsAxios,
3146
- collectionKeys,
2559
+ clearTokens,
3147
2560
  configService,
3148
- configureHttpClients,
3149
2561
  consultationService,
3150
2562
  createCmsEntry,
3151
2563
  createConsultation,
@@ -3159,7 +2571,6 @@ export {
3159
2571
  getAppointments,
3160
2572
  getAuthUser,
3161
2573
  getAvailableSlots,
3162
- getBackendUrl,
3163
2574
  getBusinessConfig,
3164
2575
  getCacheTier,
3165
2576
  getCart,
@@ -3167,43 +2578,38 @@ export {
3167
2578
  getCmsEntry,
3168
2579
  getConsultation,
3169
2580
  getConsultations,
3170
- getCountries,
3171
2581
  getCustomerDisplayName,
3172
2582
  getDeliverables,
3173
2583
  getErrorMessage,
3174
2584
  getFeaturedProducts,
3175
- getGraphQLClient,
3176
2585
  getGuestCart,
3177
2586
  getGuestCartCount,
3178
2587
  getGuestCartProductType,
3179
2588
  getGuestCartSubtotal,
3180
- getGuestSessionId,
3181
2589
  getLatestProducts,
2590
+ getLowStockProducts,
3182
2591
  getMe,
3183
2592
  getNewProducts,
3184
- getOrCreateGuestSessionId,
2593
+ getOnSaleProducts,
3185
2594
  getOrders,
3186
2595
  getPopularProducts,
3187
2596
  getRecommendedProducts,
3188
- getRuntimeConfig,
3189
2597
  getSellerShippingAddress,
3190
2598
  getShippingRates,
3191
- getStates,
2599
+ getStoredTokens,
3192
2600
  getStorefrontCollectionBySlug,
3193
2601
  getStorefrontCollections,
3194
2602
  getStorefrontProductBySlug,
3195
2603
  getStorefrontProducts,
2604
+ getStorefrontUrl,
3196
2605
  getSupportedCurrencies,
3197
- getSupportedCurrenciesList,
3198
2606
  getSupportedLanguages,
3199
- getSupportedLanguagesList,
3200
2607
  getTransactionStatus,
3201
2608
  getWishlist,
3202
2609
  googleTranslate,
3203
- initSdk,
3204
2610
  initiatePayment,
3205
- isInitialized,
3206
2611
  listCmsEntries,
2612
+ localStore,
3207
2613
  logger,
3208
2614
  loginCustomer,
3209
2615
  logisticsService,
@@ -3212,10 +2618,7 @@ export {
3212
2618
  mergeGuestCart,
3213
2619
  mergeGuestCartIfPresent,
3214
2620
  notificationsService,
3215
- paymentAxios,
3216
2621
  paymentService,
3217
- productKeys,
3218
- publicStoreAxios,
3219
2622
  refreshToken,
3220
2623
  registerCustomer,
3221
2624
  rejectQuote,
@@ -3225,90 +2628,31 @@ export {
3225
2628
  removeProductFromWishlist,
3226
2629
  requestQuote,
3227
2630
  requestRevision,
3228
- resetConfig,
3229
- resetGraphQLClient,
3230
2631
  sanitizeBaseUrl,
3231
2632
  sendContactConfirmation,
3232
2633
  sendContactEmail,
3233
2634
  sendMessage,
3234
2635
  serviceBookingService,
2636
+ sessionStore,
3235
2637
  setEnvironmentMode,
3236
2638
  setLoggerEnvironmentMode,
3237
2639
  silentRefresh,
3238
- splitFullName,
3239
- storeManagementAxios,
2640
+ splitFullName2 as splitFullName,
3240
2641
  storeTokens,
3241
- tokenStore,
3242
2642
  trackOrder,
3243
2643
  updateCartItem,
3244
2644
  updateCmsEntry,
3245
2645
  updateGuestCartItemQuantity,
3246
2646
  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,
2647
+ useSdkContext,
2648
+ validateConfirmPassword,
2649
+ validateEmail,
2650
+ validateMessage,
2651
+ validateName,
2652
+ validatePassword,
2653
+ validateRequired,
3309
2654
  validateShippingAddress,
3310
2655
  verifySocialToken,
3311
- verifyTransaction,
3312
- wishlistKeys
2656
+ verifyTransaction
3313
2657
  };
3314
2658
  //# sourceMappingURL=index.mjs.map