@kasuvia/sdk 0.0.8 → 0.0.9

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 (176) hide show
  1. package/README.md +42 -15
  2. package/dist/AddressAutocomplete-CjcqPElD.d.mts +46 -0
  3. package/dist/AddressAutocomplete-CvJHuRkf.d.ts +46 -0
  4. package/dist/components/index.d.mts +497 -0
  5. package/dist/components/index.d.ts +497 -0
  6. package/dist/components/index.js +4217 -0
  7. package/dist/components/index.js.map +1 -0
  8. package/dist/components/index.mjs +4194 -0
  9. package/dist/components/index.mjs.map +1 -0
  10. package/dist/config/server.d.mts +26 -0
  11. package/dist/config/server.d.ts +26 -0
  12. package/dist/config/server.js +38 -0
  13. package/dist/config/server.js.map +1 -0
  14. package/dist/config/server.mjs +13 -0
  15. package/dist/config/server.mjs.map +1 -0
  16. package/dist/hooks/index.d.mts +393 -160
  17. package/dist/hooks/index.d.ts +393 -160
  18. package/dist/hooks/index.js +2792 -2137
  19. package/dist/hooks/index.js.map +1 -1
  20. package/dist/hooks/index.mjs +2734 -2121
  21. package/dist/hooks/index.mjs.map +1 -1
  22. package/dist/index-CNW_LINy.d.mts +578 -0
  23. package/dist/index-CNW_LINy.d.ts +578 -0
  24. package/dist/{index-C1chUA3P.d.mts → index-F7N6UItS.d.mts} +1 -1
  25. package/dist/{index-C1chUA3P.d.ts → index-F7N6UItS.d.ts} +1 -1
  26. package/dist/index-NkI10J_E.d.mts +40 -0
  27. package/dist/index-NkI10J_E.d.ts +40 -0
  28. package/dist/index.d.mts +20437 -103
  29. package/dist/index.d.ts +20437 -103
  30. package/dist/index.js +2111 -1802
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +2006 -1786
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/media.service-Cx7dQjzX.d.mts +1393 -0
  35. package/dist/media.service-mrBFJ2UQ.d.ts +1393 -0
  36. package/dist/services/index.d.mts +908 -2
  37. package/dist/services/index.d.ts +908 -2
  38. package/dist/services/index.js +1492 -1686
  39. package/dist/services/index.js.map +1 -1
  40. package/dist/services/index.mjs +1431 -1670
  41. package/dist/services/index.mjs.map +1 -1
  42. package/package.json +46 -6
  43. package/src/components/bespoke/BespokeAvailabilityBadge.tsx +32 -0
  44. package/src/components/bespoke/BespokeProgressTracker.tsx +58 -0
  45. package/src/components/bespoke/index.ts +3 -0
  46. package/src/components/booking/SlotPicker.tsx +97 -0
  47. package/src/components/booking/index.ts +1 -0
  48. package/src/components/cart/CartItem.tsx +81 -0
  49. package/src/components/cart/CartSidebar.tsx +115 -0
  50. package/src/components/cart/CartTypeMismatchBanner.tsx +55 -0
  51. package/src/components/cart/index.ts +3 -0
  52. package/src/components/index.ts +8 -0
  53. package/src/components/orders/DeliverableReviewer.tsx +139 -0
  54. package/src/components/orders/index.ts +1 -0
  55. package/src/components/product/ProductCard.tsx +350 -0
  56. package/src/components/product/ProductGrid.tsx +84 -0
  57. package/src/components/product/index.ts +2 -0
  58. package/src/components/shared/AddressAutocomplete.tsx +212 -0
  59. package/src/components/shared/AnalyticsScripts.tsx +56 -0
  60. package/src/components/shared/CookieConsentBanner.tsx +98 -0
  61. package/src/components/shared/ImageEditorModal.tsx +1066 -0
  62. package/src/components/shared/ImageViewerModal.tsx +598 -0
  63. package/src/components/shared/LucideReactIcon.tsx +52 -0
  64. package/src/components/shared/MapPinDrop.tsx +101 -0
  65. package/src/components/shared/MultiSelectPicker.tsx +193 -0
  66. package/src/components/shared/OfflineBanner.tsx +46 -0
  67. package/src/components/shared/SearchableInput.tsx +153 -0
  68. package/src/components/shared/SearchablePopover.tsx +166 -0
  69. package/src/components/shared/SmartImage.tsx +311 -0
  70. package/src/components/shared/TruncatedValue.tsx +27 -0
  71. package/src/components/shared/UnsavedChangesGuard.tsx +138 -0
  72. package/src/components/shared/index.ts +15 -0
  73. package/src/components/skeletons/CardSkeleton.tsx +26 -0
  74. package/src/components/skeletons/CartItemSkeleton.tsx +26 -0
  75. package/src/components/skeletons/OrderItemSkeleton.tsx +26 -0
  76. package/src/components/skeletons/ProductCardSkeleton.tsx +26 -0
  77. package/src/components/skeletons/TableSkeleton.tsx +42 -0
  78. package/src/components/skeletons/index.ts +5 -0
  79. package/src/config/index.ts +22 -4
  80. package/src/config/server.ts +45 -0
  81. package/src/context/sdk-context.tsx +5 -2
  82. package/src/generated/auth-openapi.ts +2935 -0
  83. package/src/generated/cart-openapi.ts +652 -0
  84. package/src/generated/cms-openapi.ts +1668 -0
  85. package/src/generated/crm-openapi.ts +986 -0
  86. package/src/generated/graphql.ts +126 -0
  87. package/src/generated/index.ts +11 -0
  88. package/src/generated/media-openapi.ts +613 -0
  89. package/src/generated/notification-openapi.ts +862 -0
  90. package/src/generated/payment-openapi.ts +2713 -0
  91. package/src/generated/store-openapi.ts +9510 -0
  92. package/src/graphql/operations/collections.graphql +32 -0
  93. package/src/graphql/operations/products.graphql +197 -0
  94. package/src/graphql/operations/wishlist.graphql +25 -0
  95. package/src/hooks/index.ts +9 -2
  96. package/src/hooks/use-auth.ts +163 -69
  97. package/src/hooks/use-bespoke-availability.ts +39 -22
  98. package/src/hooks/use-business-config.ts +51 -0
  99. package/src/hooks/use-cart.ts +310 -238
  100. package/src/hooks/use-cms.ts +107 -127
  101. package/src/hooks/use-collections.ts +35 -55
  102. package/src/hooks/use-consultations.ts +9 -136
  103. package/src/hooks/use-countries.ts +19 -28
  104. package/src/hooks/use-currencies.ts +8 -20
  105. package/src/hooks/use-customer-address.ts +64 -0
  106. package/src/hooks/use-feedback.ts +34 -0
  107. package/src/hooks/use-languages.ts +26 -39
  108. package/src/hooks/use-media-upload.ts +23 -0
  109. package/src/hooks/use-notification-stream.ts +88 -0
  110. package/src/hooks/use-notifications.ts +163 -0
  111. package/src/hooks/use-order-stream.ts +29 -29
  112. package/src/hooks/use-orders.ts +91 -73
  113. package/src/hooks/use-payment.ts +116 -84
  114. package/src/hooks/use-products.ts +65 -269
  115. package/src/hooks/use-push-notifications.ts +122 -0
  116. package/src/hooks/use-reviews.ts +175 -0
  117. package/src/hooks/use-service-booking.ts +109 -132
  118. package/src/hooks/use-states.ts +16 -30
  119. package/src/hooks/use-wishlist.ts +44 -69
  120. package/src/index.ts +15 -11
  121. package/src/services/auth.service.ts +422 -132
  122. package/src/services/bespoke.service.ts +69 -10
  123. package/src/services/cart.service.ts +155 -186
  124. package/src/services/cms.service.ts +41 -50
  125. package/src/services/collection.service.ts +25 -63
  126. package/src/services/config.service.ts +10 -21
  127. package/src/services/consultation.service.ts +36 -93
  128. package/src/services/feedback.service.ts +76 -0
  129. package/src/services/index.ts +7 -1
  130. package/src/services/legal.service.ts +62 -0
  131. package/src/services/logistics.service.ts +235 -53
  132. package/src/services/media.service.ts +115 -0
  133. package/src/services/notifications.service.ts +204 -20
  134. package/src/services/order.service.ts +498 -127
  135. package/src/services/payment.service.ts +149 -100
  136. package/src/services/product.service.ts +157 -814
  137. package/src/services/review.service.ts +211 -0
  138. package/src/services/service-booking.service.ts +198 -99
  139. package/src/services/wishlist.service.ts +27 -74
  140. package/src/types/auth/index.ts +161 -18
  141. package/src/types/business/index.ts +9 -1
  142. package/src/types/cms/index.ts +91 -6
  143. package/src/types/cms/legal.ts +18 -0
  144. package/src/types/consultations/index.ts +60 -68
  145. package/src/types/index.ts +5 -3
  146. package/src/types/media/index.ts +35 -3
  147. package/src/types/payments/index.ts +80 -16
  148. package/src/types/reviews/index.ts +116 -0
  149. package/src/types/services/index.ts +113 -38
  150. package/src/types/store/checkout.ts +53 -0
  151. package/src/types/store/index.ts +273 -52
  152. package/src/types/store/invoice.ts +31 -0
  153. package/src/types/store/shipping.ts +84 -3
  154. package/src/types/ui/index.ts +1 -1
  155. package/src/utils/checkout.ts +19 -3
  156. package/src/utils/cookieConsent.ts +34 -0
  157. package/src/utils/format.ts +408 -0
  158. package/src/utils/geolocation.ts +134 -0
  159. package/src/utils/graphql-url.ts +47 -0
  160. package/src/utils/guest-session.ts +59 -0
  161. package/src/utils/http-client.ts +147 -0
  162. package/src/utils/index.ts +11 -4
  163. package/src/utils/status-colors.ts +79 -0
  164. package/src/utils/token-refresh.ts +115 -0
  165. package/src/utils/validators.ts +13 -0
  166. package/src/utils/youtube.ts +18 -0
  167. package/dist/index-C5YO9gTl.d.mts +0 -507
  168. package/dist/index-C5YO9gTl.d.ts +0 -507
  169. package/dist/index-CefG7_xq.d.mts +0 -793
  170. package/dist/index-DeHCf3zI.d.ts +0 -793
  171. package/src/graphql/collections.graphql.ts +0 -48
  172. package/src/graphql/index.ts +0 -7
  173. package/src/graphql/products.graphql.ts +0 -860
  174. package/src/graphql/wishlist.graphql.ts +0 -34
  175. package/src/hooks/use-consultation-stream.ts +0 -142
  176. package/src/types/bespoke/index.ts +0 -39
@@ -20,55 +20,74 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/services/index.ts
21
21
  var services_exports = {};
