@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
@@ -0,0 +1,578 @@
1
+ /**
2
+ * Shipping and delivery types for the storefront
3
+ */
4
+ interface ShippingRate {
5
+ id: string;
6
+ carrier_name: string;
7
+ carrier_logo: string | null;
8
+ carrier_rate_description: string;
9
+ carrier_slug: string;
10
+ amount: number;
11
+ currency: string;
12
+ delivery_time: string;
13
+ delivery_eta: number;
14
+ pickup_time: string;
15
+ pickup_eta: number;
16
+ pickup_available: boolean;
17
+ dropoff_available?: boolean;
18
+ dropoff_required?: boolean;
19
+ /**
20
+ * Persisted, single-use, ~45min-TTL quote id — pass this (not `amount`)
21
+ * as `shipping_quote_id` at order creation. The backend re-reads the
22
+ * amount/carrier from the stored quote itself; a client-submitted
23
+ * shipping amount with no valid quote_id is rejected.
24
+ */
25
+ quote_id?: string;
26
+ }
27
+ interface ShippingRatesResponse {
28
+ status: boolean;
29
+ message: string;
30
+ data: ShippingRate[];
31
+ }
32
+ interface DeliveryAddress {
33
+ first_name: string;
34
+ last_name: string;
35
+ phone: string;
36
+ street: string;
37
+ city: string;
38
+ state: string;
39
+ lga?: string;
40
+ country: string;
41
+ postal?: string;
42
+ latitude?: number | null;
43
+ longitude?: number | null;
44
+ plus_code?: string | null;
45
+ coordinate_source?: CoordinateSource;
46
+ }
47
+ interface AddressValidationErrorData {
48
+ message: string;
49
+ errorType?: 'state' | 'city' | 'general';
50
+ cities?: Array<{
51
+ name: string;
52
+ city_id: string;
53
+ stateCode: string;
54
+ countryCode: string;
55
+ }>;
56
+ states?: Array<{
57
+ name: string;
58
+ code: string;
59
+ countryCode: string;
60
+ }>;
61
+ }
62
+ type CoordinateSource = 'pin_drop' | 'plus_code' | 'manual' | null;
63
+ interface GeolocationData {
64
+ latitude?: number | null;
65
+ longitude?: number | null;
66
+ plus_code?: string | null;
67
+ coordinate_source?: CoordinateSource;
68
+ }
69
+ interface ReverseGeocodeRequest {
70
+ latitude: number;
71
+ longitude: number;
72
+ }
73
+ interface ReverseGeocodeResponse {
74
+ city: string | null;
75
+ state: string | null;
76
+ country: string | null;
77
+ country_code: string | null;
78
+ display_name: string | null;
79
+ }
80
+ interface PlusCodeDecodeRequest {
81
+ plus_code: string;
82
+ }
83
+ interface PlusCodeDecodeResponse {
84
+ latitude: number;
85
+ longitude: number;
86
+ latitude_lo: number;
87
+ longitude_hi: number;
88
+ plus_code: string;
89
+ }
90
+ interface AddressSuggestion {
91
+ place_id: string;
92
+ display_name: string;
93
+ line1: string;
94
+ city: string | null;
95
+ state: string | null;
96
+ postal_code: string | null;
97
+ country: string | null;
98
+ country_code: string | null;
99
+ latitude: number | null;
100
+ longitude: number | null;
101
+ }
102
+ interface AddressAutocompleteResponse {
103
+ results: AddressSuggestion[];
104
+ }
105
+ interface ShippingAddressPayload extends GeolocationData {
106
+ first_name: string;
107
+ last_name: string;
108
+ phone: string;
109
+ address_line1: string;
110
+ address_line2?: string | null;
111
+ city: string;
112
+ state: string;
113
+ country: string;
114
+ postal_code?: string | null;
115
+ is_residential?: boolean;
116
+ }
117
+
118
+ declare enum ProductTypeEnum {
119
+ PHYSICAL = "physical",
120
+ DIGITAL = "digital",
121
+ SERVICE = "service",
122
+ BESPOKE = "bespoke"
123
+ }
124
+ type ProductType = ProductTypeEnum | "physical" | "digital" | "service" | "bespoke";
125
+ declare enum ServiceTypeEnum {
126
+ APPOINTMENT = "appointment",
127
+ PROJECT = "project",
128
+ RECURRING = "recurring"
129
+ }
130
+ type ServiceType = ServiceTypeEnum | 'appointment' | 'project' | 'recurring';
131
+ declare enum ServiceLocationTypeEnum {
132
+ REMOTE = "remote",
133
+ AT_BUSINESS = "at_business",
134
+ CUSTOMER_LOCATION = "customer_location"
135
+ }
136
+ type ServiceLocationType = ServiceLocationTypeEnum | 'remote' | 'at_business' | 'customer_location';
137
+ declare enum ServiceRecurringIntervalEnum {
138
+ WEEKLY = "weekly",
139
+ MONTHLY = "monthly",
140
+ YEARLY = "yearly"
141
+ }
142
+ type ServiceRecurringInterval = ServiceRecurringIntervalEnum | 'weekly' | 'monthly' | 'yearly' | '';
143
+ interface Address {
144
+ street: string;
145
+ city: string;
146
+ state: string;
147
+ country: string;
148
+ zip?: string;
149
+ }
150
+ interface Collection {
151
+ id: string;
152
+ business_id?: string;
153
+ name: string;
154
+ slug: string;
155
+ description?: string;
156
+ collection_type?: string;
157
+ /** Raw JSON string of smart-collection matching rules (kasuvia-store-management's own evaluation detail, never parsed client-side) — the real backend GraphQL field is a String scalar, not a structured object. */
158
+ rules?: string;
159
+ image_url?: string;
160
+ image_id?: string;
161
+ status?: string;
162
+ sort_order?: number;
163
+ created_at: string;
164
+ updated_at: string;
165
+ }
166
+ interface Inventory {
167
+ id: string;
168
+ product_id: string;
169
+ variant_id?: string;
170
+ quantity: number;
171
+ reserved: number;
172
+ reorder_point: number;
173
+ reorder_quantity: number;
174
+ track_quantity: boolean;
175
+ allow_backorder: boolean;
176
+ available?: number;
177
+ is_in_stock?: boolean;
178
+ is_low_stock?: boolean;
179
+ updated_at: string;
180
+ }
181
+ interface ProductVariant {
182
+ id: string;
183
+ product_id: string;
184
+ sku?: string;
185
+ attributes: Record<string, string>;
186
+ price?: number;
187
+ images: string[];
188
+ weight_kg?: number;
189
+ length_cm?: number;
190
+ width_cm?: number;
191
+ height_cm?: number;
192
+ is_active: boolean;
193
+ inventory?: Inventory;
194
+ }
195
+ interface CustomField {
196
+ label: string;
197
+ unit?: string;
198
+ required: boolean;
199
+ /** "text" (free text/number input) or "choice" (customer picks from
200
+ * `options`) — matches kasuvia-store-management's CustomFieldSchema. */
201
+ field_type: "text" | "choice";
202
+ /** Only meaningful when field_type is "choice" - the pick list a
203
+ * merchant configured. Always [] for a "text" field. */
204
+ options: string[];
205
+ }
206
+ /** One file of a DIGITAL/MIXED product (kasuvia-store-management's ProductDigitalFile) — replaces the old dropped single `digital_file_key` scalar. */
207
+ interface ProductDigitalFile {
208
+ id: string;
209
+ file_key: string;
210
+ display_name: string;
211
+ sort_order: number;
212
+ }
213
+ interface Product {
214
+ id: string;
215
+ business_id: string;
216
+ name: string;
217
+ slug?: string;
218
+ description?: string;
219
+ brand?: string;
220
+ product_type: ProductType;
221
+ requires_shipping: boolean;
222
+ is_consumable: boolean;
223
+ is_bespoke: boolean;
224
+ is_physical?: boolean;
225
+ is_non_returnable?: boolean;
226
+ deposit_percentage?: number;
227
+ base_price: number;
228
+ currency: string;
229
+ sale_price?: number;
230
+ sale_start?: string;
231
+ sale_end?: string;
232
+ images: string[];
233
+ tags: string[];
234
+ custom_fields?: CustomField[];
235
+ is_published: boolean;
236
+ is_featured: boolean;
237
+ is_popular: boolean;
238
+ is_new: boolean;
239
+ is_temporary: boolean;
240
+ /** Real fields (kasuvia-crm's review pipeline syncs into these). */
241
+ average_rating?: number | null;
242
+ rating_count: number;
243
+ /** "kasuvia" for organic products, a real channel key ("whatsapp", etc.) for channel-imported products. */
244
+ source_channel: string;
245
+ source_channel_ref_id?: string | null;
246
+ digital_files: ProductDigitalFile[];
247
+ download_limit?: number;
248
+ download_expires_at?: string;
249
+ service_type?: ServiceType;
250
+ service_duration_minutes?: number;
251
+ service_location_type?: ServiceLocationType;
252
+ /** Only meaningful when service_location_type === "customer_location". */
253
+ service_coverage_radius_km?: number | null;
254
+ service_requires_consultation?: boolean;
255
+ service_max_capacity_per_slot?: number;
256
+ service_buffer_minutes?: number;
257
+ service_is_recurring?: boolean;
258
+ service_recurring_interval?: ServiceRecurringInterval;
259
+ service_project_based?: boolean;
260
+ weight_kg?: number;
261
+ length_cm?: number;
262
+ width_cm?: number;
263
+ height_cm?: number;
264
+ variants?: ProductVariant[];
265
+ collections?: Collection[];
266
+ inventory?: Inventory;
267
+ created_at: string;
268
+ updated_at: string;
269
+ }
270
+ interface ProductListResponse {
271
+ items: Product[];
272
+ total: number;
273
+ page: number;
274
+ page_size: number;
275
+ total_pages: number;
276
+ }
277
+ interface CollectionListResponse {
278
+ items: Collection[];
279
+ total: number;
280
+ page: number;
281
+ page_size: number;
282
+ total_pages: number;
283
+ }
284
+ interface ListParams {
285
+ page?: number;
286
+ pageSize?: number;
287
+ collectionSlug?: string;
288
+ search?: string;
289
+ excludeProductId?: string;
290
+ /** One of physical/digital/service/bespoke — omit to browse the whole catalog. */
291
+ productType?: ProductType;
292
+ }
293
+ interface PaginatedResponse<T> {
294
+ items: T[];
295
+ total: number;
296
+ page: number;
297
+ page_size: number;
298
+ total_pages: number;
299
+ }
300
+ interface CartItem {
301
+ id: string;
302
+ product_id: string;
303
+ product_slug: string;
304
+ product_name: string;
305
+ image_url?: string;
306
+ variant_id?: string;
307
+ variant_attributes?: string | Record<string, string>;
308
+ unit_price: number;
309
+ quantity: number;
310
+ custom_measurements?: string;
311
+ is_bespoke: boolean;
312
+ product_type?: ProductType;
313
+ created_at: string;
314
+ updated_at: string;
315
+ }
316
+ interface CartResponse {
317
+ /**
318
+ * The Redis cart key returned by kasuvia-cart-management on every cart operation.
319
+ * Used to correlate a cart with a shipping-rate quote and checkout session.
320
+ */
321
+ id?: string;
322
+ items: CartItem[];
323
+ subtotal: number;
324
+ total: number;
325
+ item_count: number;
326
+ product_type?: ProductType;
327
+ }
328
+ interface WishlistItem {
329
+ id: string;
330
+ product_id: string;
331
+ notes?: string;
332
+ created_at: string;
333
+ product_name?: string;
334
+ product_slug?: string;
335
+ product_price?: number;
336
+ /**
337
+ * REAL BUG FIXED (2026-09-21): was typed as an object
338
+ * (`Record<string, unknown> | null`) but the real GraphQL resolver
339
+ * (kasuvia-store-management's queries.py storefront wishlist query)
340
+ * returns a plain image URL string — a live consumer's `typeof === 'object'`
341
+ * check against this field was always false, silently hiding every
342
+ * wishlist item's image.
343
+ */
344
+ product_image?: string | null;
345
+ /** Real field (queries.py's `item.product.currency`) — the SDK's own GET_STOREFRONT_WISHLIST query already fetches it. */
346
+ currency?: string;
347
+ }
348
+ interface WishlistListResponse {
349
+ items: WishlistItem[];
350
+ total: number;
351
+ page: number;
352
+ page_size: number;
353
+ total_pages: number;
354
+ }
355
+ interface WishlistCheckResponse {
356
+ in_wishlist: boolean;
357
+ }
358
+ type OrderStatus = 'pending' | 'confirmed' | 'processing' | 'packed' | 'picked_up' | 'ready_for_pickup' | 'picked_up_by_customer' | 'in_transit' | 'shipped' | 'delivered' | 'voided' | 'refunded' | 'failed';
359
+ interface OrderItem {
360
+ id: string;
361
+ order_id?: string;
362
+ product_id?: string;
363
+ variant_id?: string;
364
+ product_name: string;
365
+ quantity: number;
366
+ unit_price: number;
367
+ variant_details?: Record<string, unknown>;
368
+ custom_measurements?: Record<string, unknown>;
369
+ image_url?: string;
370
+ }
371
+ interface Order {
372
+ id: string;
373
+ display_id: string;
374
+ business_id: string;
375
+ customer_id?: string;
376
+ status: OrderStatus;
377
+ payment_status: string;
378
+ product_type?: ProductType;
379
+ subtotal_amount?: number;
380
+ discount_amount?: number;
381
+ discount_code?: string;
382
+ tax_amount?: number;
383
+ shipping_amount?: number;
384
+ total_amount: number;
385
+ currency: string;
386
+ customer_name?: string;
387
+ customer_email?: string;
388
+ carrier_name?: string;
389
+ carrier_slug?: string;
390
+ terminal_rate_id?: string;
391
+ tracking_number?: string;
392
+ delivery_status?: string;
393
+ guest_token?: string;
394
+ guest_email?: string;
395
+ guest_phone?: string;
396
+ guest_name?: string;
397
+ shipping_surcharge_amount?: number;
398
+ shipping_surcharge_reason?: string;
399
+ shipping_surcharge_description?: string;
400
+ shipping_surcharge_applied_at?: string;
401
+ declared_weight_kg?: number;
402
+ actual_weight_kg?: number;
403
+ pickup_verification_code?: string;
404
+ pickup_verification_code_generated_at?: string;
405
+ pickup_verification_code_used_at?: string;
406
+ pickup_verification_failed_attempts?: number;
407
+ pickup_verification_locked_until?: string;
408
+ pickup_qr_payload?: string;
409
+ bespoke_brief?: string;
410
+ bespoke_reference_images?: string[];
411
+ bespoke_measurements?: Record<string, unknown>;
412
+ bespoke_preferred_timeline?: string;
413
+ bespoke_special_instructions?: string;
414
+ bespoke_deposit_ratio?: number;
415
+ bespoke_deposit_amount?: number;
416
+ bespoke_balance_amount?: number;
417
+ /** BespokeFulfillmentStatus: "processing" | "awaiting_approval" | "under_review" | "confirmed". */
418
+ bespoke_status?: string;
419
+ bespoke_deliverable_submitted_at?: string;
420
+ bespoke_deliverable_url?: string;
421
+ bespoke_deliverable_notes?: string;
422
+ bespoke_buyer_approved_at?: string;
423
+ bespoke_revision_count?: number;
424
+ bespoke_revision_notes?: string;
425
+ items: OrderItem[];
426
+ buyer_country?: string;
427
+ withdrawal_consent_given_at?: string;
428
+ created_at: string;
429
+ updated_at: string;
430
+ total?: number;
431
+ shippingAmount?: number;
432
+ discountAmount?: number;
433
+ customerEmail?: string;
434
+ customerName?: string;
435
+ createdAt?: number;
436
+ updatedAt?: number;
437
+ deliveryMethod?: string;
438
+ trackingNumber?: string;
439
+ deliveryAddress?: string;
440
+ shippingAddress?: DeliveryAddress;
441
+ cancellationReason?: string;
442
+ hasBespoke?: boolean;
443
+ bespokeStage?: string;
444
+ bespokeBrief?: string;
445
+ deliveryStatus?: string;
446
+ carrierName?: string;
447
+ terminalShipmentId?: string;
448
+ guestToken?: string;
449
+ guestEmail?: string;
450
+ guestPhone?: string;
451
+ guestName?: string;
452
+ }
453
+ interface CheckoutCustomer {
454
+ first_name: string;
455
+ last_name: string;
456
+ email: string;
457
+ phone: string;
458
+ }
459
+ interface ShippingLocation {
460
+ street: string;
461
+ city: string;
462
+ state: string;
463
+ lga: string;
464
+ country: string;
465
+ postal: string;
466
+ latitude?: number | null;
467
+ longitude?: number | null;
468
+ plus_code?: string | null;
469
+ coordinate_source?: 'pin_drop' | 'plus_code' | 'manual' | null;
470
+ }
471
+ interface FindOrderParams {
472
+ email: string;
473
+ order_id: string;
474
+ }
475
+ /**
476
+ * Mirrors kasuvia-store-management's real PhysicalFulfillmentCreate schema
477
+ * exactly (app/schemas/order.py) — the ONLY place these fields are actually
478
+ * read from on OrderCreate. See CreateOrderParams's own doc comment for the
479
+ * real bug this replaced (they used to be declared flat on CreateOrderParams
480
+ * itself, which OrderBase's `extra: "allow"` config accepted with no
481
+ * validation error, then silently discarded — order_in.physical stayed None
482
+ * regardless of what was sent).
483
+ */
484
+ interface CreateOrderPhysicalParams {
485
+ shipping_address?: DeliveryAddress;
486
+ shipping_latitude?: number | null;
487
+ shipping_longitude?: number | null;
488
+ shipping_plus_code?: string | null;
489
+ shipping_coordinate_source?: 'pin_drop' | 'plus_code' | 'manual' | null;
490
+ /**
491
+ * A quote_id from getShippingRates' per-rate "quote_id" field (carrier
492
+ * shipments only). Required for any nonzero shipping fee — the backend
493
+ * reads shipping_amount/terminal_rate_id/carrier_name from this stored
494
+ * quote. self_pickup orders need one too (a real zero-fee quote, see
495
+ * logisticsService.getShippingRates' self_pickup branch) — the backend
496
+ * derives resolved_location_id from it, required for both shipping_method.
497
+ */
498
+ shipping_quote_id?: string;
499
+ /** A ShippingQuoteGroup id when the cart needed splitting across multiple locations — mutually exclusive with shipping_quote_id. */
500
+ shipping_plan_id?: string;
501
+ /**
502
+ * Client-repeated for documentation only — the backend derives the REAL
503
+ * shipping method from the quote itself (resolved_terminal_rate_id is
504
+ * None for a self_pickup quote), never trusts this field. Safe to omit.
505
+ */
506
+ shipping_method?: 'carrier' | 'self_pickup';
507
+ }
508
+ /** Mirrors kasuvia-store-management's real DigitalFulfillmentCreate schema exactly. */
509
+ interface CreateOrderDigitalParams {
510
+ /** ISO-3166-1 alpha-2 country code (e.g. "NG"). Required for digital orders — the backend's VAT lookup refuses to guess a tax jurisdiction. */
511
+ buyer_country?: string;
512
+ withdrawal_consent_given_at?: string;
513
+ }
514
+ /**
515
+ * REAL BUG FIXED (2026-09-24), live-reported ("digital checkout still does
516
+ * not work" / the [FlatRateVAT] error persisting even after buyer_country
517
+ * was correctly collected in the UI): shipping_address, shipping_quote_id,
518
+ * shipping_latitude/longitude/plus_code/coordinate_source, buyer_country,
519
+ * withdrawal_consent_given_at, and shipping_rate_id used to be declared
520
+ * FLAT on this interface. kasuvia-store-management's real OrderCreate
521
+ * schema never had flat equivalents of any of these — confirmed against
522
+ * app/schemas/order.py directly - they only ever existed nested under
523
+ * `physical`/`digital` (see CreateOrderPhysicalParams/
524
+ * CreateOrderDigitalParams above). OrderBase's `extra: "allow"` config
525
+ * meant sending them flat produced no validation error at all - Pydantic
526
+ * silently accepted and discarded them, so order_in.physical/order_in.digital
527
+ * stayed None regardless of what the checkout form collected. Every real
528
+ * physical order's shipping_address/quote and every real digital order's
529
+ * buyer_country has been silently lost this way. shipping_rate_id and
530
+ * pickup_location_id (also previously flat) never existed on the backend
531
+ * schema in ANY shape - both removed outright as confirmed-dead.
532
+ */
533
+ interface CreateOrderParams {
534
+ customer_id?: string | null;
535
+ status?: string;
536
+ checkout_session_id?: string;
537
+ physical?: CreateOrderPhysicalParams;
538
+ digital?: CreateOrderDigitalParams;
539
+ /**
540
+ * Line items for the order.
541
+ *
542
+ * @important DASHBOARD-ONLY — For the merchant dashboard path (POST /sales/orders),
543
+ * these items are used directly. For storefront checkout (POST /orders/storefront),
544
+ * the backend IGNORES this field entirely and reads items from the customer's
545
+ * server-side Redis cart instead. Do NOT rely on this field for storefront orders.
546
+ */
547
+ items?: Array<{
548
+ product_id: string;
549
+ product_name: string;
550
+ quantity: number;
551
+ unit_price: number;
552
+ variant_id?: string;
553
+ variant_details?: Record<string, unknown>;
554
+ custom_measurements?: Record<string, unknown>;
555
+ }>;
556
+ subtotal_amount?: number;
557
+ /** @deprecated Ignored by the backend when discount_code is set (recomputed server-side from the real Discount row); rejected outright if sent without a code. */
558
+ discount_amount?: number;
559
+ discount_code?: string;
560
+ promo_code?: string;
561
+ /** @deprecated Ignored by the backend — tax is always recomputed server-side from the DB VAT rate for the buyer's country. */
562
+ tax_amount?: number;
563
+ /** @deprecated Ignored by the backend for carrier shipments once physical.shipping_quote_id is set; rejected outright if sent nonzero without one. */
564
+ shipping_amount?: number;
565
+ payment_method?: string;
566
+ guest_token?: string;
567
+ guest_email?: string;
568
+ guest_phone?: string;
569
+ guest_name?: string;
570
+ product_type?: ProductType;
571
+ bespoke_brief?: string;
572
+ bespoke_reference_images?: string[];
573
+ bespoke_measurements?: Record<string, string>;
574
+ bespoke_preferred_timeline?: string;
575
+ bespoke_special_instructions?: string;
576
+ }
577
+
578
+ export { type Address as A, ServiceLocationTypeEnum as B, type CreateOrderParams as C, type DeliveryAddress as D, type ServiceRecurringInterval as E, type FindOrderParams as F, type GeolocationData as G, ServiceRecurringIntervalEnum as H, type Inventory as I, type ServiceType as J, ServiceTypeEnum as K, type ListParams as L, type ShippingAddressPayload as M, type ShippingRate as N, type Order as O, type Product as P, type ShippingRatesResponse as Q, type ReverseGeocodeRequest as R, type ShippingLocation as S, type WishlistItem as W, type CartItem as a, type CartResponse as b, type Collection as c, type PaginatedResponse as d, type WishlistCheckResponse as e, type WishlistListResponse as f, type CheckoutCustomer as g, type ProductType as h, type OrderStatus as i, type AddressAutocompleteResponse as j, type AddressSuggestion as k, type AddressValidationErrorData as l, type CollectionListResponse as m, type CoordinateSource as n, type CreateOrderDigitalParams as o, type CreateOrderPhysicalParams as p, type CustomField as q, type OrderItem as r, type PlusCodeDecodeRequest as s, type PlusCodeDecodeResponse as t, type ProductDigitalFile as u, type ProductListResponse as v, ProductTypeEnum as w, type ProductVariant as x, type ReverseGeocodeResponse as y, type ServiceLocationType as z };
@@ -1,4 +1,4 @@
1
- type Theme = "light" | "dark";
1
+ type Theme = "light" | "dark" | "system";
2
2
  type LangCode = "en" | "ha" | "yo" | "ig" | "fr";
