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