22
22
  __export(services_exports, {
23
- acceptQuote: () => acceptQuote,
24
23
  addToCart: () => addToCart,
25
24
  addToGuestCart: () => addToGuestCart,
26
25
  addToWishlist: () => addToWishlist,
27
- approveDeliverable: () => approveDeliverable,
26
+ approveBespokeDeliverable: () => approveBespokeDeliverable,
27
+ approveMilestone: () => approveMilestone,
28
+ autocompleteAddress: () => autocompleteAddress,
28
29
  bespokeService: () => bespokeService,
29
30
  bookAppointment: () => bookAppointment,
30
31
  cancelAppointment: () => cancelAppointment,
31
32
  cancelOrder: () => cancelOrder,
33
+ changePassword: () => changePassword,
32
34
  checkAvailability: () => checkAvailability,
33
35
  checkInWishlist: () => checkInWishlist,
36
+ claimWalletCredit: () => claimWalletCredit,
34
37
  clearCart: () => clearCart,
35
38
  clearGuestCart: () => clearGuestCart,
36
39
  clearTokens: () => clearTokens,
37
40
  configService: () => configService,
38
- consultationService: () => consultationService,
41
+ confirmAppointmentCompletion: () => confirmAppointmentCompletion,
42
+ confirmMediaUpload: () => confirmMediaUpload,
43
+ createBespokeOrder: () => createBespokeOrder,
39
44
  createCmsEntry: () => createCmsEntry,
45
+ createComment: () => createComment,
40
46
  createConsultation: () => createConsultation,
47
+ createCustomerAddress: () => createCustomerAddress,
41
48
  createDedicatedAccount: () => createDedicatedAccount,
49
+ createFeedback: () => createFeedback,
42
50
  createOrder: () => createOrder,
51
+ createReview: () => createReview,
52
+ createServiceBookingOrder: () => createServiceBookingOrder,
53
+ deactivateCustomerAccount: () => deactivateCustomerAccount,
54
+ decodePlusCode: () => decodePlusCode,
43
55
  deleteCmsEntry: () => deleteCmsEntry,
56
+ deleteCustomerAddress: () => deleteCustomerAddress,
57
+ disputeAppointment: () => disputeAppointment,
44
58
  findOrder: () => findOrder,
45
- findOrderByToken: () => findOrderByToken,
59
+ forgotPasswordCustomer: () => forgotPasswordCustomer,
46
60
  getAppointment: () => getAppointment,
47
61
  getAppointments: () => getAppointments,
48
62
  getAuthUser: () => getAuthUser,
63
+ getAvailablePaymentMethods: () => getAvailablePaymentMethods,
49
64
  getAvailableSlots: () => getAvailableSlots,
50
65
  getBusinessConfig: () => getBusinessConfig,
51
66
  getCart: () => getCart,
52
67
  getCmsEntry: () => getCmsEntry,
53
- getConsultation: () => getConsultation,
54
- getConsultations: () => getConsultations,
55
- getDeliverables: () => getDeliverables,
68
+ getCustomerAddresses: () => getCustomerAddresses,
56
69
  getFeaturedProducts: () => getFeaturedProducts,
57
70
  getGuestCart: () => getGuestCart,
58
- getGuestCartCount: () => getGuestCartCount,
59
71
  getGuestCartProductType: () => getGuestCartProductType,
60
- getGuestCartSubtotal: () => getGuestCartSubtotal,
61
- getLatestProducts: () => getLatestProducts,
62
- getLowStockProducts: () => getLowStockProducts,
63
72
  getMe: () => getMe,
73
+ getMerchantLegalDocument: () => getMerchantLegalDocument,
74
+ getMilestones: () => getMilestones,
75
+ getMyFeedback: () => getMyFeedback,
64
76
  getNewProducts: () => getNewProducts,
77
+ getNotificationInbox: () => getNotificationInbox,
78
+ getNotificationPreferences: () => getNotificationPreferences,
65
79
  getOnSaleProducts: () => getOnSaleProducts,
66
80
  getOrders: () => getOrders,
81
+ getPendingComments: () => getPendingComments,
82
+ getPendingReviews: () => getPendingReviews,
67
83
  getPopularProducts: () => getPopularProducts,
84
+ getPresignedUploadUrl: () => getPresignedUploadUrl,
85
+ getProductComments: () => getProductComments,
86
+ getProductReviews: () => getProductReviews,
68
87
  getRecommendedProducts: () => getRecommendedProducts,
69
- getSellerShippingAddress: () => getSellerShippingAddress,
70
88
  getShippingRates: () => getShippingRates,
71
89
  getStoredTokens: () => getStoredTokens,
90
+ getStorefrontBusinessInfo: () => getStorefrontBusinessInfo,
72
91
  getStorefrontCollectionBySlug: () => getStorefrontCollectionBySlug,
73
92
  getStorefrontCollections: () => getStorefrontCollections,
74
93
  getStorefrontProductBySlug: () => getStorefrontProductBySlug,
@@ -76,44 +95,167 @@ __export(services_exports, {
76
95
  getSupportedCurrencies: () => getSupportedCurrencies,
77
96
  getSupportedLanguages: () => getSupportedLanguages,
78
97
  getTransactionStatus: () => getTransactionStatus,
98
+ getVapidPublicKey: () => getVapidPublicKey,
99
+ getWalletBalance: () => getWalletBalance,
100
+ getWalletLedger: () => getWalletLedger,
79
101
  getWishlist: () => getWishlist,
80
102
  googleTranslate: () => googleTranslate,
81
103
  initiatePayment: () => initiatePayment,
104
+ listBusinessLocations: () => listBusinessLocations,
82
105
  listCmsEntries: () => listCmsEntries,
106
+ listPickupLocations: () => listPickupLocations,
83
107
  loginCustomer: () => loginCustomer,
84
108
  logisticsService: () => logisticsService,
85
109
  logout: () => logout,
86
110
  mapAuthUserToCustomer: () => mapAuthUserToCustomer,
111
+ markAllNotificationsRead: () => markAllNotificationsRead,
112
+ markNotificationRead: () => markNotificationRead,
113
+ merchantReplyToReview: () => merchantReplyToReview,
87
114
  mergeGuestCart: () => mergeGuestCart,
88
115
  mergeGuestCartIfPresent: () => mergeGuestCartIfPresent,
116
+ moderateComment: () => moderateComment,
117
+ moderateReview: () => moderateReview,
89
118
  notificationsService: () => notificationsService,
90
119
  paymentService: () => paymentService,
91
120
  refreshToken: () => refreshToken,
92
121
  registerCustomer: () => registerCustomer,
93
- rejectQuote: () => rejectQuote,
94
122
  removeFromCart: () => removeFromCart,
95
123
  removeFromGuestCart: () => removeFromGuestCart,
96
124
  removeFromWishlist: () => removeFromWishlist,
97
125
  removeProductFromWishlist: () => removeProductFromWishlist,
98
- requestQuote: () => requestQuote,
99
- requestRevision: () => requestRevision,
126
+ requestBespokeRevision: () => requestBespokeRevision,
127
+ requestCustomerOtp: () => requestCustomerOtp,
128
+ requestCustomerReactivation: () => requestCustomerReactivation,
129
+ rescheduleAppointment: () => rescheduleAppointment,
130
+ resetPasswordCustomer: () => resetPasswordCustomer,
131
+ resolveDigitalDownload: () => resolveDigitalDownload,
132
+ resolveDigitalDownloadFile: () => resolveDigitalDownloadFile,
133
+ reverseGeocode: () => reverseGeocode,
100
134
  sendContactConfirmation: () => sendContactConfirmation,
101
135
  sendContactEmail: () => sendContactEmail,
102
- sendMessage: () => sendMessage,
103
136
  serviceBookingService: () => serviceBookingService,
104
137
  silentRefresh: () => silentRefresh,
105
138
  storeTokens: () => storeTokens,
139
+ subscribeToPush: () => subscribeToPush,
140
+ trackNotificationClick: () => trackNotificationClick,
106
141
  trackOrder: () => trackOrder,
142
+ unsubscribeFromPush: () => unsubscribeFromPush,
107
143
  updateCartItem: () => updateCartItem,
108
144
  updateCmsEntry: () => updateCmsEntry,
145
+ updateComment: () => updateComment,
146
+ updateCustomerAddress: () => updateCustomerAddress,
109
147
  updateGuestCartItemQuantity: () => updateGuestCartItemQuantity,
148
+ updateNotificationPreferences: () => updateNotificationPreferences,
110
149
  updateProfile: () => updateProfile,
150
+ updateReview: () => updateReview,
151
+ uploadMediaFile: () => uploadMediaFile,
152
+ uploadMediaFiles: () => uploadMediaFiles,
153
+ validatePromoCode: () => validatePromoCode,
111
154
  validateShippingAddress: () => validateShippingAddress,
155
+ verifyCustomerOtp: () => verifyCustomerOtp,
156
+ verifyCustomerReactivation: () => verifyCustomerReactivation,
112
157
  verifySocialToken: () => verifySocialToken,
113
158
  verifyTransaction: () => verifyTransaction
114
159
  });
115
160
  module.exports = __toCommonJS(services_exports);
116
161
 
162
+ // src/utils/token-refresh.ts
163
+ var GLOBAL_KEY = "__kasuviaSdkTokenRefreshRegistry__";
164
+ function getRegistry() {
165
+ const g = globalThis;
166
+ if (!g[GLOBAL_KEY]) {
167
+ g[GLOBAL_KEY] = { handler: null, inFlight: null };
168
+ }
169
+ return g[GLOBAL_KEY];
170
+ }
171
+ async function refreshAccessToken() {
172
+ const registry = getRegistry();
173
+ if (!registry.handler) return null;
174
+ if (registry.inFlight) return registry.inFlight;
175
+ registry.inFlight = registry.handler().finally(() => {
176
+ registry.inFlight = null;
177
+ });
178
+ return registry.inFlight;
179
+ }
180
+ function hasRefreshHandler() {
181
+ return getRegistry().handler !== null;
182
+ }
183
+
184
+ // src/utils/http-client.ts
185
+ var ApiError = class extends Error {
186
+ constructor(message, status, body) {
187
+ super(message);
188
+ this.name = "ApiError";
189
+ this.status = status;
190
+ this.body = body;
191
+ }
192
+ };
193
+ function extractApiErrorMessage(body, fallback) {
194
+ if (typeof body !== "object" || body === null) return fallback;
195
+ const record = body;
196
+ if (typeof record.detail === "string") return record.detail;
197
+ if (Array.isArray(record.detail) && record.detail.length > 0) {
198
+ const first = record.detail[0];
199
+ if (first && typeof first.msg === "string") {
200
+ const loc = first.loc;
201
+ const field = Array.isArray(loc) ? loc[loc.length - 1] : void 0;
202
+ return typeof field === "string" || typeof field === "number" ? `${field}: ${first.msg}` : first.msg;
203
+ }
204
+ }
205
+ const firstStringOrArrayItem = (value) => {
206
+ if (typeof value === "string") return value;
207
+ if (Array.isArray(value) && typeof value[0] === "string") return value[0];
208
+ return void 0;
209
+ };
210
+ const nonFieldMessage = firstStringOrArrayItem(record.non_field_errors);
211
+ if (nonFieldMessage) return nonFieldMessage;
212
+ for (const [key, value] of Object.entries(record)) {
213
+ if (key === "detail" || key === "non_field_errors") continue;
214
+ const message = firstStringOrArrayItem(value);
215
+ if (message) return message;
216
+ }
217
+ return fallback;
218
+ }
219
+ function storefrontHeaders(config) {
220
+ return {
221
+ "X-Storefront-Key": config.storefrontApiKey,
222
+ "X-Business-ID": config.businessId
223
+ };
224
+ }
225
+ function authHeaders(config, accessToken) {
226
+ return {
227
+ ...storefrontHeaders(config),
228
+ Authorization: `Bearer ${accessToken}`
229
+ };
230
+ }
231
+ var JSON_HEADERS = { "Content-Type": "application/json" };
232
+ async function apiRequest(url, options = {}) {
233
+ const { fallbackErrorMessage = "Request failed", ...init } = options;
234
+ const headers = new Headers(init.headers);
235
+ const hadBearerToken = headers.get("Authorization")?.startsWith("Bearer ") ?? false;
236
+ const response = await fetch(url, { ...init, headers });
237
+ if (response.status === 401 && hadBearerToken && hasRefreshHandler()) {
238
+ const freshToken = await refreshAccessToken();
239
+ if (freshToken) {
240
+ const retryHeaders = new Headers(headers);
241
+ retryHeaders.set("Authorization", `Bearer ${freshToken}`);
242
+ const retryResponse = await fetch(url, { ...init, headers: retryHeaders });
243
+ if (retryResponse.ok) {
244
+ const retryText = await retryResponse.text();
245
+ return retryText ? JSON.parse(retryText) : void 0;
246
+ }
247
+ const retryBody = await retryResponse.json().catch(() => ({}));
248
+ throw new ApiError(extractApiErrorMessage(retryBody, fallbackErrorMessage), retryResponse.status, retryBody);
249
+ }
250
+ }
251
+ if (!response.ok) {
252
+ const body = await response.json().catch(() => ({}));
253
+ throw new ApiError(extractApiErrorMessage(body, fallbackErrorMessage), response.status, body);
254
+ }
255
+ const text = await response.text();
256
+ return text ? JSON.parse(text) : void 0;
257
+ }
258
+
117
259
  // src/services/cart.service.ts
118
260
  function parseItems(items) {
119
261
  return items.map((item) => ({
@@ -121,218 +263,148 @@ function parseItems(items) {
121
263
  variant_attributes: item.variant_attributes && typeof item.variant_attributes === "string" ? JSON.parse(item.variant_attributes) : item.variant_attributes
122
264
  }));
123
265
  }
266
+ function guestHeaders(config, guestSessionId, extra) {
267
+ return { ...extra, ...storefrontHeaders(config), "X-Guest-Session": guestSessionId };
268
+ }
124
269
  async function getGuestCart(config, guestSessionId) {
125
- if (!guestSessionId) return [];
126
- try {
127
- const response = await fetch(`${config.backendUrls.store}/cart/`, {
128
- headers: {
129
- "X-Storefront-Key": config.storefrontApiKey,
130
- "X-Business-ID": config.businessId,
131
- "X-Guest-Session": guestSessionId
132
- }
133
- });
134
- if (!response.ok) return [];
135
- const data = await response.json();
136
- return parseItems(data.items || []);
137
- } catch {
138
- return [];
139
- }
270
+ if (!guestSessionId) throw new Error("Guest session ID is required to fetch guest cart");
271
+ const data = await apiRequest(`${config.backendUrls.cart}/cart/`, {
272
+ headers: guestHeaders(config, guestSessionId),
273
+ fallbackErrorMessage: "Failed to fetch guest cart"
274
+ });
275
+ return { ...data, items: parseItems(data.items || []) };
140
276
  }
141
277
  async function addToGuestCart(config, guestSessionId, item) {
142
- if (!guestSessionId) return [];
278
+ if (!guestSessionId) throw new Error("Guest session ID is required to add to guest cart");
143
279
  const payload = {
144
280
  product_id: item.product_id,
145
- product_slug: item.product_slug,
146
- product_name: item.product_name,
147
- image: item.image,
148
- variant_id: item.variant_id,
149
- variant_attributes: typeof item.variant_attributes === "string" ? item.variant_attributes : JSON.stringify(item.variant_attributes),
150
- unit_price: item.unit_price,
281
+ variant_id: item.variant_id ?? void 0,
151
282
  quantity: item.quantity,
152
- custom_measurements: item.custom_measurements,
153
- is_bespoke: item.is_bespoke
283
+ custom_measurements: item.custom_measurements ?? void 0
154
284
  };
155
- const response = await fetch(`${config.backendUrls.store}/cart/`, {
285
+ const data = await apiRequest(`${config.backendUrls.cart}/cart/`, {
156
286
  method: "POST",
157
- headers: {
158
- "Content-Type": "application/json",
159
- "X-Storefront-Key": config.storefrontApiKey,
160
- "X-Business-ID": config.businessId,
161
- "X-Guest-Session": guestSessionId
162
- },
163
- body: JSON.stringify(payload)
164
- });
165
- if (!response.ok) return [];
166
- const data = await response.json();
167
- return parseItems(data.items || []);
287
+ headers: guestHeaders(config, guestSessionId, JSON_HEADERS),
288
+ body: JSON.stringify(payload),
289
+ fallbackErrorMessage: "Failed to add to guest cart"
290
+ });
291
+ return { ...data, items: parseItems(data.items || []) };
168
292
  }
169
293
  async function updateGuestCartItemQuantity(config, guestSessionId, itemId, quantity) {
170
- if (!guestSessionId) return [];
171
- const response = await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
294
+ if (!guestSessionId) throw new Error("Guest session ID is required to update guest cart item");
295
+ const data = await apiRequest(`${config.backendUrls.cart}/cart/${itemId}`, {
172
296
  method: "PATCH",
173
- headers: {
174
- "Content-Type": "application/json",
175
- "X-Storefront-Key": config.storefrontApiKey,
176
- "X-Business-ID": config.businessId,
177
- "X-Guest-Session": guestSessionId
178
- },
179
- body: JSON.stringify({ quantity })
180
- });
181
- if (!response.ok) return [];
182
- const data = await response.json();
183
- return parseItems(data.items || []);
297
+ headers: guestHeaders(config, guestSessionId, JSON_HEADERS),
298
+ body: JSON.stringify({ quantity }),
299
+ fallbackErrorMessage: "Failed to update guest cart item"
300
+ });
301
+ return { ...data, items: parseItems(data.items || []) };
184
302
  }
185
303
  async function removeFromGuestCart(config, guestSessionId, itemId) {
186
- if (!guestSessionId) return [];
187
- await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
304
+ if (!guestSessionId) throw new Error("Guest session ID is required to remove from guest cart");
305
+ await apiRequest(`${config.backendUrls.cart}/cart/${itemId}`, {
188
306
  method: "DELETE",
189
- headers: {
190
- "X-Storefront-Key": config.storefrontApiKey,
191
- "X-Business-ID": config.businessId,
192
- "X-Guest-Session": guestSessionId
193
- }
307
+ headers: guestHeaders(config, guestSessionId),
308
+ fallbackErrorMessage: "Failed to remove item from guest cart"
194
309
  });
195
- return getGuestCart(config, guestSessionId);
196
310
  }
197
311
  async function clearGuestCart(config, guestSessionId) {
198
- if (!guestSessionId) return;
199
- await fetch(`${config.backendUrls.store}/cart/clear`, {
312
+ if (!guestSessionId) throw new Error("Guest session ID is required to clear guest cart");
313
+ await apiRequest(`${config.backendUrls.cart}/cart/clear`, {
200
314
  method: "DELETE",
201
- headers: {
202
- "X-Storefront-Key": config.storefrontApiKey,
203
- "X-Business-ID": config.businessId,
204
- "X-Guest-Session": guestSessionId
205
- }
315
+ headers: guestHeaders(config, guestSessionId),
316
+ fallbackErrorMessage: "Failed to clear guest cart"
206
317
  });
207
318
  }
208
319
  async function getCart(config, accessToken) {
209
320
  if (!accessToken) {
210
- return { id: "", items: [], subtotal: 0, total: 0, product_type: "physical" };
321
+ throw new Error("Access token is required to fetch authenticated cart");
211
322
  }
212
- const response = await fetch(`${config.backendUrls.store}/cart/`, {
213
- headers: {
214
- "Authorization": `Bearer ${accessToken}`,
215
- "X-Storefront-Key": config.storefrontApiKey,
216
- "X-Business-ID": config.businessId
217
- }
323
+ const data = await apiRequest(`${config.backendUrls.cart}/cart/`, {
324
+ headers: authHeaders(config, accessToken),
325
+ fallbackErrorMessage: "Failed to fetch cart"
218
326
  });
219
- if (!response.ok) throw new Error("Failed to fetch cart");
220
- const data = await response.json();
221
- const parsedItems = parseItems(data.items || []);
222
- return { ...data, items: parsedItems };
327
+ return { ...data, items: parseItems(data.items || []) };
223
328
  }
224
329
  async function addToCart(config, accessToken, item) {
225
- const response = await fetch(`${config.backendUrls.store}/cart/`, {
330
+ const payload = {
331
+ product_id: item.product_id,
332
+ variant_id: item.variant_id ?? void 0,
333
+ quantity: item.quantity,
334
+ custom_measurements: item.custom_measurements ?? void 0
335
+ };
336
+ const data = await apiRequest(`${config.backendUrls.cart}/cart/`, {
226
337
  method: "POST",
227
- headers: {
228
- "Content-Type": "application/json",
229
- "Authorization": `Bearer ${accessToken}`,
230
- "X-Storefront-Key": config.storefrontApiKey,
231
- "X-Business-ID": config.businessId
232
- },
233
- body: JSON.stringify(item)
234
- });
235
- if (!response.ok) throw new Error("Failed to add to cart");
236
- const data = await response.json();
237
- const parsedItems = parseItems(data.items || []);
238
- return { ...data, items: parsedItems };
338
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
339
+ body: JSON.stringify(payload),
340
+ fallbackErrorMessage: "Failed to add to cart"
341
+ });
342
+ return { ...data, items: parseItems(data.items || []) };
239
343
  }
240
344
  async function updateCartItem(config, accessToken, itemId, quantity) {
241
- const response = await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
345
+ const data = await apiRequest(`${config.backendUrls.cart}/cart/${itemId}`, {
242
346
  method: "PATCH",
243
- headers: {
244
- "Content-Type": "application/json",
245
- "Authorization": `Bearer ${accessToken}`,
246
- "X-Storefront-Key": config.storefrontApiKey,
247
- "X-Business-ID": config.businessId
248
- },
249
- body: JSON.stringify({ quantity })
250
- });
251
- if (!response.ok) throw new Error("Failed to update cart item");
252
- const data = await response.json();
253
- const parsedItems = parseItems(data.items || []);
254
- return { ...data, items: parsedItems };
347
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
348
+ body: JSON.stringify({ quantity }),
349
+ fallbackErrorMessage: "Failed to update cart item"
350
+ });
351
+ return { ...data, items: parseItems(data.items || []) };
255
352
  }
256
353
  async function removeFromCart(config, accessToken, itemId) {
257
- await fetch(`${config.backendUrls.store}/cart/${itemId}`, {
354
+ await apiRequest(`${config.backendUrls.cart}/cart/${itemId}`, {
258
355
  method: "DELETE",
259
- headers: {
260
- "Authorization": `Bearer ${accessToken}`,
261
- "X-Storefront-Key": config.storefrontApiKey,
262
- "X-Business-ID": config.businessId
263
- }
356
+ headers: authHeaders(config, accessToken),
357
+ fallbackErrorMessage: "Failed to remove cart item"
264
358
  });
265
- return getCart(config, accessToken);
266
359
  }
267
360
  async function clearCart(config, accessToken) {
268
- await fetch(`${config.backendUrls.store}/cart/clear`, {
361
+ await apiRequest(`${config.backendUrls.cart}/cart/clear`, {
269
362
  method: "DELETE",
270
- headers: {
271
- "Authorization": `Bearer ${accessToken}`,
272
- "X-Storefront-Key": config.storefrontApiKey,
273
- "X-Business-ID": config.businessId
274
- }
363
+ headers: authHeaders(config, accessToken),
364
+ fallbackErrorMessage: "Failed to clear cart"
275
365
  });
276
366
  }
277
- async function mergeGuestCart(config, accessToken, guestSessionId) {
278
- const guestItems = guestSessionId ? await getGuestCart(config, guestSessionId) : [];
279
- if (guestItems.length === 0) {
280
- return getCart(config, accessToken);
281
- }
367
+ async function mergeGuestCart(config, accessToken, guestSessionId, guestItems) {
282
368
  const payloadItems = guestItems.map((item) => ({
283
369
  product_id: item.product_id,
284
- product_slug: item.product_slug,
285
- product_name: item.product_name,
286
- image: item.image,
287
- variant_id: item.variant_id,
288
- variant_attributes: typeof item.variant_attributes === "string" ? item.variant_attributes : JSON.stringify(item.variant_attributes ?? {}),
289
- unit_price: item.unit_price,
370
+ variant_id: item.variant_id ?? void 0,
290
371
  quantity: item.quantity,
291
- custom_measurements: typeof item.custom_measurements === "string" ? item.custom_measurements : JSON.stringify(item.custom_measurements ?? {}),
292
- is_bespoke: item.is_bespoke
372
+ custom_measurements: item.custom_measurements ?? void 0
293
373
  }));
294
- const headers = {
295
- "Content-Type": "application/json",
296
- "Authorization": `Bearer ${accessToken}`,
297
- "X-Storefront-Key": config.storefrontApiKey,
298
- "X-Business-ID": config.businessId
299
- };
374
+ const headers = { ...JSON_HEADERS, ...authHeaders(config, accessToken) };
300
375
  if (guestSessionId) {
301
376
  headers["X-Guest-Session"] = guestSessionId;
302
377
  }
303
- const response = await fetch(`${config.backendUrls.store}/cart/merge`, {
378
+ const data = await apiRequest(`${config.backendUrls.cart}/cart/merge`, {
304
379
  method: "POST",
305
380
  headers,
306
- body: JSON.stringify({ items: payloadItems })
381
+ body: JSON.stringify({ items: payloadItems }),
382
+ fallbackErrorMessage: "Failed to merge guest cart"
307
383
  });
308
- if (!response.ok) throw new Error("Failed to merge guest cart");
309
- const data = await response.json();
310
384
  return { ...data, items: parseItems(data.items || []) };
311
385
  }
312
386
  async function mergeGuestCartIfPresent(config, accessToken, guestSessionId) {
313
- try {
314
- const guestItems = await getGuestCart(config, guestSessionId);
315
- if (guestItems.length === 0) return;
316
- await mergeGuestCart(config, accessToken, guestSessionId);
317
- } catch (error) {
318
- console.warn("[Cart] Failed to merge guest cart:", error);
319
- }
320
- }
321
- function getGuestCartCount() {
322
- return 0;
387
+ const guestCart = await getGuestCart(config, guestSessionId);
388
+ if (!guestCart.items.length) return;
389
+ await mergeGuestCart(config, accessToken, guestSessionId, guestCart.items);
323
390
  }
324
- function getGuestCartSubtotal() {
325
- return 0;
326
- }
327
- function getGuestCartProductType() {
328
- return "physical";
391
+ function getGuestCartProductType(items) {
392
+ if (!items || !items.length) return null;
393
+ const types = new Set(items.map((i) => i.product_type).filter(Boolean));
394
+ if (types.size === 0) return null;
395
+ if (types.size === 1) return [...types][0] ?? null;
396
+ return "physical" /* PHYSICAL */;
329
397
  }
330
398
 
331
399
  // src/services/order.service.ts
400
+ function extractShippingAddress(raw) {
401
+ const val = raw.physical_fulfillment?.shipping_address;
402
+ return typeof val === "object" && val !== null ? val : null;
403
+ }
332
404
  function deriveCustomerName(raw) {
333
405
  if (raw.customer_name) return raw.customer_name;
334
406
  if (raw.guest_name) return raw.guest_name;
335
- const addr = typeof raw.shipping_address === "object" && raw.shipping_address !== null ? raw.shipping_address : null;
407
+ const addr = extractShippingAddress(raw);
336
408
  if (addr) {
337
409
  const full = `${addr.first_name ?? ""} ${addr.last_name ?? ""}`.trim();
338
410
  if (full) return full;
@@ -344,25 +416,123 @@ function deriveCustomerName(raw) {
344
416
  function normaliseStorefrontOrder(raw) {
345
417
  const items = (raw.items ?? []).map((item) => ({
346
418
  id: item.id,
347
- productName: item.product_name ?? item.productName ?? "",
348
- image: item.image ?? "",
349
- quantity: item.quantity ?? 1,
350
- price: item.unit_price ?? item.price ?? 0
419
+ order_id: item.order_id,
420
+ product_id: item.product_id ?? void 0,
421
+ variant_id: item.variant_id ?? void 0,
422
+ product_name: item.product_name ?? "",
423
+ quantity: item.quantity,
424
+ unit_price: item.unit_price,
425
+ variant_details: item.variant_details,
426
+ custom_measurements: item.custom_measurements,
427
+ image_url: item.image_url ?? void 0
351
428
  }));
352
- const addr = typeof raw.shipping_address === "object" && raw.shipping_address !== null ? raw.shipping_address : null;
429
+ const addr = extractShippingAddress(raw);
430
+ const customerName = deriveCustomerName(raw);
431
+ const customerEmail = raw.guest_email ?? raw.customer_email ?? "";
432
+ const physical = raw.physical_fulfillment;
433
+ if (!raw.currency) {
434
+ throw new Error(`Order ${raw.id} response is missing a currency field.`);
435
+ }
436
+ if (!raw.created_at) {
437
+ throw new Error(`Order ${raw.id} response is missing a created_at field.`);
438
+ }
439
+ if (!raw.updated_at) {
440
+ throw new Error(`Order ${raw.id} response is missing an updated_at field.`);
441
+ }
442
+ if (!raw.business_id) {
443
+ throw new Error(`Order ${raw.id} response is missing a business_id field.`);
444
+ }
353
445
  return {
354
446
  id: raw.id,
355
- display_id: raw.display_id,
447
+ display_id: raw.display_id || raw.id,
448
+ business_id: raw.business_id,
449
+ customer_id: raw.customer_id ?? void 0,
356
450
  items,
357
- total: raw.total_amount ?? raw.total ?? 0,
358
451
  status: raw.status,
359
- customerEmail: raw.guest_email ?? raw.customer_email ?? "",
360
- customerName: deriveCustomerName(raw),
361
- createdAt: raw.created_at ? new Date(raw.created_at).getTime() : Date.now(),
362
- updatedAt: raw.updated_at ? new Date(raw.updated_at).getTime() : Date.now(),
363
- deliveryMethod: raw.delivery_method,
364
- trackingNumber: raw.tracking_number,
365
- deliveryAddress: typeof raw.shipping_address === "string" ? raw.shipping_address : addr ? `${addr.street}, ${addr.city}, ${addr.state}, ${addr.country}` : void 0,
452
+ payment_status: raw.payment_status || "pending",
453
+ product_type: raw.product_type ?? void 0,
454
+ // Canonical backend fields
455
+ total_amount: raw.total_amount,
456
+ currency: raw.currency,
457
+ subtotal_amount: raw.subtotal_amount ?? void 0,
458
+ shipping_amount: raw.shipping_amount ?? void 0,
459
+ discount_amount: raw.discount_amount ?? void 0,
460
+ tax_amount: raw.tax_amount ?? void 0,
461
+ customer_name: customerName,
462
+ customer_email: customerEmail,
463
+ // REAL BUG FIXED (2026-09-23) via the REST codegen initiative: every
464
+ // field below this point used to read a flat `raw.<field>` that does
465
+ // NOT exist anywhere on the real OrderResponse - confirmed by reading
466
+ // the actual Pydantic classes, not just the generated types. They
467
+ // genuinely live nested under `physical_fulfillment` (shipping/
468
+ // tracking/carrier/pickup/surcharge/weight) or `digital_fulfillment`
469
+ // (buyer_country) - "One nested block per product type, instead of
470
+ // ~35 flat fields on OrderBase" per that schema file's own Order
471
+ // Schema Refactor comment. Every one of these was silently `undefined`
472
+ // on every real order: a customer's tracking number, carrier, delivery
473
+ // status, and shipping address never actually rendered anywhere on the
474
+ // storefront's order tracking page.
475
+ tracking_number: physical?.tracking_number ?? void 0,
476
+ delivery_status: physical?.delivery_status ?? void 0,
477
+ carrier_name: physical?.carrier_name ?? void 0,
478
+ carrier_slug: physical?.carrier_slug ?? void 0,
479
+ terminal_rate_id: physical?.terminal_rate_id ?? void 0,
480
+ guest_token: raw.guest_token ?? void 0,
481
+ guest_email: raw.guest_email ?? void 0,
482
+ guest_phone: raw.guest_phone ?? void 0,
483
+ guest_name: raw.guest_name ?? void 0,
484
+ buyer_country: raw.digital_fulfillment?.buyer_country ?? void 0,
485
+ created_at: raw.created_at,
486
+ updated_at: raw.updated_at,
487
+ // Weight discrepancy & surcharge fields (Task 2) — physical_fulfillment
488
+ shipping_surcharge_amount: physical?.shipping_surcharge_amount ?? void 0,
489
+ shipping_surcharge_reason: physical?.shipping_surcharge_reason ?? void 0,
490
+ shipping_surcharge_description: physical?.shipping_surcharge_description ?? void 0,
491
+ shipping_surcharge_applied_at: physical?.shipping_surcharge_applied_at ?? void 0,
492
+ declared_weight_kg: physical?.declared_weight_kg ?? void 0,
493
+ actual_weight_kg: physical?.actual_weight_kg ?? void 0,
494
+ // Self-pickup verification fields (Task 3) — physical_fulfillment
495
+ pickup_verification_code: physical?.pickup_verification_code ?? void 0,
496
+ pickup_verification_code_generated_at: physical?.pickup_verification_code_generated_at ?? void 0,
497
+ pickup_verification_code_used_at: physical?.pickup_verification_code_used_at ?? void 0,
498
+ pickup_verification_failed_attempts: physical?.pickup_verification_failed_attempts,
499
+ pickup_verification_locked_until: physical?.pickup_verification_locked_until ?? void 0,
500
+ pickup_qr_payload: physical?.pickup_qr_payload ?? void 0,
501
+ // Bespoke fields — real backend nests these under `bespoke_fulfillment`.
502
+ bespoke_brief: raw.bespoke_fulfillment?.brief ?? void 0,
503
+ bespoke_reference_images: raw.bespoke_fulfillment?.reference_images ?? void 0,
504
+ bespoke_measurements: raw.bespoke_fulfillment?.measurements ?? void 0,
505
+ bespoke_preferred_timeline: raw.bespoke_fulfillment?.preferred_timeline ?? void 0,
506
+ bespoke_special_instructions: raw.bespoke_fulfillment?.special_instructions ?? void 0,
507
+ bespoke_deposit_ratio: raw.bespoke_fulfillment?.deposit_ratio ?? void 0,
508
+ bespoke_deposit_amount: raw.bespoke_fulfillment?.deposit_amount ?? void 0,
509
+ bespoke_balance_amount: raw.bespoke_fulfillment?.balance_amount ?? void 0,
510
+ bespoke_status: raw.bespoke_fulfillment?.status ?? void 0,
511
+ bespoke_deliverable_submitted_at: raw.bespoke_fulfillment?.deliverable_submitted_at ?? void 0,
512
+ bespoke_deliverable_url: raw.bespoke_fulfillment?.deliverable_url ?? void 0,
513
+ bespoke_deliverable_notes: raw.bespoke_fulfillment?.deliverable_notes ?? void 0,
514
+ bespoke_buyer_approved_at: raw.bespoke_fulfillment?.buyer_approved_at ?? void 0,
515
+ bespoke_revision_count: raw.bespoke_fulfillment?.revision_count ?? 0,
516
+ bespoke_revision_notes: raw.bespoke_fulfillment?.revision_notes ?? void 0,
517
+ // SDK camelCase convenience aliases
518
+ total: raw.total_amount ?? void 0,
519
+ shippingAmount: raw.shipping_amount ?? void 0,
520
+ discountAmount: raw.discount_amount ?? void 0,
521
+ customerEmail,
522
+ customerName,
523
+ createdAt: new Date(raw.created_at).getTime(),
524
+ updatedAt: new Date(raw.updated_at).getTime(),
525
+ // REAL BUG FIXED (2026-09-23), found alongside the nesting bug above:
526
+ // `deliveryMethod` reads physical_fulfillment.shipping_method now
527
+ // (was reading a flat `delivery_method` field that never existed at
528
+ // all, anywhere - not even nested). The real value is "carrier" or
529
+ // "self_pickup" (PhysicalFulfillmentCreate.shipping_method's own
530
+ // docstring) - see the matching fix in kasuvia-storefront's
531
+ // OrderDeliveryInfo.tsx, which used to compare against the wrong
532
+ // string "pickup".
533
+ deliveryMethod: physical?.shipping_method ?? void 0,
534
+ trackingNumber: physical?.tracking_number ?? void 0,
535
+ deliveryAddress: addr ? `${addr.street}, ${addr.city}, ${addr.state}, ${addr.country}` : void 0,
366
536
  shippingAddress: addr ? {
367
537
  first_name: addr.first_name ?? "",
368
538
  last_name: addr.last_name ?? "",
@@ -370,62 +540,85 @@ function normaliseStorefrontOrder(raw) {
370
540
  street: addr.street ?? "",
371
541
  city: addr.city ?? "",
372
542
  state: addr.state ?? "",
373
- lga: addr.lga ?? "",
543
+ lga: addr.lga,
374
544
  country: addr.country ?? "",
375
- postal: addr.postal ?? ""
545
+ postal: addr.postal
376
546
  } : void 0,
377
- cancellationReason: raw.cancellation_reason,
547
+ // REAL GAP (2026-09-23), NOT fixed here: confirmed cancellation_reason
548
+ // does not exist anywhere in OrderResponse or any of its fulfillment
549
+ // sub-schemas (kasuvia-store-management's app/schemas/order.py) - the
550
+ // cancel-order endpoint accepts a `reason` in its request body but the
551
+ // backend never persists/returns it back on the order. Permanently
552
+ // undefined until the backend adds real storage for it; kept as a
553
+ // field on the public Order type rather than silently removed, since
554
+ // deleting a public SDK field is a breaking change this fix's scope
555
+ // doesn't cover.
556
+ cancellationReason: void 0,
378
557
  hasBespoke: raw.product_type === "bespoke",
379
- bespokeStage: raw.bespoke_stage,
380
- bespokeBrief: raw.bespoke_brief,
381
- deliveryStatus: raw.delivery_status,
382
- carrierName: raw.carrier_name,
383
- terminalShipmentId: raw.terminal_shipment_id,
384
- guestToken: raw.guest_token,
385
- guestEmail: raw.guest_email,
386
- guestPhone: raw.guest_phone,
387
- guestName: raw.guest_name
558
+ // REAL GAP (2026-09-23), NOT fixed here: same as cancellationReason -
559
+ // confirmed no `bespoke_stage` field exists anywhere; the real,
560
+ // equivalent concept is bespoke_fulfillment.status (already exposed
561
+ // above as `bespoke_status`). Reads that here rather than staying
562
+ // permanently undefined, since it's genuinely the same real data the
563
+ // consuming components (BespokeProgress) want to key off of.
564
+ bespokeStage: raw.bespoke_fulfillment?.status ?? void 0,
565
+ bespokeBrief: raw.bespoke_fulfillment?.brief ?? void 0,
566
+ deliveryStatus: physical?.delivery_status ?? void 0,
567
+ carrierName: physical?.carrier_name ?? void 0,
568
+ terminalShipmentId: physical?.terminal_shipment_id ?? void 0,
569
+ guestToken: raw.guest_token ?? void 0,
570
+ guestEmail: raw.guest_email ?? void 0,
571
+ guestPhone: raw.guest_phone ?? void 0,
572
+ guestName: raw.guest_name ?? void 0
388
573
  };
389
574
  }
390
- async function createOrder(config, accessToken, payload) {
391
- const response = await fetch(`${config.backendUrls.store}/orders/storefront`, {
575
+ async function createOrder(config, accessToken, payload, guestSessionId) {
576
+ const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
577
+ if (accessToken) {
578
+ headers["Authorization"] = `Bearer ${accessToken}`;
579
+ } else if (guestSessionId) {
580
+ headers["X-Guest-Session"] = guestSessionId;
581
+ }
582
+ const data = await apiRequest(`${config.backendUrls.store}/orders/storefront`, {
392
583
  method: "POST",
393
- headers: {
394
- "Content-Type": "application/json",
395
- "Authorization": `Bearer ${accessToken}`,
396
- "X-Storefront-Key": config.storefrontApiKey,
397
- "X-Business-ID": config.businessId
398
- },
399
- body: JSON.stringify(payload)
400
- });
401
- if (!response.ok) throw new Error("Failed to create order");
402
- const data = await response.json();
584
+ headers,
585
+ body: JSON.stringify(payload),
586
+ fallbackErrorMessage: "Failed to create order"
587
+ });
403
588
  return normaliseStorefrontOrder(data);
404
589
  }
405
- async function findOrder(config, params) {
406
- const queryParams = new URLSearchParams();
407
- if (params.email) queryParams.set("email", params.email);
408
- if (params.order_id) queryParams.set("order_id", params.order_id);
409
- if (params.guest_token) queryParams.set("guest_token", params.guest_token);
410
- const response = await fetch(`${config.backendUrls.store}/orders/find/?${queryParams.toString()}`, {
411
- headers: {
412
- "X-Storefront-Key": config.storefrontApiKey,
413
- "X-Business-ID": config.businessId
414
- }
590
+ async function createBespokeOrder(config, accessToken, payload) {
591
+ const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
592
+ if (accessToken) headers["Authorization"] = `Bearer ${accessToken}`;
593
+ const data = await apiRequest(`${config.backendUrls.store}/orders/storefront/bespoke`, {
594
+ method: "POST",
595
+ headers,
596
+ body: JSON.stringify(payload),
597
+ fallbackErrorMessage: "Failed to create bespoke order"
415
598
  });
416
- if (!response.ok) throw new Error("Failed to find order");
417
- const data = await response.json();
418
599
  return normaliseStorefrontOrder(data);
419
600
  }
420
- async function findOrderByToken(config, token) {
421
- const response = await fetch(`${config.backendUrls.store}/orders/find/?guest_token=${token}`, {
422
- headers: {
423
- "X-Storefront-Key": config.storefrontApiKey,
424
- "X-Business-ID": config.businessId
425
- }
601
+ async function createServiceBookingOrder(config, accessToken, payload) {
602
+ const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
603
+ if (accessToken) headers["Authorization"] = `Bearer ${accessToken}`;
604
+ const data = await apiRequest(`${config.backendUrls.store}/orders/storefront/service`, {
605
+ method: "POST",
606
+ headers,
607
+ body: JSON.stringify(payload),
608
+ fallbackErrorMessage: "Failed to create service booking order"
609
+ });
610
+ return normaliseStorefrontOrder(data);
611
+ }
612
+ async function findOrder(config, params) {
613
+ if (!params.email || !params.order_id) {
614
+ throw new Error("Both email and order_id are required to find an order.");
615
+ }
616
+ const data = await apiRequest(`${config.backendUrls.store}/orders/track`, {
617
+ method: "POST",
618
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
619
+ body: JSON.stringify({ order_id: params.order_id, email: params.email }),
620
+ fallbackErrorMessage: "Failed to find order"
426
621
  });
427
- if (!response.ok) throw new Error("Failed to find order by token");
428
- const data = await response.json();
429
622
  return normaliseStorefrontOrder(data);
430
623
  }
431
624
  async function getOrders(config, accessToken, params) {
@@ -433,45 +626,110 @@ async function getOrders(config, accessToken, params) {
433
626
  if (params?.email) queryParams.set("email", params.email);
434
627
  if (params?.page) queryParams.set("page", params.page.toString());
435
628
  if (params?.page_size) queryParams.set("page_size", params.page_size.toString());
436
- const response = await fetch(`${config.backendUrls.store}/orders/?${queryParams.toString()}`, {
437
- headers: {
438
- "Authorization": `Bearer ${accessToken}`,
439
- "X-Storefront-Key": config.storefrontApiKey,
440
- "X-Business-ID": config.businessId
441
- }
629
+ const data = await apiRequest(`${config.backendUrls.store}/orders/?${queryParams.toString()}`, {
630
+ headers: authHeaders(config, accessToken),
631
+ fallbackErrorMessage: "Failed to get orders"
442
632
  });
443
- if (!response.ok) throw new Error("Failed to get orders");
444
- const data = await response.json();
445
633
  const items = Array.isArray(data) ? data : data.items ?? [];
446
634
  return items.map(normaliseStorefrontOrder);
447
635
  }
448
636
  async function cancelOrder(config, accessToken, orderId, reason) {
449
- const response = await fetch(`${config.backendUrls.store}/orders/${orderId}/cancel/`, {
637
+ const data = await apiRequest(`${config.backendUrls.store}/orders/${orderId}/cancel/`, {
450
638
  method: "POST",
451
- headers: {
452
- "Content-Type": "application/json",
453
- "Authorization": `Bearer ${accessToken}`,
454
- "X-Storefront-Key": config.storefrontApiKey,
455
- "X-Business-ID": config.businessId
456
- },
457
- body: JSON.stringify({ reason })
458
- });
459
- if (!response.ok) throw new Error("Failed to cancel order");
460
- const data = await response.json();
639
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
640
+ body: JSON.stringify({ reason }),
641
+ fallbackErrorMessage: "Failed to cancel order"
642
+ });
461
643
  return normaliseStorefrontOrder(data);
462
644
  }
463
- async function trackOrder(config, orderId, token) {
464
- const queryParams = token ? `?token=${token}` : "";
465
- const response = await fetch(`${config.backendUrls.store}/orders/track/${orderId}${queryParams}`, {
466
- headers: {
467
- "X-Storefront-Key": config.storefrontApiKey,
468
- "X-Business-ID": config.businessId
469
- }
645
+ async function trackOrder(config, orderId, accessToken) {
646
+ const data = await apiRequest(`${config.backendUrls.store}/orders/${orderId}`, {
647
+ headers: authHeaders(config, accessToken),
648
+ fallbackErrorMessage: "Failed to track order"
470
649
  });
471
- if (!response.ok) throw new Error("Failed to track order");
472
- const data = await response.json();
473
650
  return normaliseStorefrontOrder(data);
474
651
  }
652
+ async function validatePromoCode(config, code, cartTotal) {
653
+ try {
654
+ return await apiRequest(`${config.backendUrls.store}/sales/discounts/validate`, {
655
+ method: "POST",
656
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
657
+ body: JSON.stringify({ code, cart_total: cartTotal }),
658
+ fallbackErrorMessage: "Invalid promo code"
659
+ });
660
+ } catch (err) {
661
+ const message = err instanceof ApiError ? err.message : "Invalid promo code";
662
+ return { valid: false, discount_amount: 0, discount_type: "fixed", message };
663
+ }
664
+ }
665
+ async function resolveRedirectOrJson(url, fallbackErrorMessage) {
666
+ const response = await fetch(url, { redirect: "manual" });
667
+ if (response.status >= 300 && response.status < 400) {
668
+ const location = response.headers.get("location");
669
+ if (!location) {
670
+ throw new Error(`${fallbackErrorMessage}: server redirected with no destination URL.`);
671
+ }
672
+ return { type: "redirect", url: location };
673
+ }
674
+ const body = await response.json().catch(() => ({}));
675
+ if (!response.ok) {
676
+ throw new ApiError(extractDigitalDownloadError(body, fallbackErrorMessage), response.status, body);
677
+ }
678
+ return { type: "json", data: body };
679
+ }
680
+ function extractDigitalDownloadError(body, fallback) {
681
+ if (typeof body === "object" && body !== null && "detail" in body && typeof body.detail === "string") {
682
+ return body.detail;
683
+ }
684
+ return fallback;
685
+ }
686
+ async function resolveDigitalDownload(config, orderId, token) {
687
+ const result = await resolveRedirectOrJson(
688
+ `${config.backendUrls.store}/orders/${orderId}/download/${token}`,
689
+ "Failed to resolve digital download link"
690
+ );
691
+ if (result.type === "redirect") return result;
692
+ return { type: "listing", ...result.data };
693
+ }
694
+ async function resolveDigitalDownloadFile(config, orderId, token, fileId) {
695
+ const result = await resolveRedirectOrJson(
696
+ `${config.backendUrls.store}/orders/${orderId}/download/${token}/${fileId}`,
697
+ "Failed to resolve this file's download link"
698
+ );
699
+ if (result.type !== "redirect") {
700
+ throw new Error("Failed to resolve this file's download link: server did not return a redirect.");
701
+ }
702
+ return result.url;
703
+ }
704
+
705
+ // src/services/consultation.service.ts
706
+ async function createConsultation(config, accessToken, params) {
707
+ return apiRequest(`${config.backendUrls.crm}/consultations/`, {
708
+ method: "POST",
709
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
710
+ body: JSON.stringify(params),
711
+ fallbackErrorMessage: "Failed to submit your request"
712
+ });
713
+ }
714
+
715
+ // src/services/feedback.service.ts
716
+ async function createFeedback(config, accessToken, params) {
717
+ return apiRequest(`${config.backendUrls.crm}/feedback/`, {
718
+ method: "POST",
719
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
720
+ body: JSON.stringify(params),
721
+ fallbackErrorMessage: "Failed to submit your message"
722
+ });
723
+ }
724
+ async function getMyFeedback(config, accessToken, params) {
725
+ const query = new URLSearchParams();
726
+ if (params?.page) query.set("page", String(params.page));
727
+ if (params?.page_size) query.set("page_size", String(params.page_size));
728
+ return apiRequest(`${config.backendUrls.crm}/feedback/my?${query.toString()}`, {
729
+ headers: authHeaders(config, accessToken),
730
+ fallbackErrorMessage: "Failed to load your requests"
731
+ });
732
+ }
475
733
 
476
734
  // src/constants.ts
477
735
  var STORAGE_KEYS = {
@@ -482,88 +740,145 @@ var STORAGE_KEYS = {
482
740
  STOREFRONT_STATE: "storefront_state_v3"
483
741
  };
484
742
 
743
+ // src/utils/customer.ts
744
+ function buildFullName(firstname, lastname) {
745
+ const name = [firstname, lastname].filter(Boolean).join(" ").trim();
746
+ return name || void 0;
747
+ }
748
+ function splitFullName(fullName) {
749
+ if (!fullName?.trim()) return { firstname: "", lastname: "" };
750
+ const parts = fullName.trim().split(/\s+/);
751
+ return {
752
+ firstname: parts[0] ?? "",
753
+ lastname: parts.slice(1).join(" ")
754
+ };
755
+ }
756
+
485
757
  // src/services/auth.service.ts
486
- async function loginCustomer(config, payload) {
487
- const response = await fetch(`${config.backendUrls.auth}/auth/login/customer/`, {
758
+ async function loginCustomer(config, payload, guestSessionId) {
759
+ const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
760
+ if (guestSessionId) {
761
+ headers["X-Guest-Session"] = guestSessionId;
762
+ }
763
+ return apiRequest(`${config.backendUrls.auth}/auth/login/customer/`, {
488
764
  method: "POST",
489
- headers: {
490
- "Content-Type": "application/json",
491
- "X-Storefront-Key": config.storefrontApiKey,
492
- "X-Business-ID": config.businessId
493
- },
494
- body: JSON.stringify({
495
- ...payload,
496
- tenant_id: config.businessId
497
- })
765
+ headers,
766
+ body: JSON.stringify(payload),
767
+ fallbackErrorMessage: "Login failed"
498
768
  });
499
- if (!response.ok) {
500
- throw new Error("Login failed");
501
- }
502
- const data = await response.json();
503
- return data;
504
769
  }
505
- async function registerCustomer(config, payload) {
506
- const response = await fetch(`${config.backendUrls.auth}/auth/register/customer/`, {
770
+ async function registerCustomer(config, payload, guestSessionId) {
771
+ const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
772
+ if (guestSessionId) {
773
+ headers["X-Guest-Session"] = guestSessionId;
774
+ }
775
+ return apiRequest(`${config.backendUrls.auth}/auth/register/customer/`, {
507
776
  method: "POST",
508
- headers: {
509
- "Content-Type": "application/json",
510
- "X-Storefront-Key": config.storefrontApiKey,
511
- "X-Business-ID": config.businessId
512
- },
513
- body: JSON.stringify({
514
- ...payload,
515
- tenant_id: config.businessId
516
- })
777
+ headers,
778
+ body: JSON.stringify(payload),
779
+ fallbackErrorMessage: "Registration failed"
517
780
  });
518
- if (!response.ok) {
519
- throw new Error("Registration failed");
520
- }
521
- const data = await response.json();
522
- return data;
523
781
  }
524
782
  async function refreshToken(config, refresh) {
525
- const response = await fetch(`${config.backendUrls.auth}/auth/token/refresh/`, {
783
+ return apiRequest(`${config.backendUrls.auth}/auth/token/refresh/`, {
526
784
  method: "POST",
527
- headers: {
528
- "Content-Type": "application/json"
529
- },
530
- body: JSON.stringify({ refresh })
785
+ headers: JSON_HEADERS,
786
+ body: JSON.stringify({ refresh }),
787
+ fallbackErrorMessage: "Token refresh failed"
531
788
  });
532
- if (!response.ok) {
533
- throw new Error("Token refresh failed");
534
- }
535
- const data = await response.json();
536
- return data;
537
789
  }
538
790
  async function logout(config, refresh) {
539
791
  const payload = refresh ? { refresh } : {};
540
792
  try {
541
- await fetch(`${config.backendUrls.auth}/auth/logout/`, {
793
+ await apiRequest(`${config.backendUrls.auth}/auth/logout/`, {
542
794
  method: "POST",
543
- headers: {
544
- "Content-Type": "application/json"
545
- },
546
- body: JSON.stringify(payload)
795
+ headers: JSON_HEADERS,
796
+ body: JSON.stringify(payload),
797
+ fallbackErrorMessage: "Server-side logout failed"
547
798
  });
548
- } catch {
799
+ } catch (err) {
800
+ if (err instanceof ApiError) {
801
+ console.error(`[auth.service] Server-side logout failed with status ${err.status}; local session will still be cleared.`);
802
+ } else {
803
+ console.error("[auth.service] Server-side logout request failed; local session will still be cleared.", err);
804
+ }
549
805
  }
550
806
  }
551
807
  async function verifySocialToken(config, provider, token) {
552
- const response = await fetch(`${config.backendUrls.auth}/auth/social/verify/${provider}/`, {
808
+ return apiRequest(`${config.backendUrls.auth}/auth/social/verify/${provider}/`, {
553
809
  method: "POST",
554
- headers: {
555
- "Content-Type": "application/json"
556
- },
557
- body: JSON.stringify({
558
- id_token: token,
559
- storefront_key: config.storefrontApiKey
560
- })
810
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
811
+ body: JSON.stringify({ id_token: token }),
812
+ fallbackErrorMessage: "Social token verification failed"
561
813
  });
562
- if (!response.ok) {
563
- throw new Error("Social token verification failed");
814
+ }
815
+ async function requestCustomerOtp(config, payload) {
816
+ await apiRequest(`${config.backendUrls.auth}/auth/login/customer/passwordless/request/`, {
817
+ method: "POST",
818
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
819
+ body: JSON.stringify(payload),
820
+ fallbackErrorMessage: "Failed to send login code"
821
+ });
822
+ }
823
+ async function verifyCustomerOtp(config, payload, guestSessionId) {
824
+ const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
825
+ if (guestSessionId) {
826
+ headers["X-Guest-Session"] = guestSessionId;
564
827
  }
565
- const data = await response.json();
566
- return data;
828
+ return apiRequest(`${config.backendUrls.auth}/auth/login/customer/passwordless/verify/`, {
829
+ method: "POST",
830
+ headers,
831
+ body: JSON.stringify(payload),
832
+ fallbackErrorMessage: "Invalid or expired code"
833
+ });
834
+ }
835
+ async function forgotPasswordCustomer(config, payload) {
836
+ return apiRequest(`${config.backendUrls.auth}/auth/forgot-password/customer/`, {
837
+ method: "POST",
838
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
839
+ body: JSON.stringify(payload),
840
+ fallbackErrorMessage: "Failed to request password reset"
841
+ });
842
+ }
843
+ async function resetPasswordCustomer(config, payload) {
844
+ return apiRequest(`${config.backendUrls.auth}/auth/reset-password/customer/`, {
845
+ method: "POST",
846
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
847
+ body: JSON.stringify(payload),
848
+ fallbackErrorMessage: "Invalid or expired reset code"
849
+ });
850
+ }
851
+ async function deactivateCustomerAccount(config, accessToken, payload) {
852
+ try {
853
+ const data = await apiRequest(`${config.backendUrls.auth}/auth/customer/deactivate/`, {
854
+ method: "POST",
855
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
856
+ body: JSON.stringify(payload || {}),
857
+ fallbackErrorMessage: "Failed to deactivate account"
858
+ });
859
+ return { status: "success", detail: data.detail };
860
+ } catch (err) {
861
+ if (err instanceof ApiError && err.status === 409) {
862
+ return { status: "confirmation_required", data: err.body };
863
+ }
864
+ throw err;
865
+ }
866
+ }
867
+ async function requestCustomerReactivation(config, payload) {
868
+ return apiRequest(`${config.backendUrls.auth}/auth/customer/reactivate/`, {
869
+ method: "POST",
870
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
871
+ body: JSON.stringify(payload),
872
+ fallbackErrorMessage: "Failed to request reactivation"
873
+ });
874
+ }
875
+ async function verifyCustomerReactivation(config, payload) {
876
+ return apiRequest(`${config.backendUrls.auth}/auth/customer/reactivate/verify/`, {
877
+ method: "POST",
878
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
879
+ body: JSON.stringify(payload),
880
+ fallbackErrorMessage: "Invalid or expired reactivation code"
881
+ });
567
882
  }
568
883
  function parseJwtPayload(token) {
569
884
  try {
@@ -618,70 +933,94 @@ function buildCustomerFromClaims(claims) {
618
933
  }
619
934
  async function getMe(config, accessToken) {
620
935
  if (!config || !accessToken) {
621
- const response2 = await fetch("/api/auth/me", { credentials: "include" });
622
- if (!response2.ok) throw new Error("Failed to fetch profile");
623
- const data2 = await response2.json();
624
- return data2.user;
936
+ const data2 = await apiRequest("/api/auth/me", {
937
+ credentials: "include",
938
+ fallbackErrorMessage: "Failed to fetch profile"
939
+ });
940
+ return mapAuthUserToCustomer(data2.user);
625
941
  }
626
- const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
627
- headers: {
628
- "Authorization": `Bearer ${accessToken}`
629
- }
942
+ const data = await apiRequest(`${config.backendUrls.auth}/auth/profile/`, {
943
+ headers: authHeaders(config, accessToken),
944
+ fallbackErrorMessage: "Failed to fetch profile"
630
945
  });
631
- if (!response.ok) {
632
- throw new Error("Failed to fetch profile");
633
- }
634
- const data = await response.json();
635
946
  return mapAuthUserToCustomer(data);
636
947
  }
637
948
  async function getAuthUser(config, accessToken) {
638
949
  if (!config || !accessToken) {
639
- const response2 = await fetch("/api/auth/me", { credentials: "include" });
640
- if (!response2.ok) throw new Error("Failed to fetch auth user");
641
- const data2 = await response2.json();
642
- return data2.user;
950
+ const data = await apiRequest("/api/auth/me", {
951
+ credentials: "include",
952
+ fallbackErrorMessage: "Failed to fetch auth user"
953
+ });
954
+ return data.user;
643
955
  }
644
- const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
645
- headers: {
646
- "Authorization": `Bearer ${accessToken}`
647
- }
956
+ return apiRequest(`${config.backendUrls.auth}/auth/profile/`, {
957
+ headers: authHeaders(config, accessToken),
958
+ fallbackErrorMessage: "Failed to fetch auth user"
648
959
  });
649
- if (!response.ok) {
650
- throw new Error("Failed to fetch auth user");
651
- }
652
- const data = await response.json();
653
- return data;
654
960
  }
655
961
  async function updateProfile(configOrPayload, accessTokenOrPayload, payloadParam) {
656
962
  const isArg1Config = typeof configOrPayload === "object" && configOrPayload !== null && "businessId" in configOrPayload;
657
963
  if (!isArg1Config) {
658
964
  const payload2 = configOrPayload;
659
- const response2 = await fetch("/api/auth/profile", {
965
+ return apiRequest("/api/auth/profile", {
660
966
  method: "PUT",
661
- headers: { "Content-Type": "application/json" },
967
+ headers: JSON_HEADERS,
662
968
  credentials: "include",
663
- body: JSON.stringify(payload2)
969
+ body: JSON.stringify(payload2),
970
+ fallbackErrorMessage: "Failed to update profile"
664
971
  });
665
- if (!response2.ok) throw new Error("Failed to update profile");
666
- return response2.json();
667
972
  }
668
973
  const config = configOrPayload;
669
974
  const accessToken = accessTokenOrPayload;
670
975
  const payload = payloadParam;
671
- const response = await fetch(`${config.backendUrls.auth}/auth/profile/`, {
976
+ const data = await apiRequest(`${config.backendUrls.auth}/auth/profile/`, {
672
977
  method: "PUT",
673
- headers: {
674
- "Content-Type": "application/json",
675
- "Authorization": `Bearer ${accessToken}`
676
- },
677
- body: JSON.stringify(payload)
978
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
979
+ body: JSON.stringify(payload),
980
+ fallbackErrorMessage: "Failed to update profile"
678
981
  });
679
- if (!response.ok) {
680
- throw new Error("Failed to update profile");
681
- }
682
- const data = await response.json();
683
982
  return mapAuthUserToCustomer(data);
684
983
  }
984
+ async function changePassword(config, accessToken, payload) {
985
+ return apiRequest(`${config.backendUrls.auth}/auth/change-password/`, {
986
+ method: "POST",
987
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
988
+ body: JSON.stringify(payload),
989
+ fallbackErrorMessage: "Failed to change password"
990
+ });
991
+ }
992
+ async function getStorefrontBusinessInfo(config) {
993
+ return apiRequest(`${config.backendUrls.auth}/auth/storefront/business-info/`, {
994
+ headers: storefrontHeaders(config),
995
+ fallbackErrorMessage: "Failed to fetch business info"
996
+ });
997
+ }
998
+ async function getPresignedUploadUrl(config, accessToken, params) {
999
+ const query = new URLSearchParams(
1000
+ Object.entries(params).filter(([, v]) => v !== void 0)
1001
+ );
1002
+ return apiRequest(
1003
+ `${config.backendUrls.auth}/auth/media/presigned-url/?${query.toString()}`,
1004
+ {
1005
+ method: "POST",
1006
+ headers: { Authorization: `Bearer ${accessToken}` },
1007
+ fallbackErrorMessage: "Failed to get presigned upload URL"
1008
+ }
1009
+ );
1010
+ }
1011
+ async function confirmMediaUpload(config, accessToken, params) {
1012
+ const query = new URLSearchParams(
1013
+ Object.entries(params).filter(([, v]) => v !== void 0)
1014
+ );
1015
+ return apiRequest(
1016
+ `${config.backendUrls.auth}/auth/media/confirm-upload/?${query.toString()}`,
1017
+ {
1018
+ method: "POST",
1019
+ headers: { Authorization: `Bearer ${accessToken}` },
1020
+ fallbackErrorMessage: "Failed to confirm upload"
1021
+ }
1022
+ );
1023
+ }
685
1024
  async function silentRefresh(config, refresh) {
686
1025
  try {
687
1026
  const data = await refreshToken(config, refresh);
@@ -692,25 +1031,11 @@ async function silentRefresh(config, refresh) {
692
1031
  const user = buildCustomerFromClaims(claims);
693
1032
  const provider = user.provider;
694
1033
  return { user, provider, newAccessToken: data.access, newRefreshToken: data.refresh };
695
- } catch {
1034
+ } catch (err) {
1035
+ console.error("[auth.service] Silent token refresh failed:", err);
696
1036
  return null;
697
1037
  }
698
1038
  }
699
- function buildFullName(firstname, lastname) {
700
- if (firstname && lastname) return `${firstname} ${lastname}`;
701
- return firstname || lastname || "";
702
- }
703
- function splitFullName(fullName) {
704
- if (!fullName) return { firstname: "", lastname: "" };
705
- const parts = fullName.trim().split(/\s+/);
706
- if (parts.length === 1) {
707
- return { firstname: parts[0], lastname: "" };
708
- }
709
- return {
710
- firstname: parts[0],
711
- lastname: parts.slice(1).join(" ")
712
- };
713
- }
714
1039
  function storeTokens(accessToken, refreshToken2) {
715
1040
  if (typeof window !== "undefined") {
716
1041
  localStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, accessToken);
@@ -732,1061 +1057,369 @@ function getStoredTokens() {
732
1057
  refreshToken: localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN)
733
1058
  };
734
1059
  }
1060
+ async function getCustomerAddresses(config, accessToken) {
1061
+ const data = await apiRequest(`${config.backendUrls.auth}/auth/profile/addresses/`, {
1062
+ headers: authHeaders(config, accessToken),
1063
+ fallbackErrorMessage: "Failed to fetch saved addresses"
1064
+ });
1065
+ return data.results;
1066
+ }
1067
+ async function createCustomerAddress(config, accessToken, payload) {
1068
+ return apiRequest(`${config.backendUrls.auth}/auth/profile/addresses/`, {
1069
+ method: "POST",
1070
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1071
+ body: JSON.stringify(payload),
1072
+ fallbackErrorMessage: "Failed to save address"
1073
+ });
1074
+ }
1075
+ async function updateCustomerAddress(config, accessToken, addressId, payload) {
1076
+ return apiRequest(`${config.backendUrls.auth}/auth/profile/addresses/${addressId}/`, {
1077
+ method: "PATCH",
1078
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1079
+ body: JSON.stringify(payload),
1080
+ fallbackErrorMessage: "Failed to update address"
1081
+ });
1082
+ }
1083
+ async function deleteCustomerAddress(config, accessToken, addressId) {
1084
+ await apiRequest(`${config.backendUrls.auth}/auth/profile/addresses/${addressId}/`, {
1085
+ method: "DELETE",
1086
+ headers: authHeaders(config, accessToken),
1087
+ fallbackErrorMessage: "Failed to delete address"
1088
+ });
1089
+ }
735
1090
 
736
- // src/services/product.service.ts
1091
+ // src/utils/graphql-url.ts
737
1092
  var import_graphql_request = require("graphql-request");
738
- function createGraphQLClient(config) {
1093
+ function resolveGraphQLEndpoint(url) {
1094
+ if (typeof window === "undefined") return url;
1095
+ try {
1096
+ new URL(url);
1097
+ return url;
1098
+ } catch {
1099
+ return `${window.location.origin}${url}`;
1100
+ }
1101
+ }
1102
+ function createGraphQLClient(config, accessToken) {
739
1103
  const headers = {
740
1104
  "Content-Type": "application/json",
741
1105
  "Accept": "application/json",
742
1106
  "X-Storefront-Key": config.storefrontApiKey,
743
1107
  "X-Business-ID": config.businessId
744
1108
  };
745
- return new import_graphql_request.GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
746
- }
747
- var GET_STOREFRONT_PRODUCTS = `
748
- query GetStorefrontProducts($page: Int!, $pageSize: Int!, $collectionSlug: String, $search: String) {
749
- storefront_products(page: $page, pageSize: $pageSize, collectionSlug: $collectionSlug, search: $search) {
750
- items {
751
- id
752
- business_id
753
- name
754
- slug
755
- description
756
- brand
757
- product_type
758
- requires_shipping
759
- is_consumable
760
- is_bespoke
761
- base_price
762
- currency
763
- images
764
- tags
765
- custom_fields { label unit required }
766
- is_published
767
- is_featured
768
- is_popular
769
- is_new
770
- is_temporary
771
- digital_file_key
772
- download_limit
773
- download_expires_at
774
- weight_kg
775
- length_cm
776
- width_cm
777
- height_cm
778
- created_at
779
- updated_at
780
- variants {
781
- id
782
- product_id
783
- sku
784
- attributes
785
- price
786
- images
787
- weight_kg
788
- is_active
789
- inventory {
790
- id
791
- product_id
792
- variant_id
793
- quantity
794
- reserved
795
- reorder_point
796
- reorder_quantity
797
- track_quantity
798
- allow_backorder
799
- available
800
- is_in_stock
801
- is_low_stock
802
- updated_at
803
- }
804
- created_at
805
- updated_at
806
- }
807
- collections {
808
- id
809
- business_id
810
- name
811
- slug
812
- description
813
- image
814
- collection_type
815
- rules
816
- status
817
- sort_order
818
- created_at
819
- updated_at
820
- }
821
- }
822
- total
823
- page
824
- page_size
825
- total_pages
826
- }
827
- }
828
- `;
829
- var GET_STOREFRONT_PRODUCT_BY_SLUG = `
830
- query GetStorefrontProductBySlug($slug: String!) {
831
- storefront_product_by_slug(slug: $slug) {
832
- id
833
- business_id
834
- name
835
- slug
836
- description
837
- brand
838
- product_type
839
- requires_shipping
840
- is_consumable
841
- is_bespoke
842
- base_price
843
- currency
844
- images
845
- tags
846
- custom_fields { label unit required }
847
- is_published
848
- is_featured
849
- is_popular
850
- is_new
851
- is_temporary
852
- digital_file_key
853
- download_limit
854
- download_expires_at
855
- weight_kg
856
- length_cm
857
- width_cm
858
- height_cm
859
- created_at
860
- updated_at
861
- variants {
862
- id
863
- product_id
864
- sku
865
- attributes
866
- price
867
- images
868
- weight_kg
869
- is_active
870
- inventory {
871
- id
872
- product_id
873
- variant_id
874
- quantity
875
- reserved
876
- reorder_point
877
- reorder_quantity
878
- track_quantity
879
- allow_backorder
880
- available
881
- is_in_stock
882
- is_low_stock
883
- updated_at
884
- }
885
- created_at
886
- updated_at
887
- }
888
- collections {
889
- id
890
- business_id
891
- name
892
- slug
893
- description
894
- image
895
- collection_type
896
- rules
897
- status
898
- sort_order
899
- created_at
900
- updated_at
901
- }
902
- }
903
- }
904
- `;
905
- var GET_STOREFRONT_LATEST = `
906
- query GetStorefrontLatest($page: Int!, $pageSize: Int!) {
907
- storefront_latest(page: $page, pageSize: $pageSize) {
908
- items {
909
- id
910
- business_id
911
- name
912
- slug
913
- description
914
- brand
915
- product_type
916
- requires_shipping
917
- is_consumable
918
- is_bespoke
919
- base_price
920
- currency
921
- images
922
- tags
923
- custom_fields { label unit required }
924
- is_published
925
- is_featured
926
- is_popular
927
- is_new
928
- is_temporary
929
- digital_file_key
930
- download_limit
931
- download_expires_at
932
- weight_kg
933
- length_cm
934
- width_cm
935
- height_cm
936
- created_at
937
- updated_at
938
- variants {
939
- id
940
- product_id
941
- sku
942
- attributes
943
- price
944
- images
945
- weight_kg
946
- is_active
947
- inventory {
948
- id
949
- product_id
950
- variant_id
951
- quantity
952
- reserved
953
- reorder_point
954
- reorder_quantity
955
- track_quantity
956
- allow_backorder
957
- available
958
- is_in_stock
959
- is_low_stock
960
- updated_at
961
- }
962
- created_at
963
- updated_at
964
- }
965
- collections {
966
- id
967
- business_id
968
- name
969
- slug
970
- description
971
- image
972
- collection_type
973
- rules
974
- status
975
- sort_order
976
- created_at
977
- updated_at
978
- }
979
- }
980
- total
981
- page
982
- page_size
983
- total_pages
984
- }
985
- }
986
- `;
987
- var GET_STOREFRONT_POPULAR = `
988
- query GetStorefrontPopular($page: Int!, $pageSize: Int!) {
989
- storefront_popular(page: $page, pageSize: $pageSize) {
990
- items {
991
- id
992
- business_id
993
- name
994
- slug
995
- description
996
- brand
997
- product_type
998
- requires_shipping
999
- is_consumable
1000
- is_bespoke
1001
- base_price
1002
- currency
1003
- images
1004
- tags
1005
- custom_fields { label unit required }
1006
- is_published
1007
- is_featured
1008
- is_popular
1009
- is_new
1010
- is_temporary
1011
- digital_file_key
1012
- download_limit
1013
- download_expires_at
1014
- weight_kg
1015
- length_cm
1016
- width_cm
1017
- height_cm
1018
- created_at
1019
- updated_at
1020
- variants {
1021
- id
1022
- product_id
1023
- sku
1024
- attributes
1025
- price
1026
- images
1027
- weight_kg
1028
- is_active
1029
- inventory {
1030
- id
1031
- product_id
1032
- variant_id
1033
- quantity
1034
- reserved
1035
- reorder_point
1036
- reorder_quantity
1037
- track_quantity
1038
- allow_backorder
1039
- available
1040
- is_in_stock
1041
- is_low_stock
1042
- updated_at
1043
- }
1044
- created_at
1045
- updated_at
1046
- }
1047
- collections {
1048
- id
1049
- business_id
1050
- name
1051
- slug
1052
- description
1053
- image
1054
- collection_type
1055
- rules
1056
- status
1057
- sort_order
1058
- created_at
1059
- updated_at
1060
- }
1061
- }
1062
- total
1063
- page
1064
- page_size
1065
- total_pages
1066
- }
1067
- }
1068
- `;
1069
- var GET_STOREFRONT_FEATURED = `
1070
- query GetStorefrontFeatured($page: Int!, $pageSize: Int!) {
1071
- storefront_featured(page: $page, pageSize: $pageSize) {
1072
- items {
1073
- id
1074
- business_id
1075
- name
1076
- slug
1077
- description
1078
- brand
1079
- product_type
1080
- requires_shipping
1081
- is_consumable
1082
- is_bespoke
1083
- base_price
1084
- currency
1085
- images
1086
- tags
1087
- custom_fields { label unit required }
1088
- is_published
1089
- is_featured
1090
- is_popular
1091
- is_new
1092
- is_temporary
1093
- digital_file_key
1094
- download_limit
1095
- download_expires_at
1096
- weight_kg
1097
- length_cm
1098
- width_cm
1099
- height_cm
1100
- created_at
1101
- updated_at
1102
- variants {
1103
- id
1104
- product_id
1105
- sku
1106
- attributes
1107
- price
1108
- images
1109
- weight_kg
1110
- is_active
1111
- inventory {
1112
- id
1113
- product_id
1114
- variant_id
1115
- quantity
1116
- reserved
1117
- reorder_point
1118
- reorder_quantity
1119
- track_quantity
1120
- allow_backorder
1121
- available
1122
- is_in_stock
1123
- is_low_stock
1124
- updated_at
1125
- }
1126
- created_at
1127
- updated_at
1128
- }
1129
- collections {
1130
- id
1131
- business_id
1132
- name
1133
- slug
1134
- description
1135
- image
1136
- collection_type
1137
- rules
1138
- status
1139
- sort_order
1140
- created_at
1141
- updated_at
1142
- }
1143
- }
1144
- total
1145
- page
1146
- page_size
1147
- total_pages
1148
- }
1149
- }
1150
- `;
1151
- var GET_STOREFRONT_NEW = `
1152
- query GetStorefrontNew($page: Int!, $pageSize: Int!) {
1153
- storefront_new(page: $page, pageSize: $pageSize) {
1154
- items {
1155
- id
1156
- business_id
1157
- name
1158
- slug
1159
- description
1160
- brand
1161
- product_type
1162
- requires_shipping
1163
- is_consumable
1164
- is_bespoke
1165
- base_price
1166
- currency
1167
- sale_price
1168
- sale_start
1169
- sale_end
1170
- images
1171
- tags
1172
- custom_fields { label unit required }
1173
- is_published
1174
- is_featured
1175
- is_popular
1176
- is_new
1177
- is_temporary
1178
- digital_file_key
1179
- download_limit
1180
- download_expires_at
1181
- weight_kg
1182
- length_cm
1183
- width_cm
1184
- height_cm
1185
- created_at
1186
- updated_at
1187
- variants {
1188
- id
1189
- product_id
1190
- sku
1191
- attributes
1192
- price
1193
- images
1194
- weight_kg
1195
- is_active
1196
- inventory {
1197
- id
1198
- product_id
1199
- variant_id
1200
- quantity
1201
- reserved
1202
- reorder_point
1203
- reorder_quantity
1204
- track_quantity
1205
- allow_backorder
1206
- available
1207
- is_in_stock
1208
- is_low_stock
1209
- updated_at
1210
- }
1211
- created_at
1212
- updated_at
1213
- }
1214
- collections {
1215
- id
1216
- business_id
1217
- name
1218
- slug
1219
- description
1220
- image
1221
- collection_type
1222
- rules
1223
- status
1224
- sort_order
1225
- created_at
1226
- updated_at
1227
- }
1228
- }
1229
- total
1230
- page
1231
- page_size
1232
- total_pages
1233
- }
1234
- }
1235
- `;
1236
- var GET_STOREFRONT_ON_SALE = `
1237
- query GetStorefrontOnSale($page: Int!, $pageSize: Int!) {
1238
- storefront_on_sale(page: $page, pageSize: $pageSize) {
1239
- items {
1240
- id
1241
- business_id
1242
- name
1243
- slug
1244
- description
1245
- brand
1246
- product_type
1247
- requires_shipping
1248
- is_consumable
1249
- is_bespoke
1250
- base_price
1251
- currency
1252
- sale_price
1253
- sale_start
1254
- sale_end
1255
- images
1256
- tags
1257
- custom_fields { label unit required }
1258
- is_published
1259
- is_featured
1260
- is_popular
1261
- is_new
1262
- is_temporary
1263
- digital_file_key
1264
- download_limit
1265
- download_expires_at
1266
- weight_kg
1267
- length_cm
1268
- width_cm
1269
- height_cm
1270
- created_at
1271
- updated_at
1272
- variants {
1273
- id
1274
- product_id
1275
- sku
1276
- attributes
1277
- price
1278
- images
1279
- weight_kg
1280
- is_active
1281
- inventory {
1282
- id
1283
- product_id
1284
- variant_id
1285
- quantity
1286
- reserved
1287
- reorder_point
1288
- reorder_quantity
1289
- track_quantity
1290
- allow_backorder
1291
- available
1292
- is_in_stock
1293
- is_low_stock
1294
- updated_at
1295
- }
1296
- created_at
1297
- updated_at
1298
- }
1299
- collections {
1300
- id
1301
- business_id
1302
- name
1303
- slug
1304
- description
1305
- image
1306
- collection_type
1307
- rules
1308
- status
1309
- sort_order
1310
- created_at
1311
- updated_at
1312
- }
1313
- }
1314
- total
1315
- page
1316
- page_size
1317
- total_pages
1318
- }
1319
- }
1320
- `;
1321
- var GET_STOREFRONT_LOW_STOCK = `
1322
- query GetStorefrontLowStock($page: Int!, $pageSize: Int!) {
1323
- storefront_low_stock(page: $page, pageSize: $pageSize) {
1324
- items {
1325
- id
1326
- business_id
1327
- name
1328
- slug
1329
- description
1330
- brand
1331
- product_type
1332
- requires_shipping
1333
- is_consumable
1334
- is_bespoke
1335
- base_price
1336
- currency
1337
- sale_price
1338
- sale_start
1339
- sale_end
1340
- images
1341
- tags
1342
- custom_fields { label unit required }
1343
- is_published
1344
- is_featured
1345
- is_popular
1346
- is_new
1347
- is_temporary
1348
- digital_file_key
1349
- download_limit
1350
- download_expires_at
1351
- weight_kg
1352
- length_cm
1353
- width_cm
1354
- height_cm
1355
- created_at
1356
- updated_at
1357
- variants {
1358
- id
1359
- product_id
1360
- sku
1361
- attributes
1362
- price
1363
- images
1364
- weight_kg
1365
- is_active
1366
- inventory {
1367
- id
1368
- product_id
1369
- variant_id
1370
- quantity
1371
- reserved
1372
- reorder_point
1373
- reorder_quantity
1374
- track_quantity
1375
- allow_backorder
1376
- available
1377
- is_in_stock
1378
- is_low_stock
1379
- updated_at
1380
- }
1381
- created_at
1382
- updated_at
1383
- }
1384
- collections {
1385
- id
1386
- business_id
1387
- name
1388
- slug
1389
- description
1390
- image
1391
- collection_type
1392
- rules
1393
- status
1394
- sort_order
1395
- created_at
1396
- updated_at
1397
- }
1398
- }
1399
- total
1400
- page
1401
- page_size
1402
- total_pages
1403
- }
1109
+ if (accessToken) {
1110
+ headers["Authorization"] = `Bearer ${accessToken}`;
1404
1111
  }
1405
- `;
1406
- var GET_STOREFRONT_RECOMMENDED = `
1407
- query GetStorefrontRecommended($page: Int!, $pageSize: Int!, $excludeProductId: String) {
1408
- storefront_recommended(page: $page, pageSize: $pageSize, excludeProductId: $excludeProductId) {
1409
- items {
1410
- id
1411
- business_id
1412
- name
1413
- slug
1414
- description
1415
- brand
1416
- product_type
1417
- requires_shipping
1418
- is_consumable
1419
- is_bespoke
1420
- base_price
1421
- currency
1422
- images
1423
- tags
1424
- custom_fields { label unit required }
1425
- is_published
1426
- is_featured
1427
- is_popular
1428
- is_new
1429
- is_temporary
1430
- digital_file_key
1431
- download_limit
1432
- download_expires_at
1433
- weight_kg
1434
- length_cm
1435
- width_cm
1436
- height_cm
1437
- created_at
1438
- updated_at
1439
- variants {
1440
- id
1441
- product_id
1442
- sku
1443
- attributes
1444
- price
1445
- images
1446
- weight_kg
1447
- is_active
1448
- inventory {
1449
- id
1450
- product_id
1451
- variant_id
1452
- quantity
1453
- reserved
1454
- reorder_point
1455
- reorder_quantity
1456
- track_quantity
1457
- allow_backorder
1458
- available
1459
- is_in_stock
1460
- is_low_stock
1461
- updated_at
1462
- }
1463
- created_at
1464
- updated_at
1465
- }
1466
- collections {
1467
- id
1468
- business_id
1469
- name
1470
- slug
1471
- description
1472
- image
1473
- collection_type
1474
- rules
1475
- status
1476
- sort_order
1477
- created_at
1478
- updated_at
1479
- }
1480
- }
1481
- total
1482
- page
1483
- page_size
1484
- total_pages
1112
+ return new import_graphql_request.GraphQLClient(resolveGraphQLEndpoint(`${config.backendUrls.store}/graphql`), { headers });
1113
+ }
1114
+
1115
+ // src/generated/graphql.ts
1116
+ var GetStorefrontCollectionsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontCollections" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_collections" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "CollectionFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "CollectionFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Collection" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] };
1117
+ var GetStorefrontCollectionBySlugDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontCollectionBySlug" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_collection_by_slug" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "slug" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "CollectionFields" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "CollectionFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Collection" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] };
1118
+ var GetStorefrontProductsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontProducts" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "collectionSlug" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "search" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "productType" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_products" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "collectionSlug" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "collectionSlug" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "search" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "search" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "productType" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "productType" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
1119
+ var GetStorefrontProductBySlugDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontProductBySlug" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_product_by_slug" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "slug" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
1120
+ var GetStorefrontPopularDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontPopular" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_popular" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
1121
+ var GetStorefrontFeaturedDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontFeatured" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_featured" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
1122
+ var GetStorefrontNewDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontNew" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_new" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
1123
+ var GetStorefrontOnSaleDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontOnSale" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_on_sale" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
1124
+ var GetStorefrontRecommendedDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontRecommended" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "excludeProductId" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_recommended" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "excludeProductId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "excludeProductId" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "FragmentSpread", "name": { "kind": "Name", "value": "ProductFields" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }, { "kind": "FragmentDefinition", "name": { "kind": "Name", "value": "ProductFields" }, "typeCondition": { "kind": "NamedType", "name": { "kind": "Name", "value": "Product" } }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "brand" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "requires_shipping" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_consumable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_bespoke" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_physical" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_non_returnable" } }, { "kind": "Field", "name": { "kind": "Name", "value": "deposit_percentage" } }, { "kind": "Field", "name": { "kind": "Name", "value": "base_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_start" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sale_end" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "tags" } }, { "kind": "Field", "name": { "kind": "Name", "value": "custom_fields" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "label" } }, { "kind": "Field", "name": { "kind": "Name", "value": "unit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "required" } }, { "kind": "Field", "name": { "kind": "Name", "value": "field_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "options" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_published" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_featured" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_popular" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_new" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_temporary" } }, { "kind": "Field", "name": { "kind": "Name", "value": "average_rating" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rating_count" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel" } }, { "kind": "Field", "name": { "kind": "Name", "value": "source_channel_ref_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_duration_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_location_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_coverage_radius_km" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_requires_consultation" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_max_capacity_per_slot" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_buffer_minutes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_is_recurring" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_recurring_interval" } }, { "kind": "Field", "name": { "kind": "Name", "value": "service_project_based" } }, { "kind": "Field", "name": { "kind": "Name", "value": "digital_files" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "file_key" } }, { "kind": "Field", "name": { "kind": "Name", "value": "display_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_limit" } }, { "kind": "Field", "name": { "kind": "Name", "value": "download_expires_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "length_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "width_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "height_cm" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variants" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sku" } }, { "kind": "Field", "name": { "kind": "Name", "value": "attributes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "images" } }, { "kind": "Field", "name": { "kind": "Name", "value": "weight_kg" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_active" } }, { "kind": "Field", "name": { "kind": "Name", "value": "inventory" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "variant_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reserved" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_point" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reorder_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "track_quantity" } }, { "kind": "Field", "name": { "kind": "Name", "value": "allow_backorder" } }, { "kind": "Field", "name": { "kind": "Name", "value": "available" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_in_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "is_low_stock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "collections" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "business_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "image_url" } }, { "kind": "Field", "name": { "kind": "Name", "value": "collection_type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rules" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "sort_order" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "updated_at" } }] } }] } }] };
1125
+ var GetStorefrontWishlistDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetStorefrontWishlist" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "storefront_wishlist" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "page" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "page" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "pageSize" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "pageSize" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "notes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created_at" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_price" } }, { "kind": "Field", "name": { "kind": "Name", "value": "currency" } }, { "kind": "Field", "name": { "kind": "Name", "value": "product_image" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "total" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page" } }, { "kind": "Field", "name": { "kind": "Name", "value": "page_size" } }, { "kind": "Field", "name": { "kind": "Name", "value": "total_pages" } }] } }] } }] };
1126
+ var CheckInStorefrontWishlistDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "CheckInStorefrontWishlist" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "productId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "check_in_storefront_wishlist" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "productId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "productId" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "in_wishlist" } }] } }] } }] };
1127
+
1128
+ // src/services/product.service.ts
1129
+ function mapProductType(raw) {
1130
+ switch (raw) {
1131
+ case "PHYSICAL":
1132
+ return "physical" /* PHYSICAL */;
1133
+ case "DIGITAL":
1134
+ return "digital" /* DIGITAL */;
1135
+ case "SERVICE":
1136
+ return "service" /* SERVICE */;
1137
+ case "BESPOKE":
1138
+ return "bespoke" /* BESPOKE */;
1139
+ default: {
1140
+ const _exhaustive = raw;
1141
+ throw new Error(`Unhandled GraphQL ProductType member: ${_exhaustive}`);
1485
1142
  }
1486
1143
  }
1487
- `;
1144
+ }
1145
+ function mapCustomFieldType(raw) {
1146
+ if (raw === "text" || raw === "choice") return raw;
1147
+ throw new Error(`Unrecognised custom field field_type from backend: "${raw}"`);
1148
+ }
1149
+ function mapProduct(raw) {
1150
+ return {
1151
+ ...raw,
1152
+ product_type: mapProductType(raw.product_type),
1153
+ custom_fields: raw.custom_fields.map((f) => ({
1154
+ ...f,
1155
+ unit: f.unit ?? void 0,
1156
+ field_type: mapCustomFieldType(f.field_type)
1157
+ })),
1158
+ description: raw.description ?? void 0,
1159
+ brand: raw.brand ?? void 0,
1160
+ is_physical: raw.is_physical ?? void 0,
1161
+ sale_price: raw.sale_price ?? void 0,
1162
+ sale_start: raw.sale_start ?? void 0,
1163
+ sale_end: raw.sale_end ?? void 0,
1164
+ source_channel_ref_id: raw.source_channel_ref_id ?? void 0,
1165
+ download_limit: raw.download_limit ?? void 0,
1166
+ download_expires_at: raw.download_expires_at ?? void 0,
1167
+ service_type: raw.service_type ?? void 0,
1168
+ service_duration_minutes: raw.service_duration_minutes ?? void 0,
1169
+ service_location_type: raw.service_location_type ?? void 0,
1170
+ service_coverage_radius_km: raw.service_coverage_radius_km ?? void 0,
1171
+ service_max_capacity_per_slot: raw.service_max_capacity_per_slot ?? void 0,
1172
+ service_recurring_interval: raw.service_recurring_interval ?? void 0,
1173
+ length_cm: raw.length_cm ?? void 0,
1174
+ width_cm: raw.width_cm ?? void 0,
1175
+ height_cm: raw.height_cm ?? void 0,
1176
+ average_rating: raw.average_rating ?? void 0,
1177
+ created_at: raw.created_at,
1178
+ updated_at: raw.updated_at,
1179
+ variants: raw.variants.map((v) => ({
1180
+ ...v,
1181
+ sku: v.sku ?? void 0,
1182
+ attributes: v.attributes ? JSON.parse(v.attributes) : {},
1183
+ price: v.price ?? void 0,
1184
+ weight_kg: v.weight_kg ?? void 0,
1185
+ inventory: v.inventory ? {
1186
+ ...v.inventory,
1187
+ variant_id: v.inventory.variant_id ?? void 0,
1188
+ updated_at: v.inventory.updated_at
1189
+ } : void 0,
1190
+ created_at: v.created_at,
1191
+ updated_at: v.updated_at
1192
+ })),
1193
+ collections: raw.collections.map((c) => ({
1194
+ ...c,
1195
+ business_id: c.business_id ?? void 0,
1196
+ description: c.description ?? void 0,
1197
+ image_url: c.image_url ?? void 0,
1198
+ rules: c.rules ?? void 0,
1199
+ created_at: c.created_at,
1200
+ updated_at: c.updated_at
1201
+ }))
1202
+ };
1203
+ }
1204
+ function mapProductConnection(connection) {
1205
+ return { ...connection, items: connection.items.map(mapProduct) };
1206
+ }
1488
1207
  async function getStorefrontProducts(config, params) {
1489
1208
  const client = createGraphQLClient(config);
1490
- const variables = {
1209
+ const data = await client.request(GetStorefrontProductsDocument, {
1491
1210
  page: params?.page || 1,
1492
1211
  pageSize: params?.pageSize || 20,
1493
1212
  collectionSlug: params?.collectionSlug,
1494
- search: params?.search
1495
- };
1496
- const data = await client.request(GET_STOREFRONT_PRODUCTS, variables);
1497
- return data.storefront_products;
1213
+ search: params?.search,
1214
+ productType: params?.productType
1215
+ });
1216
+ return mapProductConnection(data.storefront_products);
1498
1217
  }
1499
1218
  async function getStorefrontProductBySlug(config, slug) {
1500
1219
  const client = createGraphQLClient(config);
1501
- const data = await client.request(GET_STOREFRONT_PRODUCT_BY_SLUG, { slug });
1502
- return data.storefront_product_by_slug;
1503
- }
1504
- async function getLatestProducts(config, params) {
1505
- const client = createGraphQLClient(config);
1506
- const variables = {
1507
- page: params?.page || 1,
1508
- pageSize: params?.pageSize || 4
1509
- };
1510
- const data = await client.request(GET_STOREFRONT_LATEST, variables);
1511
- return data.storefront_latest;
1220
+ const data = await client.request(GetStorefrontProductBySlugDocument, { slug });
1221
+ if (!data.storefront_product_by_slug) {
1222
+ throw new Error(`Product not found: ${slug}`);
1223
+ }
1224
+ return mapProduct(data.storefront_product_by_slug);
1512
1225
  }
1513
1226
  async function getPopularProducts(config, params) {
1514
1227
  const client = createGraphQLClient(config);
1515
- const variables = {
1228
+ const data = await client.request(GetStorefrontPopularDocument, {
1516
1229
  page: params?.page || 1,
1517
1230
  pageSize: params?.pageSize || 4
1518
- };
1519
- const data = await client.request(GET_STOREFRONT_POPULAR, variables);
1520
- return data.storefront_popular;
1231
+ });
1232
+ return mapProductConnection(data.storefront_popular);
1521
1233
  }
1522
1234
  async function getFeaturedProducts(config, params) {
1523
1235
  const client = createGraphQLClient(config);
1524
- const variables = {
1236
+ const data = await client.request(GetStorefrontFeaturedDocument, {
1525
1237
  page: params?.page || 1,
1526
1238
  pageSize: params?.pageSize || 4
1527
- };
1528
- const data = await client.request(GET_STOREFRONT_FEATURED, variables);
1529
- return data.storefront_featured;
1239
+ });
1240
+ return mapProductConnection(data.storefront_featured);
1530
1241
  }
1531
1242
  async function getNewProducts(config, params) {
1532
1243
  const client = createGraphQLClient(config);
1533
- const variables = {
1244
+ const data = await client.request(GetStorefrontNewDocument, {
1534
1245
  page: params?.page || 1,
1535
1246
  pageSize: params?.pageSize || 4
1536
- };
1537
- const data = await client.request(GET_STOREFRONT_NEW, variables);
1538
- return data.storefront_new;
1247
+ });
1248
+ return mapProductConnection(data.storefront_new);
1539
1249
  }
1540
1250
  async function getOnSaleProducts(config, params) {
1541
1251
  const client = createGraphQLClient(config);
1542
- const variables = {
1543
- page: params?.page || 1,
1544
- pageSize: params?.pageSize || 4
1545
- };
1546
- const data = await client.request(GET_STOREFRONT_ON_SALE, variables);
1547
- return data.storefront_on_sale;
1548
- }
1549
- async function getLowStockProducts(config, params) {
1550
- const client = createGraphQLClient(config);
1551
- const variables = {
1252
+ const data = await client.request(GetStorefrontOnSaleDocument, {
1552
1253
  page: params?.page || 1,
1553
1254
  pageSize: params?.pageSize || 4
1554
- };
1555
- const data = await client.request(GET_STOREFRONT_LOW_STOCK, variables);
1556
- return data.storefront_low_stock;
1255
+ });
1256
+ return mapProductConnection(data.storefront_on_sale);
1557
1257
  }
1558
1258
  async function getRecommendedProducts(config, params) {
1559
1259
  const client = createGraphQLClient(config);
1560
- const variables = {
1260
+ const data = await client.request(GetStorefrontRecommendedDocument, {
1561
1261
  page: params?.page || 1,
1562
1262
  pageSize: params?.pageSize || 4,
1563
1263
  excludeProductId: params?.excludeProductId
1564
- };
1565
- const data = await client.request(GET_STOREFRONT_RECOMMENDED, variables);
1566
- return data.storefront_recommended;
1264
+ });
1265
+ return mapProductConnection(data.storefront_recommended);
1567
1266
  }
1568
1267
 
1569
1268
  // src/services/collection.service.ts
1570
- var import_graphql_request2 = require("graphql-request");
1571
- var GET_STOREFRONT_COLLECTIONS = `
1572
- query GetStorefrontCollections($page: Int!, $pageSize: Int!) {
1573
- storefront_collections(page: $page, pageSize: $pageSize) {
1574
- items {
1575
- id
1576
- business_id
1577
- name
1578
- slug
1579
- description
1580
- image
1581
- collection_type
1582
- rules
1583
- status
1584
- sort_order
1585
- created_at
1586
- updated_at
1587
- }
1588
- total
1589
- page
1590
- page_size
1591
- total_pages
1592
- }
1593
- }
1594
- `;
1595
- var GET_STOREFRONT_COLLECTION_BY_SLUG = `
1596
- query GetStorefrontCollectionBySlug($slug: String!) {
1597
- storefront_collection_by_slug(slug: $slug) {
1598
- id
1599
- business_id
1600
- name
1601
- slug
1602
- description
1603
- image
1604
- collection_type
1605
- rules
1606
- status
1607
- sort_order
1608
- created_at
1609
- updated_at
1610
- }
1611
- }
1612
- `;
1613
- function createGraphQLClient2(config) {
1614
- const headers = {
1615
- "Content-Type": "application/json",
1616
- "Accept": "application/json",
1617
- "X-Storefront-Key": config.storefrontApiKey,
1618
- "X-Business-ID": config.businessId
1269
+ function mapCollection(raw) {
1270
+ return {
1271
+ ...raw,
1272
+ business_id: raw.business_id ?? void 0,
1273
+ description: raw.description ?? void 0,
1274
+ image_url: raw.image_url ?? void 0,
1275
+ rules: raw.rules ?? void 0,
1276
+ created_at: raw.created_at,
1277
+ updated_at: raw.updated_at
1619
1278
  };
1620
- return new import_graphql_request2.GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
1621
1279
  }
1622
1280
  async function getStorefrontCollections(config, params) {
1623
- const client = createGraphQLClient2(config);
1624
- const variables = {
1281
+ const client = createGraphQLClient(config);
1282
+ const data = await client.request(GetStorefrontCollectionsDocument, {
1625
1283
  page: params?.page || 1,
1626
1284
  pageSize: params?.pageSize || 20
1627
- };
1628
- const data = await client.request(GET_STOREFRONT_COLLECTIONS, variables);
1629
- return data.storefront_collections;
1285
+ });
1286
+ return { ...data.storefront_collections, items: data.storefront_collections.items.map(mapCollection) };
1630
1287
  }
1631
1288
  async function getStorefrontCollectionBySlug(config, slug) {
1632
- const client = createGraphQLClient2(config);
1633
- const data = await client.request(GET_STOREFRONT_COLLECTION_BY_SLUG, { slug });
1634
- return data.storefront_collection_by_slug;
1289
+ const client = createGraphQLClient(config);
1290
+ const data = await client.request(GetStorefrontCollectionBySlugDocument, { slug });
1291
+ if (!data.storefront_collection_by_slug) {
1292
+ throw new Error(`Collection not found: ${slug}`);
1293
+ }
1294
+ return mapCollection(data.storefront_collection_by_slug);
1635
1295
  }
1636
1296
 
1637
1297
  // src/services/wishlist.service.ts
1638
- var import_graphql_request3 = require("graphql-request");
1639
- var GET_STOREFRONT_WISHLIST = `
1640
- query GetStorefrontWishlist($page: Int!, $pageSize: Int!) {
1641
- storefront_wishlist(page: $page, pageSize: $pageSize) {
1642
- items {
1643
- id
1644
- product_id
1645
- notes
1646
- created_at
1647
- product_name
1648
- product_slug
1649
- product_price
1650
- currency
1651
- product_image
1652
- }
1653
- total
1654
- page
1655
- page_size
1656
- total_pages
1657
- }
1658
- }
1659
- `;
1660
- var CHECK_IN_STOREFRONT_WISHLIST = `
1661
- query CheckInStorefrontWishlist($productId: String!) {
1662
- check_in_storefront_wishlist(productId: $productId) {
1663
- in_wishlist
1664
- }
1665
- }
1666
- `;
1667
- function createGraphQLClient3(config, accessToken) {
1668
- const headers = {
1669
- "Content-Type": "application/json",
1670
- "Accept": "application/json",
1671
- "X-Storefront-Key": config.storefrontApiKey,
1672
- "X-Business-ID": config.businessId
1673
- };
1674
- if (accessToken) {
1675
- headers["Authorization"] = `Bearer ${accessToken}`;
1676
- }
1677
- return new import_graphql_request3.GraphQLClient(`${config.backendUrls.store}/graphql`, { headers });
1678
- }
1679
1298
  async function getWishlist(config, accessToken, params) {
1680
- const client = createGraphQLClient3(config, accessToken);
1681
- const variables = {
1299
+ const client = createGraphQLClient(config, accessToken);
1300
+ const data = await client.request(GetStorefrontWishlistDocument, {
1682
1301
  page: params?.page || 1,
1683
1302
  pageSize: params?.pageSize || 20
1303
+ });
1304
+ return {
1305
+ ...data.storefront_wishlist,
1306
+ items: data.storefront_wishlist.items.map((item) => ({
1307
+ ...item,
1308
+ created_at: item.created_at,
1309
+ notes: item.notes ?? void 0,
1310
+ product_name: item.product_name ?? void 0,
1311
+ product_slug: item.product_slug ?? void 0,
1312
+ product_price: item.product_price ?? void 0,
1313
+ currency: item.currency ?? void 0,
1314
+ product_image: item.product_image ?? void 0
1315
+ }))
1684
1316
  };
1685
- const data = await client.request(GET_STOREFRONT_WISHLIST, variables);
1686
- return data.storefront_wishlist;
1687
1317
  }
1688
1318
  async function checkInWishlist(config, accessToken, productId) {
1689
- const client = createGraphQLClient3(config, accessToken);
1690
- const data = await client.request(CHECK_IN_STOREFRONT_WISHLIST, { productId });
1319
+ const client = createGraphQLClient(config, accessToken);
1320
+ const data = await client.request(CheckInStorefrontWishlistDocument, { productId });
1691
1321
  return data.check_in_storefront_wishlist;
1692
1322
  }
1693
1323
  async function addToWishlist(config, accessToken, productId, notes) {
1694
- const response = await fetch(`${config.backendUrls.store}/wishlist/`, {
1324
+ return apiRequest(`${config.backendUrls.store}/wishlist/`, {
1695
1325
  method: "POST",
1696
- headers: {
1697
- "Content-Type": "application/json",
1698
- "Authorization": `Bearer ${accessToken}`,
1699
- "X-Storefront-Key": config.storefrontApiKey,
1700
- "X-Business-ID": config.businessId
1701
- },
1326
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1702
1327
  body: JSON.stringify({
1703
1328
  product_id: productId,
1704
1329
  notes: notes || void 0
1705
- })
1330
+ }),
1331
+ fallbackErrorMessage: "Failed to add to wishlist"
1706
1332
  });
1707
- if (!response.ok) throw new Error("Failed to add to wishlist");
1708
- return response.json();
1709
1333
  }
1710
1334
  async function removeFromWishlist(config, accessToken, itemId) {
1711
- const response = await fetch(`${config.backendUrls.store}/wishlist/${itemId}`, {
1335
+ await apiRequest(`${config.backendUrls.store}/wishlist/${itemId}`, {
1712
1336
  method: "DELETE",
1713
- headers: {
1714
- "Authorization": `Bearer ${accessToken}`,
1715
- "X-Storefront-Key": config.storefrontApiKey,
1716
- "X-Business-ID": config.businessId
1717
- }
1337
+ headers: authHeaders(config, accessToken),
1338
+ fallbackErrorMessage: "Failed to remove from wishlist"
1718
1339
  });
1719
- if (!response.ok) throw new Error("Failed to remove from wishlist");
1720
1340
  }
1721
1341
  async function removeProductFromWishlist(config, accessToken, productId) {
1722
- const response = await fetch(`${config.backendUrls.store}/wishlist/product/${productId}`, {
1342
+ await apiRequest(`${config.backendUrls.store}/wishlist/product/${productId}`, {
1723
1343
  method: "DELETE",
1724
- headers: {
1725
- "Authorization": `Bearer ${accessToken}`,
1726
- "X-Storefront-Key": config.storefrontApiKey,
1727
- "X-Business-ID": config.businessId
1728
- }
1344
+ headers: authHeaders(config, accessToken),
1345
+ fallbackErrorMessage: "Failed to remove product from wishlist"
1729
1346
  });
1730
- if (!response.ok) throw new Error("Failed to remove product from wishlist");
1731
1347
  }
1732
1348
 
1733
1349
  // src/services/payment.service.ts
1350
+ function isValidUUID(str) {
1351
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);
1352
+ }
1353
+ async function getAvailablePaymentMethods(config, currency, countryCode) {
1354
+ const params = {};
1355
+ if (currency) params.currency = currency;
1356
+ if (countryCode) params.country_code = countryCode;
1357
+ const query = new URLSearchParams(params).toString();
1358
+ return apiRequest(`${config.backendUrls.payment}/payments/storefront/methods${query ? `?${query}` : ""}`, {
1359
+ headers: storefrontHeaders(config),
1360
+ fallbackErrorMessage: "Failed to fetch available payment methods"
1361
+ });
1362
+ }
1734
1363
  async function createDedicatedAccount(config, accessToken, request) {
1735
- const isValidUUID = (str) => {
1736
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1737
- return uuidRegex.test(str);
1738
- };
1739
- const response = await fetch(`${config.backendUrls.payment}/payments/dedicated-account`, {
1364
+ const origin = request.storefront_origin || (typeof window !== "undefined" ? window.location.origin : "");
1365
+ const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
1366
+ if (accessToken) {
1367
+ headers["Authorization"] = `Bearer ${accessToken}`;
1368
+ }
1369
+ if (origin) {
1370
+ headers["Origin"] = origin;
1371
+ }
1372
+ return apiRequest(`${config.backendUrls.payment}/payments/storefront/dedicated-account`, {
1740
1373
  method: "POST",
1741
- headers: {
1742
- "Content-Type": "application/json",
1743
- "Authorization": `Bearer ${accessToken}`,
1744
- "X-Storefront-Key": config.storefrontApiKey,
1745
- "X-Business-ID": config.businessId
1746
- },
1374
+ headers,
1747
1375
  body: JSON.stringify({
1748
1376
  order_id: request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0,
1749
1377
  amount: request.amount,
1750
1378
  customer_email: request.customer_email,
1751
1379
  customer_name: request.customer_name,
1752
1380
  currency: request.currency,
1381
+ gateway: request.gateway,
1753
1382
  idempotency_key: request.idempotency_key
1754
- })
1383
+ }),
1384
+ fallbackErrorMessage: "Failed to create dedicated account"
1755
1385
  });
1756
- if (!response.ok) throw new Error("Failed to create dedicated account");
1757
- const data = await response.json();
1758
- return data;
1759
1386
  }
1760
1387
  async function initiatePayment(config, accessToken, request) {
1761
- const isValidUUID = (str) => {
1762
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1763
- return uuidRegex.test(str);
1764
- };
1765
1388
  const validOrderId = request.order_id && isValidUUID(request.order_id) ? request.order_id : void 0;
1766
- const response = await fetch(`${config.backendUrls.payment}/payments/storefront/initiate`, {
1767
- method: "POST",
1768
- headers: {
1769
- "Content-Type": "application/json",
1770
- "Authorization": `Bearer ${accessToken}`,
1771
- "X-Storefront-Key": config.storefrontApiKey,
1772
- "X-Business-ID": config.businessId
1773
- },
1774
- body: JSON.stringify({
1775
- amount: request.amount,
1776
- currency: request.currency,
1777
- order_id: validOrderId,
1778
- quote_id: request.quote_id,
1779
- metadata_json: {
1780
- customer_email: request.customer_email,
1781
- customer_name: request.customer_name ?? "",
1389
+ const origin = request.storefront_origin || (typeof window !== "undefined" ? window.location.origin : "");
1390
+ const headers = { ...JSON_HEADERS, ...storefrontHeaders(config) };
1391
+ if (accessToken) {
1392
+ headers["Authorization"] = `Bearer ${accessToken}`;
1393
+ }
1394
+ if (origin) {
1395
+ headers["Origin"] = origin;
1396
+ }
1397
+ const data = await apiRequest(
1398
+ `${config.backendUrls.payment}/payments/storefront/initiate`,
1399
+ {
1400
+ method: "POST",
1401
+ headers,
1402
+ body: JSON.stringify({
1403
+ amount: request.amount,
1404
+ currency: request.currency,
1405
+ // Same real backend default as getAvailablePaymentMethods above
1406
+ // (huma's own `default:"NG"` on this field) — omit rather than
1407
+ // hardcode a client-side copy of it.
1408
+ country_code: request.country_code,
1409
+ gateway: request.gateway,
1782
1410
  order_id: validOrderId,
1783
- ...request.metadata ?? {}
1784
- },
1785
- idempotency_key: request.idempotency_key
1786
- })
1787
- });
1788
- if (!response.ok) throw new Error("Failed to initiate payment");
1789
- const data = await response.json();
1411
+ quote_id: request.quote_id,
1412
+ metadata_json: {
1413
+ customer_email: request.customer_email,
1414
+ customer_name: request.customer_name ?? "",
1415
+ order_id: validOrderId,
1416
+ ...request.metadata ?? {}
1417
+ },
1418
+ idempotency_key: request.idempotency_key
1419
+ }),
1420
+ fallbackErrorMessage: "Failed to initiate payment"
1421
+ }
1422
+ );
1790
1423
  return {
1791
1424
  id: data.id,
1792
1425
  gateway_ref: data.gateway_ref,
@@ -1795,311 +1428,241 @@ async function initiatePayment(config, accessToken, request) {
1795
1428
  checkout_url: data.metadata_json?.checkout_url ?? ""
1796
1429
  };
1797
1430
  }
1798
- async function requestQuote(config, amount) {
1799
- const response = await fetch(`${config.backendUrls.payment}/payments/quote`, {
1800
- method: "POST",
1801
- headers: {
1802
- "Content-Type": "application/json",
1803
- "X-Storefront-Key": config.storefrontApiKey,
1804
- "X-Business-ID": config.businessId
1805
- },
1806
- body: JSON.stringify({ amount })
1807
- });
1808
- if (!response.ok) throw new Error("Failed to request quote");
1809
- const data = await response.json();
1810
- return data;
1811
- }
1812
- async function verifyTransaction(configOrReference, reference) {
1813
- if (typeof configOrReference === "string") {
1814
- const ref2 = configOrReference;
1815
- const response2 = await fetch(`/api/payments/verify/${ref2}`, {
1816
- method: "POST",
1817
- headers: { "Content-Type": "application/json" }
1818
- });
1819
- if (!response2.ok) throw new Error("Failed to verify transaction");
1820
- return response2.json();
1821
- }
1822
- const config = configOrReference;
1823
- const ref = reference || "";
1824
- const response = await fetch(`${config.backendUrls.payment}/payments/verify/${ref}`, {
1431
+ async function verifyTransaction(config, reference) {
1432
+ return apiRequest(`${config.backendUrls.payment}/payments/verify/${reference}`, {
1825
1433
  method: "POST",
1826
- headers: {
1827
- "Content-Type": "application/json",
1828
- "X-Storefront-Key": config.storefrontApiKey,
1829
- "X-Business-ID": config.businessId
1830
- }
1434
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
1435
+ fallbackErrorMessage: "Failed to verify transaction"
1831
1436
  });
1832
- if (!response.ok) throw new Error("Failed to verify transaction");
1833
- const data = await response.json();
1834
- return data;
1835
1437
  }
1836
1438
  async function getTransactionStatus(config, transactionId) {
1837
- const response = await fetch(`${config.backendUrls.payment}/payments/transactions/${transactionId}`, {
1838
- headers: {
1839
- "X-Storefront-Key": config.storefrontApiKey,
1840
- "X-Business-ID": config.businessId
1439
+ return apiRequest(`${config.backendUrls.payment}/payments/transactions/${transactionId}`, {
1440
+ headers: storefrontHeaders(config),
1441
+ fallbackErrorMessage: "Failed to get transaction status"
1442
+ });
1443
+ }
1444
+ async function getWalletBalance(config, accessToken) {
1445
+ return apiRequest(`${config.backendUrls.payment}/wallet/balance`, {
1446
+ headers: authHeaders(config, accessToken),
1447
+ fallbackErrorMessage: "Failed to fetch wallet balance"
1448
+ });
1449
+ }
1450
+ async function getWalletLedger(config, accessToken, params) {
1451
+ const page = params?.page ?? 1;
1452
+ const pageSize = params?.page_size ?? 20;
1453
+ return apiRequest(
1454
+ `${config.backendUrls.payment}/wallet/ledger?page=${page}&page_size=${pageSize}`,
1455
+ {
1456
+ headers: authHeaders(config, accessToken),
1457
+ fallbackErrorMessage: "Failed to fetch wallet ledger"
1841
1458
  }
1459
+ );
1460
+ }
1461
+ async function claimWalletCredit(config, accessToken, claimToken) {
1462
+ return apiRequest(`${config.backendUrls.payment}/wallet/claim`, {
1463
+ method: "POST",
1464
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1465
+ body: JSON.stringify({ claim_token: claimToken }),
1466
+ fallbackErrorMessage: "Failed to claim wallet credit"
1842
1467
  });
1843
- if (!response.ok) throw new Error("Failed to get transaction status");
1844
- const data = await response.json();
1845
- return data;
1846
1468
  }
1847
1469
  var paymentService = {
1470
+ getAvailablePaymentMethods,
1848
1471
  createDedicatedAccount,
1849
1472
  initiatePayment,
1850
- requestQuote,
1851
1473
  verifyTransaction,
1852
- getTransactionStatus
1474
+ getTransactionStatus,
1475
+ getWalletBalance,
1476
+ getWalletLedger,
1477
+ claimWalletCredit
1853
1478
  };
1854
1479
 
1855
- // src/services/consultation.service.ts
1856
- async function createConsultation(config, accessToken, payload) {
1857
- const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
1480
+ // src/services/logistics.service.ts
1481
+ async function getShippingRates(config, payload) {
1482
+ return apiRequest(`${config.backendUrls.store}/logistics/shipping/rates`, {
1858
1483
  method: "POST",
1859
- headers: {
1860
- "Content-Type": "application/json",
1861
- "Authorization": `Bearer ${accessToken}`,
1862
- "X-Storefront-Key": config.storefrontApiKey,
1863
- "X-Business-ID": config.businessId
1864
- },
1865
- body: JSON.stringify(payload)
1866
- });
1867
- if (!response.ok) throw new Error("Failed to create consultation");
1868
- return response.json();
1869
- }
1870
- async function getConsultations(config, accessToken) {
1871
- const response = await fetch(`${config.backendUrls.store}/social/consultations/`, {
1872
- headers: {
1873
- "Authorization": `Bearer ${accessToken}`,
1874
- "X-Storefront-Key": config.storefrontApiKey,
1875
- "X-Business-ID": config.businessId
1876
- }
1484
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
1485
+ body: JSON.stringify(payload),
1486
+ fallbackErrorMessage: "Failed to get shipping rates"
1877
1487
  });
1878
- if (!response.ok) throw new Error("Failed to get consultations");
1879
- return response.json();
1880
1488
  }
1881
- async function getConsultation(config, accessToken, id) {
1882
- const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}`, {
1883
- headers: {
1884
- "Authorization": `Bearer ${accessToken}`,
1885
- "X-Storefront-Key": config.storefrontApiKey,
1886
- "X-Business-ID": config.businessId
1887
- }
1489
+ async function validateShippingAddress(config, payload) {
1490
+ return apiRequest(`${config.backendUrls.store}/logistics/shipping-address/validate`, {
1491
+ method: "POST",
1492
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
1493
+ body: JSON.stringify(payload),
1494
+ fallbackErrorMessage: "Failed to validate shipping address"
1888
1495
  });
1889
- if (!response.ok) throw new Error("Failed to get consultation");
1890
- return response.json();
1891
1496
  }
1892
- async function sendMessage(config, accessToken, id, payload) {
1893
- await fetch(`${config.backendUrls.store}/social/consultations/${id}/messages`, {
1894
- method: "POST",
1895
- headers: {
1896
- "Content-Type": "application/json",
1897
- "Authorization": `Bearer ${accessToken}`,
1898
- "X-Storefront-Key": config.storefrontApiKey,
1899
- "X-Business-ID": config.businessId
1900
- },
1901
- body: JSON.stringify(payload)
1497
+ async function fetchLocationList(config, path, coords, fallbackErrorMessage) {
1498
+ const params = new URLSearchParams();
1499
+ if (coords) {
1500
+ params.set("latitude", String(coords.latitude));
1501
+ params.set("longitude", String(coords.longitude));
1502
+ }
1503
+ const qs = params.toString();
1504
+ return apiRequest(`${config.backendUrls.store}/logistics/${path}${qs ? `?${qs}` : ""}`, {
1505
+ headers: storefrontHeaders(config),
1506
+ fallbackErrorMessage
1902
1507
  });
1903
1508
  }
1904
- async function acceptQuote(config, accessToken, id, payload) {
1905
- const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/accept-quote`, {
1906
- method: "POST",
1907
- headers: {
1908
- "Content-Type": "application/json",
1909
- "Authorization": `Bearer ${accessToken}`,
1910
- "X-Storefront-Key": config.storefrontApiKey,
1911
- "X-Business-ID": config.businessId
1912
- },
1913
- body: JSON.stringify(payload)
1914
- });
1915
- if (!response.ok) throw new Error("Failed to accept quote");
1916
- return response.json();
1917
- }
1918
- async function rejectQuote(config, accessToken, id, reason) {
1919
- const response = await fetch(`${config.backendUrls.store}/social/consultations/${id}/reject-quote`, {
1920
- method: "POST",
1921
- headers: {
1922
- "Content-Type": "application/json",
1923
- "Authorization": `Bearer ${accessToken}`,
1924
- "X-Storefront-Key": config.storefrontApiKey,
1925
- "X-Business-ID": config.businessId
1926
- },
1927
- body: JSON.stringify({ reason })
1928
- });
1929
- if (!response.ok) throw new Error("Failed to reject quote");
1930
- return response.json();
1931
- }
1932
- var consultationService = {
1933
- createConsultation,
1934
- getConsultations,
1935
- getConsultation,
1936
- sendMessage,
1937
- acceptQuote,
1938
- rejectQuote
1939
- };
1940
-
1941
- // src/services/logistics.service.ts
1942
- async function getShippingRates(config, payload) {
1943
- const response = await fetch(`${config.backendUrls.store}/logistics/shipping/rates`, {
1509
+ async function listPickupLocations(config, coords) {
1510
+ return fetchLocationList(config, "pickup-locations", coords, "Failed to list pickup locations");
1511
+ }
1512
+ async function listBusinessLocations(config, coords) {
1513
+ return fetchLocationList(config, "locations", coords, "Failed to list business locations");
1514
+ }
1515
+ async function reverseGeocode(config, payload) {
1516
+ return apiRequest(`${config.backendUrls.store}/logistics/reverse-geocode`, {
1944
1517
  method: "POST",
1945
- headers: {
1946
- "Content-Type": "application/json",
1947
- "X-Storefront-Key": config.storefrontApiKey,
1948
- "X-Business-ID": config.businessId
1949
- },
1950
- body: JSON.stringify(payload)
1951
- });
1952
- if (!response.ok) throw new Error("Failed to get shipping rates");
1953
- return response.json();
1954
- }
1955
- async function getSellerShippingAddress(config) {
1956
- const response = await fetch(`${config.backendUrls.store}/logistics/shipping-address`, {
1957
- headers: {
1958
- "X-Storefront-Key": config.storefrontApiKey,
1959
- "X-Business-ID": config.businessId
1960
- }
1518
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
1519
+ body: JSON.stringify(payload),
1520
+ fallbackErrorMessage: "Failed to reverse geocode coordinates"
1961
1521
  });
1962
- if (!response.ok) throw new Error("Failed to get seller shipping address");
1963
- return response.json();
1964
1522
  }
1965
- async function validateShippingAddress(config, payload) {
1966
- const response = await fetch(`${config.backendUrls.store}/logistics/shipping-address/validate`, {
1523
+ async function decodePlusCode(config, payload) {
1524
+ return apiRequest(`${config.backendUrls.store}/logistics/plus-code/decode`, {
1967
1525
  method: "POST",
1968
- headers: {
1969
- "Content-Type": "application/json",
1970
- "X-Storefront-Key": config.storefrontApiKey,
1971
- "X-Business-ID": config.businessId
1972
- },
1973
- body: JSON.stringify(payload)
1526
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
1527
+ body: JSON.stringify(payload),
1528
+ fallbackErrorMessage: "Failed to decode Plus Code"
1529
+ });
1530
+ }
1531
+ async function autocompleteAddress(config, q, country) {
1532
+ const params = new URLSearchParams();
1533
+ params.set("q", q);
1534
+ if (country) params.set("country", country);
1535
+ return apiRequest(`${config.backendUrls.store}/logistics/address/autocomplete?${params.toString()}`, {
1536
+ headers: storefrontHeaders(config),
1537
+ fallbackErrorMessage: "Failed to autocomplete address"
1974
1538
  });
1975
- if (!response.ok) throw new Error("Failed to validate shipping address");
1976
- return response.json();
1977
1539
  }
1978
1540
  var logisticsService = {
1979
1541
  getShippingRates,
1980
- getSellerShippingAddress,
1981
- validateShippingAddress
1542
+ validateShippingAddress,
1543
+ listPickupLocations,
1544
+ listBusinessLocations,
1545
+ reverseGeocode,
1546
+ decodePlusCode,
1547
+ autocompleteAddress
1982
1548
  };
1983
1549
 
1984
1550
  // src/services/bespoke.service.ts
1985
1551
  async function checkAvailability(config, product_id) {
1986
- const response = await fetch(`${config.backendUrls.store}/bespoke/availability/${product_id}`, {
1987
- headers: {
1988
- "X-Storefront-Key": config.storefrontApiKey,
1989
- "X-Business-ID": config.businessId
1990
- }
1552
+ return apiRequest(`${config.backendUrls.store}/bespoke/capacity/availability/${product_id}`, {
1553
+ headers: storefrontHeaders(config),
1554
+ fallbackErrorMessage: "Failed to check bespoke availability"
1555
+ });
1556
+ }
1557
+ async function approveBespokeDeliverable(config, accessToken, orderId) {
1558
+ return apiRequest(`${config.backendUrls.store}/orders/${orderId}/bespoke/approve`, {
1559
+ method: "POST",
1560
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1561
+ body: JSON.stringify({}),
1562
+ fallbackErrorMessage: "Failed to approve deliverable"
1563
+ });
1564
+ }
1565
+ async function requestBespokeRevision(config, accessToken, orderId, notes) {
1566
+ return apiRequest(`${config.backendUrls.store}/orders/${orderId}/bespoke/request-revision`, {
1567
+ method: "POST",
1568
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1569
+ body: JSON.stringify({ notes }),
1570
+ fallbackErrorMessage: "Failed to request revision"
1991
1571
  });
1992
- if (!response.ok) throw new Error("Failed to check bespoke availability");
1993
- return response.json();
1994
1572
  }
1995
1573
  var bespokeService = {
1996
- checkAvailability
1574
+ checkAvailability,
1575
+ approveBespokeDeliverable,
1576
+ requestBespokeRevision
1997
1577
  };
1998
1578
 
1999
1579
  // src/services/service-booking.service.ts
2000
- async function getAvailableSlots(config, product_id, date_from, date_to) {
2001
- const response = await fetch(
2002
- `${config.backendUrls.store}/service/available-slots/${product_id}?date_from=${date_from}&date_to=${date_to}`,
1580
+ async function getAvailableSlots(config, productId, date, params) {
1581
+ const query = new URLSearchParams({ date });
1582
+ if (params?.staffId) query.set("staff_id", params.staffId);
1583
+ if (params?.locationId) query.set("location_id", params.locationId);
1584
+ if (params?.customerLatitude !== void 0) query.set("customer_latitude", String(params.customerLatitude));
1585
+ if (params?.customerLongitude !== void 0) query.set("customer_longitude", String(params.customerLongitude));
1586
+ return apiRequest(
1587
+ `${config.backendUrls.store}/catalog/products/${productId}/available-slots?${query.toString()}`,
2003
1588
  {
2004
- headers: {
2005
- "X-Storefront-Key": config.storefrontApiKey,
2006
- "X-Business-ID": config.businessId
2007
- }
1589
+ headers: storefrontHeaders(config),
1590
+ fallbackErrorMessage: "Failed to get available slots"
2008
1591
  }
2009
1592
  );
2010
- if (!response.ok) throw new Error("Failed to get available slots");
2011
- return response.json();
2012
1593
  }
2013
1594
  async function bookAppointment(config, accessToken, payload) {
2014
- const response = await fetch(`${config.backendUrls.store}/service/appointments/`, {
1595
+ return apiRequest(`${config.backendUrls.store}/service/bookings/schedule`, {
2015
1596
  method: "POST",
2016
- headers: {
2017
- "Content-Type": "application/json",
2018
- "Authorization": `Bearer ${accessToken}`,
2019
- "X-Storefront-Key": config.storefrontApiKey,
2020
- "X-Business-ID": config.businessId
2021
- },
2022
- body: JSON.stringify(payload)
2023
- });
2024
- if (!response.ok) throw new Error("Failed to book appointment");
2025
- return response.json();
2026
- }
2027
- async function getAppointments(config, accessToken) {
2028
- const response = await fetch(`${config.backendUrls.store}/service/bookings/my`, {
2029
- headers: {
2030
- "Authorization": `Bearer ${accessToken}`,
2031
- "X-Storefront-Key": config.storefrontApiKey,
2032
- "X-Business-ID": config.businessId
2033
- }
1597
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1598
+ body: JSON.stringify(payload),
1599
+ fallbackErrorMessage: "Failed to book appointment"
1600
+ });
1601
+ }
1602
+ async function getAppointments(config, accessToken, params) {
1603
+ const query = new URLSearchParams();
1604
+ if (params?.status) query.set("status", params.status);
1605
+ if (params?.page) query.set("page", String(params.page));
1606
+ if (params?.page_size) query.set("page_size", String(params.page_size));
1607
+ return apiRequest(`${config.backendUrls.store}/service/bookings/my?${query.toString()}`, {
1608
+ headers: authHeaders(config, accessToken),
1609
+ fallbackErrorMessage: "Failed to get appointments"
2034
1610
  });
2035
- if (!response.ok) throw new Error("Failed to get appointments");
2036
- return response.json();
2037
1611
  }
2038
1612
  async function getAppointment(config, accessToken, id) {
2039
- const response = await fetch(`${config.backendUrls.store}/service/bookings/${id}`, {
2040
- headers: {
2041
- "Authorization": `Bearer ${accessToken}`,
2042
- "X-Storefront-Key": config.storefrontApiKey,
2043
- "X-Business-ID": config.businessId
2044
- }
1613
+ return apiRequest(`${config.backendUrls.store}/service/bookings/${id}`, {
1614
+ headers: authHeaders(config, accessToken),
1615
+ fallbackErrorMessage: "Failed to get appointment"
2045
1616
  });
2046
- if (!response.ok) throw new Error("Failed to get appointment");
2047
- return response.json();
2048
1617
  }
2049
- async function cancelAppointment(config, accessToken, id) {
2050
- await fetch(`${config.backendUrls.store}/service/bookings/${id}`, {
2051
- method: "DELETE",
2052
- headers: {
2053
- "Authorization": `Bearer ${accessToken}`,
2054
- "X-Storefront-Key": config.storefrontApiKey,
2055
- "X-Business-ID": config.businessId
2056
- }
1618
+ async function cancelAppointment(config, accessToken, id, payload) {
1619
+ return apiRequest(`${config.backendUrls.store}/service/bookings/${id}/cancel`, {
1620
+ method: "POST",
1621
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1622
+ body: JSON.stringify(payload ?? {}),
1623
+ fallbackErrorMessage: "Failed to cancel appointment"
2057
1624
  });
2058
1625
  }
2059
- async function getDeliverables(config, accessToken, order_id) {
2060
- const response = await fetch(`${config.backendUrls.store}/service/projects/${order_id}/deliverables/`, {
2061
- headers: {
2062
- "Authorization": `Bearer ${accessToken}`,
2063
- "X-Storefront-Key": config.storefrontApiKey,
2064
- "X-Business-ID": config.businessId
2065
- }
1626
+ async function rescheduleAppointment(config, accessToken, id, payload) {
1627
+ return apiRequest(`${config.backendUrls.store}/service/bookings/${id}/reschedule`, {
1628
+ method: "POST",
1629
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1630
+ body: JSON.stringify(payload),
1631
+ fallbackErrorMessage: "Failed to reschedule appointment"
2066
1632
  });
2067
- if (!response.ok) throw new Error("Failed to get deliverables");
2068
- return response.json();
2069
1633
  }
2070
- async function approveDeliverable(config, accessToken, order_id, deliverable_id) {
2071
- const response = await fetch(
2072
- `${config.backendUrls.store}/service/projects/${order_id}/deliverables/${deliverable_id}/approve`,
2073
- {
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({ approved: true })
2082
- }
2083
- );
2084
- if (!response.ok) throw new Error("Failed to approve deliverable");
2085
- return response.json();
1634
+ async function disputeAppointment(config, accessToken, id, payload) {
1635
+ return apiRequest(`${config.backendUrls.store}/service/bookings/${id}/dispute`, {
1636
+ method: "POST",
1637
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1638
+ body: JSON.stringify(payload),
1639
+ fallbackErrorMessage: "Failed to open dispute"
1640
+ });
1641
+ }
1642
+ async function confirmAppointmentCompletion(config, accessToken, id, payload) {
1643
+ return apiRequest(`${config.backendUrls.store}/service/bookings/${id}/confirm`, {
1644
+ method: "POST",
1645
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1646
+ body: JSON.stringify(payload ?? {}),
1647
+ fallbackErrorMessage: "Failed to confirm completion"
1648
+ });
1649
+ }
1650
+ async function getMilestones(config, accessToken, bookingId) {
1651
+ return apiRequest(`${config.backendUrls.store}/service/bookings/${bookingId}/milestones`, {
1652
+ headers: authHeaders(config, accessToken),
1653
+ fallbackErrorMessage: "Failed to get milestones"
1654
+ });
2086
1655
  }
2087
- async function requestRevision(config, accessToken, order_id, deliverable_id, feedback) {
2088
- const response = await fetch(
2089
- `${config.backendUrls.store}/service/projects/${order_id}/deliverables/${deliverable_id}/revision`,
1656
+ async function approveMilestone(config, accessToken, bookingId, milestoneId, payload) {
1657
+ return apiRequest(
1658
+ `${config.backendUrls.store}/service/bookings/${bookingId}/milestones/${milestoneId}/approve`,
2090
1659
  {
2091
1660
  method: "POST",
2092
- headers: {
2093
- "Content-Type": "application/json",
2094
- "Authorization": `Bearer ${accessToken}`,
2095
- "X-Storefront-Key": config.storefrontApiKey,
2096
- "X-Business-ID": config.businessId
2097
- },
2098
- body: JSON.stringify({ approved: false, feedback })
1661
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1662
+ body: JSON.stringify(payload ?? {}),
1663
+ fallbackErrorMessage: "Failed to approve milestone"
2099
1664
  }
2100
1665
  );
2101
- if (!response.ok) throw new Error("Failed to request revision");
2102
- return response.json();
2103
1666
  }
2104
1667
  var serviceBookingService = {
2105
1668
  getAvailableSlots,
@@ -2107,41 +1670,111 @@ var serviceBookingService = {
2107
1670
  getAppointments,
2108
1671
  getAppointment,
2109
1672
  cancelAppointment,
2110
- getDeliverables,
2111
- approveDeliverable,
2112
- requestRevision
1673
+ rescheduleAppointment,
1674
+ disputeAppointment,
1675
+ confirmAppointmentCompletion,
1676
+ getMilestones,
1677
+ approveMilestone
2113
1678
  };
2114
1679
 
2115
1680
  // src/services/notifications.service.ts
1681
+ function bearerHeaders(accessToken) {
1682
+ return { Authorization: `Bearer ${accessToken}` };
1683
+ }
2116
1684
  async function sendContactEmail(config, payload) {
2117
- const response = await fetch(`${config.backendUrls.notifications}/contact/send-contact-email`, {
1685
+ return apiRequest(`${config.backendUrls.notifications}/contact/send-contact-email`, {
2118
1686
  method: "POST",
2119
- headers: {
2120
- "Content-Type": "application/json",
2121
- "X-Storefront-Key": config.storefrontApiKey,
2122
- "X-Business-ID": config.businessId
2123
- },
2124
- body: JSON.stringify(payload)
1687
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
1688
+ body: JSON.stringify(payload),
1689
+ fallbackErrorMessage: "Failed to send contact email"
2125
1690
  });
2126
- if (!response.ok) throw new Error("Failed to send contact email");
2127
- return response.json();
2128
1691
  }
2129
1692
  async function sendContactConfirmation(config, payload) {
2130
- const response = await fetch(`${config.backendUrls.notifications}/contact/send-contact-confirmation`, {
1693
+ return apiRequest(`${config.backendUrls.notifications}/contact/send-contact-confirmation`, {
1694
+ method: "POST",
1695
+ headers: { ...JSON_HEADERS, ...storefrontHeaders(config) },
1696
+ body: JSON.stringify(payload),
1697
+ fallbackErrorMessage: "Failed to send contact confirmation"
1698
+ });
1699
+ }
1700
+ async function getNotificationPreferences(config, accessToken) {
1701
+ return apiRequest(`${config.backendUrls.notifications}/notifications/preferences/`, {
1702
+ headers: bearerHeaders(accessToken),
1703
+ fallbackErrorMessage: "Failed to fetch notification preferences"
1704
+ });
1705
+ }
1706
+ async function updateNotificationPreferences(config, accessToken, payload) {
1707
+ return apiRequest(`${config.backendUrls.notifications}/notifications/preferences/`, {
1708
+ method: "PATCH",
1709
+ headers: { ...JSON_HEADERS, ...bearerHeaders(accessToken) },
1710
+ body: JSON.stringify(payload),
1711
+ fallbackErrorMessage: "Failed to update notification preferences"
1712
+ });
1713
+ }
1714
+ async function getVapidPublicKey(config) {
1715
+ return apiRequest(`${config.backendUrls.notifications}/push/vapid-public-key`, {
1716
+ fallbackErrorMessage: "Failed to fetch VAPID public key"
1717
+ });
1718
+ }
1719
+ async function subscribeToPush(config, accessToken, params) {
1720
+ return apiRequest(`${config.backendUrls.notifications}/push/subscribe`, {
1721
+ method: "POST",
1722
+ headers: { ...JSON_HEADERS, ...bearerHeaders(accessToken) },
1723
+ body: JSON.stringify(params),
1724
+ fallbackErrorMessage: "Failed to subscribe to push notifications"
1725
+ });
1726
+ }
1727
+ async function unsubscribeFromPush(config, accessToken, endpoint) {
1728
+ return apiRequest(`${config.backendUrls.notifications}/push/subscribe`, {
1729
+ method: "DELETE",
1730
+ headers: { ...JSON_HEADERS, ...bearerHeaders(accessToken) },
1731
+ body: JSON.stringify({ endpoint }),
1732
+ fallbackErrorMessage: "Failed to unsubscribe from push notifications"
1733
+ });
1734
+ }
1735
+ async function getNotificationInbox(config, accessToken, params) {
1736
+ const query = new URLSearchParams();
1737
+ if (params?.page) query.set("page", String(params.page));
1738
+ if (params?.limit) query.set("limit", String(params.limit));
1739
+ if (params?.unread_only) query.set("unread_only", "true");
1740
+ return apiRequest(`${config.backendUrls.notifications}/notifications?${query.toString()}`, {
1741
+ headers: bearerHeaders(accessToken),
1742
+ fallbackErrorMessage: "Failed to fetch notifications"
1743
+ });
1744
+ }
1745
+ async function markNotificationRead(config, accessToken, notificationId) {
1746
+ return apiRequest(`${config.backendUrls.notifications}/notifications/${notificationId}/read`, {
1747
+ method: "POST",
1748
+ headers: bearerHeaders(accessToken),
1749
+ fallbackErrorMessage: "Failed to mark notification as read"
1750
+ });
1751
+ }
1752
+ async function markAllNotificationsRead(config, accessToken) {
1753
+ return apiRequest(`${config.backendUrls.notifications}/notifications/mark-all-read`, {
1754
+ method: "POST",
1755
+ headers: bearerHeaders(accessToken),
1756
+ fallbackErrorMessage: "Failed to mark all notifications as read"
1757
+ });
1758
+ }
1759
+ async function trackNotificationClick(config, accessToken, notificationId) {
1760
+ return apiRequest(`${config.backendUrls.notifications}/notifications/${notificationId}/click`, {
2131
1761
  method: "POST",
2132
- headers: {
2133
- "Content-Type": "application/json",
2134
- "X-Storefront-Key": config.storefrontApiKey,
2135
- "X-Business-ID": config.businessId
2136
- },
2137
- body: JSON.stringify(payload)
1762
+ headers: bearerHeaders(accessToken),
1763
+ fallbackErrorMessage: "Failed to track notification click"
2138
1764
  });
2139
- if (!response.ok) throw new Error("Failed to send contact confirmation");
2140
- return response.json();
2141
1765
  }
2142
1766
  var notificationsService = {
2143
1767
  sendContactEmail,
2144
- sendContactConfirmation
1768
+ sendContactConfirmation,
1769
+ getNotificationPreferences,
1770
+ updateNotificationPreferences,
1771
+ getVapidPublicKey,
1772
+ subscribeToPush,
1773
+ unsubscribeFromPush,
1774
+ getNotificationInbox,
1775
+ markNotificationRead,
1776
+ markAllNotificationsRead,
1777
+ trackNotificationClick
2145
1778
  };
2146
1779
 
2147
1780
  // src/services/app.service.ts
@@ -2159,34 +1792,22 @@ async function googleTranslate(text, target, source = "en") {
2159
1792
 
2160
1793
  // src/services/config.service.ts
2161
1794
  async function getSupportedLanguages(config) {
2162
- const response = await fetch(`${config.backendUrls.payment}/config/supported-languages`, {
2163
- headers: {
2164
- "X-Storefront-Key": config.storefrontApiKey,
2165
- "X-Business-ID": config.businessId
2166
- }
1795
+ return apiRequest(`${config.backendUrls.payment}/config/supported-languages`, {
1796
+ headers: storefrontHeaders(config),
1797
+ fallbackErrorMessage: "Failed to get supported languages"
2167
1798
  });
2168
- if (!response.ok) throw new Error("Failed to get supported languages");
2169
- return response.json();
2170
1799
  }
2171
1800
  async function getSupportedCurrencies(config) {
2172
- const response = await fetch(`${config.backendUrls.payment}/config/supported-currencies`, {
2173
- headers: {
2174
- "X-Storefront-Key": config.storefrontApiKey,
2175
- "X-Business-ID": config.businessId
2176
- }
1801
+ return apiRequest(`${config.backendUrls.payment}/config/supported-currencies`, {
1802
+ headers: storefrontHeaders(config),
1803
+ fallbackErrorMessage: "Failed to get supported currencies"
2177
1804
  });
2178
- if (!response.ok) throw new Error("Failed to get supported currencies");
2179
- return response.json();
2180
1805
  }
2181
1806
  async function getBusinessConfig(config) {
2182
- const response = await fetch(`${config.backendUrls.auth}/internal/businesses/${config.businessId}/`, {
2183
- headers: {
2184
- "X-Storefront-Key": config.storefrontApiKey,
2185
- "X-Business-ID": config.businessId
2186
- }
1807
+ return apiRequest(`${config.backendUrls.auth}/internal/businesses/${config.businessId}/`, {
1808
+ headers: storefrontHeaders(config),
1809
+ fallbackErrorMessage: "Failed to get business config"
2187
1810
  });
2188
- if (!response.ok) throw new Error("Failed to get business config");
2189
- return response.json();
2190
1811
  }
2191
1812
  var configService = {
2192
1813
  getSupportedLanguages,
@@ -2195,134 +1816,293 @@ var configService = {
2195
1816
  };
2196
1817
 
2197
1818
  // src/services/cms.service.ts
2198
- async function listCmsEntries(config, modelSlug, params) {
1819
+ async function listCmsEntries(config, businessUuid, modelSlug, params) {
2199
1820
  const queryParams = new URLSearchParams();
2200
1821
  queryParams.set("page", (params?.page || 1).toString());
2201
1822
  queryParams.set("page_size", (params?.page_size || 50).toString());
2202
- const response = await fetch(
2203
- `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries?${queryParams.toString()}`,
1823
+ return apiRequest(
1824
+ `${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries?${queryParams.toString()}`,
2204
1825
  {
2205
- headers: {
2206
- "X-Storefront-Key": config.storefrontApiKey,
2207
- "X-Business-ID": config.businessId
2208
- }
1826
+ headers: storefrontHeaders(config),
1827
+ fallbackErrorMessage: "Failed to list CMS entries"
2209
1828
  }
2210
1829
  );
2211
- if (!response.ok) throw new Error("Failed to list CMS entries");
2212
- return response.json();
2213
1830
  }
2214
- async function getCmsEntry(config, modelSlug, entryId) {
2215
- const response = await fetch(
2216
- `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
1831
+ async function getCmsEntry(config, businessUuid, modelSlug, entryId) {
1832
+ return apiRequest(
1833
+ `${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries/${entryId}`,
2217
1834
  {
2218
- headers: {
2219
- "X-Storefront-Key": config.storefrontApiKey,
2220
- "X-Business-ID": config.businessId
2221
- }
1835
+ headers: storefrontHeaders(config),
1836
+ fallbackErrorMessage: "Failed to get CMS entry"
2222
1837
  }
2223
1838
  );
2224
- if (!response.ok) throw new Error("Failed to get CMS entry");
2225
- return response.json();
2226
1839
  }
2227
- async function createCmsEntry(config, accessToken, modelSlug, params) {
2228
- const response = await fetch(
2229
- `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries`,
1840
+ async function createCmsEntry(config, businessUuid, accessToken, modelSlug, params) {
1841
+ return apiRequest(
1842
+ `${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries`,
2230
1843
  {
2231
1844
  method: "POST",
2232
- headers: {
2233
- "Content-Type": "application/json",
2234
- "Authorization": `Bearer ${accessToken}`,
2235
- "X-Storefront-Key": config.storefrontApiKey,
2236
- "X-Business-ID": config.businessId
2237
- },
2238
- body: JSON.stringify(params)
1845
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1846
+ body: JSON.stringify(params),
1847
+ fallbackErrorMessage: "Failed to create CMS entry"
2239
1848
  }
2240
1849
  );
2241
- if (!response.ok) throw new Error("Failed to create CMS entry");
2242
- return response.json();
2243
1850
  }
2244
- async function updateCmsEntry(config, accessToken, modelSlug, entryId, params) {
2245
- const response = await fetch(
2246
- `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
1851
+ async function updateCmsEntry(config, businessUuid, accessToken, modelSlug, entryId, params) {
1852
+ return apiRequest(
1853
+ `${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries/${entryId}`,
2247
1854
  {
2248
1855
  method: "PUT",
2249
- headers: {
2250
- "Content-Type": "application/json",
2251
- "Authorization": `Bearer ${accessToken}`,
2252
- "X-Storefront-Key": config.storefrontApiKey,
2253
- "X-Business-ID": config.businessId
2254
- },
2255
- body: JSON.stringify(params)
1856
+ headers: { ...JSON_HEADERS, ...authHeaders(config, accessToken) },
1857
+ body: JSON.stringify(params),
1858
+ fallbackErrorMessage: "Failed to update CMS entry"
2256
1859
  }
2257
1860
  );
2258
- if (!response.ok) throw new Error("Failed to update CMS entry");
2259
- return response.json();
2260
1861
  }
2261
- async function deleteCmsEntry(config, accessToken, modelSlug, entryId) {
2262
- const response = await fetch(
2263
- `${config.backendUrls.cms}/sdk/${config.businessId}/${modelSlug}/entries/${entryId}`,
1862
+ async function deleteCmsEntry(config, businessUuid, accessToken, modelSlug, entryId) {
1863
+ await apiRequest(
1864
+ `${config.backendUrls.cms}/sdk/${businessUuid}/${modelSlug}/entries/${entryId}`,
2264
1865
  {
2265
1866
  method: "DELETE",
2266
- headers: {
2267
- "Authorization": `Bearer ${accessToken}`,
2268
- "X-Storefront-Key": config.storefrontApiKey,
2269
- "X-Business-ID": config.businessId
2270
- }
1867
+ headers: authHeaders(config, accessToken),
1868
+ fallbackErrorMessage: "Failed to delete CMS entry"
2271
1869
  }
2272
1870
  );
2273
- if (!response.ok) throw new Error("Failed to delete CMS entry");
1871
+ }
1872
+
1873
+ // src/services/legal.service.ts
1874
+ async function getMerchantLegalDocument(config, businessUuid, documentType, fetchOptions) {
1875
+ if (!businessUuid || !config?.backendUrls?.cms) return null;
1876
+ try {
1877
+ const res = await fetch(
1878
+ `${config.backendUrls.cms}/cms/legal/storefront/${businessUuid}/${documentType}`,
1879
+ fetchOptions
1880
+ );
1881
+ if (!res.ok) return null;
1882
+ return await res.json();
1883
+ } catch {
1884
+ return null;
1885
+ }
1886
+ }
1887
+
1888
+ // src/services/review.service.ts
1889
+ function fetchWithConfig(url, config, options = {}) {
1890
+ const headers = {
1891
+ ...JSON_HEADERS,
1892
+ Accept: "application/json",
1893
+ ...options.headers
1894
+ };
1895
+ if (config.storefrontApiKey) headers["X-Storefront-Key"] = config.storefrontApiKey;
1896
+ if (config.businessId) headers["X-Business-ID"] = config.businessId;
1897
+ if (config.authToken) headers["Authorization"] = `Bearer ${config.authToken}`;
1898
+ return apiRequest(url, { ...options, headers, fallbackErrorMessage: options.fallbackErrorMessage ?? "Request failed" });
1899
+ }
1900
+ async function createReview(reviewData, config) {
1901
+ const url = `${config.backendUrls.crm}/reviews`;
1902
+ return fetchWithConfig(url, config, {
1903
+ method: "POST",
1904
+ body: JSON.stringify(reviewData),
1905
+ fallbackErrorMessage: "Failed to create review"
1906
+ });
1907
+ }
1908
+ async function updateReview(reviewId, reviewData, config) {
1909
+ const url = `${config.backendUrls.crm}/reviews/${reviewId}`;
1910
+ return fetchWithConfig(url, config, {
1911
+ method: "PUT",
1912
+ body: JSON.stringify(reviewData),
1913
+ fallbackErrorMessage: "Failed to update review"
1914
+ });
1915
+ }
1916
+ async function getProductReviews(productId, params = {}, config) {
1917
+ const queryParams = new URLSearchParams();
1918
+ if (params.page) queryParams.append("page", params.page.toString());
1919
+ if (params.page_size) queryParams.append("page_size", params.page_size.toString());
1920
+ if (params.moderation_status) queryParams.append("moderation_status", params.moderation_status);
1921
+ const url = `${config.backendUrls.crm}/products/${productId}/reviews?${queryParams.toString()}`;
1922
+ return fetchWithConfig(url, config, { fallbackErrorMessage: "Failed to fetch product reviews" });
1923
+ }
1924
+ async function createComment(commentData, config) {
1925
+ const url = `${config.backendUrls.crm}/comments`;
1926
+ return fetchWithConfig(url, config, {
1927
+ method: "POST",
1928
+ body: JSON.stringify(commentData),
1929
+ fallbackErrorMessage: "Failed to create comment"
1930
+ });
1931
+ }
1932
+ async function updateComment(commentId, commentData, config) {
1933
+ const url = `${config.backendUrls.crm}/comments/${commentId}`;
1934
+ return fetchWithConfig(url, config, {
1935
+ method: "PUT",
1936
+ body: JSON.stringify(commentData),
1937
+ fallbackErrorMessage: "Failed to update comment"
1938
+ });
1939
+ }
1940
+ async function getProductComments(productId, params = {}, config) {
1941
+ const queryParams = new URLSearchParams();
1942
+ if (params.page) queryParams.append("page", params.page.toString());
1943
+ if (params.page_size) queryParams.append("page_size", params.page_size.toString());
1944
+ if (params.moderation_status) queryParams.append("moderation_status", params.moderation_status);
1945
+ const url = `${config.backendUrls.crm}/products/${productId}/comments?${queryParams.toString()}`;
1946
+ return fetchWithConfig(url, config, { fallbackErrorMessage: "Failed to fetch product comments" });
1947
+ }
1948
+ async function getPendingReviews(config) {
1949
+ const url = `${config.backendUrls.crm}/admin/reviews/pending`;
1950
+ return fetchWithConfig(url, config, { fallbackErrorMessage: "Failed to fetch pending reviews" });
1951
+ }
1952
+ async function getPendingComments(config) {
1953
+ const url = `${config.backendUrls.crm}/admin/comments/pending`;
1954
+ return fetchWithConfig(url, config, { fallbackErrorMessage: "Failed to fetch pending comments" });
1955
+ }
1956
+ async function moderateReview(reviewId, action, config) {
1957
+ const url = `${config.backendUrls.crm}/admin/reviews/${reviewId}/moderate`;
1958
+ return fetchWithConfig(url, config, {
1959
+ method: "POST",
1960
+ body: JSON.stringify(action),
1961
+ fallbackErrorMessage: "Failed to moderate review"
1962
+ });
1963
+ }
1964
+ async function moderateComment(commentId, action, config) {
1965
+ const url = `${config.backendUrls.crm}/admin/comments/${commentId}/moderate`;
1966
+ return fetchWithConfig(url, config, {
1967
+ method: "POST",
1968
+ body: JSON.stringify(action),
1969
+ fallbackErrorMessage: "Failed to moderate comment"
1970
+ });
1971
+ }
1972
+ async function merchantReplyToReview(reviewId, replyData, config) {
1973
+ const url = `${config.backendUrls.crm}/admin/reviews/${reviewId}/reply`;
1974
+ return fetchWithConfig(url, config, {
1975
+ method: "POST",
1976
+ body: JSON.stringify(replyData),
1977
+ fallbackErrorMessage: "Failed to post merchant reply"
1978
+ });
1979
+ }
1980
+
1981
+ // src/services/media.service.ts
1982
+ async function uploadMediaFile(params) {
1983
+ const presignedUrlEndpoint = params.presignedUrlEndpoint ?? "/api/auth/media/presigned-url";
1984
+ const confirmUploadEndpoint = params.confirmUploadEndpoint ?? "/api/auth/media/confirm-upload";
1985
+ const { presigned_url, storage_path } = await apiRequest(presignedUrlEndpoint, {
1986
+ method: "POST",
1987
+ headers: JSON_HEADERS,
1988
+ credentials: "include",
1989
+ body: JSON.stringify({
1990
+ filename: params.file.name,
1991
+ content_type: params.file.type,
1992
+ context: params.context,
1993
+ entity_id: params.entityId,
1994
+ affiliation: params.affiliation,
1995
+ owner_id: params.ownerId
1996
+ }),
1997
+ fallbackErrorMessage: "Could not start upload"
1998
+ });
1999
+ const putResponse = await fetch(presigned_url, {
2000
+ method: "PUT",
2001
+ headers: { "Content-Type": params.file.type },
2002
+ body: params.file
2003
+ });
2004
+ if (!putResponse.ok) {
2005
+ throw new Error(`Failed to upload ${params.file.name}`);
2006
+ }
2007
+ return apiRequest(confirmUploadEndpoint, {
2008
+ method: "POST",
2009
+ headers: JSON_HEADERS,
2010
+ credentials: "include",
2011
+ body: JSON.stringify({
2012
+ storage_path,
2013
+ entity_id: params.entityId,
2014
+ original_filename: params.file.name,
2015
+ content_type: params.file.type,
2016
+ size: params.file.size,
2017
+ context: params.context,
2018
+ affiliation: params.affiliation,
2019
+ owner_id: params.ownerId
2020
+ }),
2021
+ fallbackErrorMessage: `Could not confirm upload of ${params.file.name}`
2022
+ });
2023
+ }
2024
+ async function uploadMediaFiles(files, params) {
2025
+ const assets = [];
2026
+ const errors = [];
2027
+ for (const file of files) {
2028
+ try {
2029
+ assets.push(await uploadMediaFile({ ...params, file }));
2030
+ } catch (err) {
2031
+ errors.push({ file: file.name, message: err instanceof Error ? err.message : "Upload failed" });
2032
+ }
2033
+ }
2034
+ return { assets, errors };
2274
2035
  }
2275
2036
  // Annotate the CommonJS export names for ESM import in node:
2276
2037
  0 && (module.exports = {
2277
- acceptQuote,
2278
2038
  addToCart,
2279
2039
  addToGuestCart,
2280
2040
  addToWishlist,
2281
- approveDeliverable,
2041
+ approveBespokeDeliverable,
2042
+ approveMilestone,
2043
+ autocompleteAddress,
2282
2044
  bespokeService,
2283
2045
  bookAppointment,
2284
2046
  cancelAppointment,
2285
2047
  cancelOrder,
2048
+ changePassword,
2286
2049
  checkAvailability,
2287
2050
  checkInWishlist,
2051
+ claimWalletCredit,
2288
2052
  clearCart,
2289
2053
  clearGuestCart,
2290
2054
  clearTokens,
2291
2055
  configService,
2292
- consultationService,
2056
+ confirmAppointmentCompletion,
2057
+ confirmMediaUpload,
2058
+ createBespokeOrder,
2293
2059
  createCmsEntry,
2060
+ createComment,
2294
2061
  createConsultation,
2062
+ createCustomerAddress,
2295
2063
  createDedicatedAccount,
2064
+ createFeedback,
2296
2065
  createOrder,
2066
+ createReview,
2067
+ createServiceBookingOrder,
2068
+ deactivateCustomerAccount,
2069
+ decodePlusCode,
2297
2070
  deleteCmsEntry,
2071
+ deleteCustomerAddress,
2072
+ disputeAppointment,
2298
2073
  findOrder,
2299
- findOrderByToken,
2074
+ forgotPasswordCustomer,
2300
2075
  getAppointment,
2301
2076
  getAppointments,
2302
2077
  getAuthUser,
2078
+ getAvailablePaymentMethods,
2303
2079
  getAvailableSlots,
2304
2080
  getBusinessConfig,
2305
2081
  getCart,
2306
2082
  getCmsEntry,
2307
- getConsultation,
2308
- getConsultations,
2309
- getDeliverables,
2083
+ getCustomerAddresses,
2310
2084
  getFeaturedProducts,
2311
2085
  getGuestCart,
2312
- getGuestCartCount,
2313
2086
  getGuestCartProductType,
2314
- getGuestCartSubtotal,
2315
- getLatestProducts,
2316
- getLowStockProducts,
2317
2087
  getMe,
2088
+ getMerchantLegalDocument,
2089
+ getMilestones,
2090
+ getMyFeedback,
2318
2091
  getNewProducts,
2092
+ getNotificationInbox,
2093
+ getNotificationPreferences,
2319
2094
  getOnSaleProducts,
2320
2095
  getOrders,
2096
+ getPendingComments,
2097
+ getPendingReviews,
2321
2098
  getPopularProducts,
2099
+ getPresignedUploadUrl,
2100
+ getProductComments,
2101
+ getProductReviews,
2322
2102
  getRecommendedProducts,
2323
- getSellerShippingAddress,
2324
2103
  getShippingRates,
2325
2104
  getStoredTokens,
2105
+ getStorefrontBusinessInfo,
2326
2106
  getStorefrontCollectionBySlug,
2327
2107
  getStorefrontCollections,
2328
2108
  getStorefrontProductBySlug,
@@ -2330,39 +2110,65 @@ async function deleteCmsEntry(config, accessToken, modelSlug, entryId) {
2330
2110
  getSupportedCurrencies,
2331
2111
  getSupportedLanguages,
2332
2112
  getTransactionStatus,
2113
+ getVapidPublicKey,
2114
+ getWalletBalance,
2115
+ getWalletLedger,
2333
2116
  getWishlist,
2334
2117
  googleTranslate,
2335
2118
  initiatePayment,
2119
+ listBusinessLocations,
2336
2120
  listCmsEntries,
2121
+ listPickupLocations,
2337
2122
  loginCustomer,
2338
2123
  logisticsService,
2339
2124
  logout,
2340
2125
  mapAuthUserToCustomer,
2126
+ markAllNotificationsRead,
2127
+ markNotificationRead,
2128
+ merchantReplyToReview,
2341
2129
  mergeGuestCart,
2342
2130
  mergeGuestCartIfPresent,
2131
+ moderateComment,
2132
+ moderateReview,
2343
2133
  notificationsService,
2344
2134
  paymentService,
2345
2135
  refreshToken,
2346
2136
  registerCustomer,
2347
- rejectQuote,
2348
2137
  removeFromCart,
2349
2138
  removeFromGuestCart,
2350
2139
  removeFromWishlist,
2351
2140
  removeProductFromWishlist,
2352
- requestQuote,
2353
- requestRevision,
2141
+ requestBespokeRevision,
2142
+ requestCustomerOtp,
2143
+ requestCustomerReactivation,
2144
+ rescheduleAppointment,
2145
+ resetPasswordCustomer,
2146
+ resolveDigitalDownload,
2147
+ resolveDigitalDownloadFile,
2148
+ reverseGeocode,
2354
2149
  sendContactConfirmation,
2355
2150
  sendContactEmail,
2356
- sendMessage,
2357
2151
  serviceBookingService,
2358
2152
  silentRefresh,
2359
2153
  storeTokens,
2154
+ subscribeToPush,
2155
+ trackNotificationClick,
2360
2156
  trackOrder,
2157
+ unsubscribeFromPush,
2361
2158
  updateCartItem,
2362
2159
  updateCmsEntry,
2160
+ updateComment,
2161
+ updateCustomerAddress,
2363
2162
  updateGuestCartItemQuantity,
2163
+ updateNotificationPreferences,
2364
2164
  updateProfile,
2165
+ updateReview,
2166
+ uploadMediaFile,
2167
+ uploadMediaFiles,
2168
+ validatePromoCode,
2365
2169
  validateShippingAddress,
2170
+ verifyCustomerOtp,
2171
+ verifyCustomerReactivation,
2366
2172
  verifySocialToken,
2367
2173
  verifyTransaction
2368
2174
  });