3
3
  interface AppState {
4
4
  theme: Theme;
@@ -1,4 +1,4 @@
1
- type Theme = "light" | "dark";
1
+ type Theme = "light" | "dark" | "system";
2
2
  type LangCode = "en" | "ha" | "yo" | "ig" | "fr";
3
3
  interface AppState {
4
4
  theme: Theme;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Kasuvia SDK Configuration
3
+ *
4
+ * Stateless configuration - no module-scoped state.
5
+ * All configuration is passed as parameters to SDK functions.
6
+ *
7
+ * SECURITY NOTE: `backendUrls` must resolve to real backend hosts (e.g. https://kasuvia-auth-...
8
+ * .onrender.com/api/v1) ONLY in a config instance built for server-side use - never pass that
9
+ * instance into SdkProvider or any other client-rendered code. A consuming app should build TWO
10
+ * SdkConfig instances of this exact same shape: a server one (real URLs, for Next.js API routes /
11
+ * Server Components) and a client one (same-origin proxy paths like /api/proxy/store, safe for
12
+ * SdkProvider and any "use client" component).
13
+ *
14
+ * REAL GAP CLOSED (2026-09-17): this plain interface alone couldn't enforce that distinction -
15
+ * getting it backwards used to compile fine and fail at runtime instead (confirmed: kasuvia-storefront's
16
+ * ProductsListing.tsx imported the server instance into a "use client" file, which silently
17
+ * resolved backendUrls.store to '' in the browser bundle rather than erroring loudly - fixed
18
+ * 2026-09-03, but nothing here caught the next occurrence of the same mistake). Build the SERVER
19
+ * instance via `createServerSdkConfig` from '@kasuvia/sdk/config/server' instead of a plain object
20
+ * literal - that module is tagged `import 'server-only'` on its own isolated build entry, so
21
+ * Next.js's bundler refuses at BUILD TIME to include it in any "use client" file's module graph,
22
+ * closing this exact incident class instead of just documenting it. The client instance needs no
23
+ * such guard (proxy paths carry no secret/real-host material) - a plain object literal is fine.
24
+ */
25
+ interface SdkConfig {
26
+ businessId: string;
27
+ storefrontApiKey: string;
28
+ authToken?: string;
29
+ backendUrls: {
30
+ auth: string;
31
+ store: string;
32
+ cart: string;
33
+ payment: string;
34
+ notifications: string;
35
+ cms: string;
36
+ crm: string;
37
+ };
38
+ }
39
+
40
+ export type { SdkConfig as S };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Kasuvia SDK Configuration
3
+ *
4
+ * Stateless configuration - no module-scoped state.
5
+ * All configuration is passed as parameters to SDK functions.
6
+ *
7
+ * SECURITY NOTE: `backendUrls` must resolve to real backend hosts (e.g. https://kasuvia-auth-...
8
+ * .onrender.com/api/v1) ONLY in a config instance built for server-side use - never pass that
9
+ * instance into SdkProvider or any other client-rendered code. A consuming app should build TWO
10
+ * SdkConfig instances of this exact same shape: a server one (real URLs, for Next.js API routes /
11
+ * Server Components) and a client one (same-origin proxy paths like /api/proxy/store, safe for
12
+ * SdkProvider and any "use client" component).
13
+ *
14
+ * REAL GAP CLOSED (2026-09-17): this plain interface alone couldn't enforce that distinction -
15
+ * getting it backwards used to compile fine and fail at runtime instead (confirmed: kasuvia-storefront's
16
+ * ProductsListing.tsx imported the server instance into a "use client" file, which silently
17
+ * resolved backendUrls.store to '' in the browser bundle rather than erroring loudly - fixed
18
+ * 2026-09-03, but nothing here caught the next occurrence of the same mistake). Build the SERVER
19
+ * instance via `createServerSdkConfig` from '@kasuvia/sdk/config/server' instead of a plain object
20
+ * literal - that module is tagged `import 'server-only'` on its own isolated build entry, so
21
+ * Next.js's bundler refuses at BUILD TIME to include it in any "use client" file's module graph,
22
+ * closing this exact incident class instead of just documenting it. The client instance needs no
23
+ * such guard (proxy paths carry no secret/real-host material) - a plain object literal is fine.
24
+ */
25
+ interface SdkConfig {
26
+ businessId: string;
27
+ storefrontApiKey: string;
28
+ authToken?: string;
29
+ backendUrls: {
30
+ auth: string;
31
+ store: string;
32
+ cart: string;
33
+ payment: string;
34
+ notifications: string;
35
+ cms: string;
36
+ crm: string;
37
+ };
38
+ }
39
+
40
+ export type { SdkConfig as S };