@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.
- package/README.md +42 -15
- package/dist/AddressAutocomplete-CjcqPElD.d.mts +46 -0
- package/dist/AddressAutocomplete-CvJHuRkf.d.ts +46 -0
- package/dist/components/index.d.mts +497 -0
- package/dist/components/index.d.ts +497 -0
- package/dist/components/index.js +4217 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/index.mjs +4194 -0
- package/dist/components/index.mjs.map +1 -0
- package/dist/config/server.d.mts +26 -0
- package/dist/config/server.d.ts +26 -0
- package/dist/config/server.js +38 -0
- package/dist/config/server.js.map +1 -0
- package/dist/config/server.mjs +13 -0
- package/dist/config/server.mjs.map +1 -0
- package/dist/hooks/index.d.mts +393 -160
- package/dist/hooks/index.d.ts +393 -160
- package/dist/hooks/index.js +2792 -2137
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +2734 -2121
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index-CNW_LINy.d.mts +578 -0
- package/dist/index-CNW_LINy.d.ts +578 -0
- package/dist/{index-C1chUA3P.d.mts → index-F7N6UItS.d.mts} +1 -1
- package/dist/{index-C1chUA3P.d.ts → index-F7N6UItS.d.ts} +1 -1
- package/dist/index-NkI10J_E.d.mts +40 -0
- package/dist/index-NkI10J_E.d.ts +40 -0
- package/dist/index.d.mts +20437 -103
- package/dist/index.d.ts +20437 -103
- package/dist/index.js +2111 -1802
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2006 -1786
- package/dist/index.mjs.map +1 -1
- package/dist/media.service-Cx7dQjzX.d.mts +1393 -0
- package/dist/media.service-mrBFJ2UQ.d.ts +1393 -0
- package/dist/services/index.d.mts +908 -2
- package/dist/services/index.d.ts +908 -2
- package/dist/services/index.js +1492 -1686
- package/dist/services/index.js.map +1 -1
- package/dist/services/index.mjs +1431 -1670
- package/dist/services/index.mjs.map +1 -1
- package/package.json +46 -6
- package/src/components/bespoke/BespokeAvailabilityBadge.tsx +32 -0
- package/src/components/bespoke/BespokeProgressTracker.tsx +58 -0
- package/src/components/bespoke/index.ts +3 -0
- package/src/components/booking/SlotPicker.tsx +97 -0
- package/src/components/booking/index.ts +1 -0
- package/src/components/cart/CartItem.tsx +81 -0
- package/src/components/cart/CartSidebar.tsx +115 -0
- package/src/components/cart/CartTypeMismatchBanner.tsx +55 -0
- package/src/components/cart/index.ts +3 -0
- package/src/components/index.ts +8 -0
- package/src/components/orders/DeliverableReviewer.tsx +139 -0
- package/src/components/orders/index.ts +1 -0
- package/src/components/product/ProductCard.tsx +350 -0
- package/src/components/product/ProductGrid.tsx +84 -0
- package/src/components/product/index.ts +2 -0
- package/src/components/shared/AddressAutocomplete.tsx +212 -0
- package/src/components/shared/AnalyticsScripts.tsx +56 -0
- package/src/components/shared/CookieConsentBanner.tsx +98 -0
- package/src/components/shared/ImageEditorModal.tsx +1066 -0
- package/src/components/shared/ImageViewerModal.tsx +598 -0
- package/src/components/shared/LucideReactIcon.tsx +52 -0
- package/src/components/shared/MapPinDrop.tsx +101 -0
- package/src/components/shared/MultiSelectPicker.tsx +193 -0
- package/src/components/shared/OfflineBanner.tsx +46 -0
- package/src/components/shared/SearchableInput.tsx +153 -0
- package/src/components/shared/SearchablePopover.tsx +166 -0
- package/src/components/shared/SmartImage.tsx +311 -0
- package/src/components/shared/TruncatedValue.tsx +27 -0
- package/src/components/shared/UnsavedChangesGuard.tsx +138 -0
- package/src/components/shared/index.ts +15 -0
- package/src/components/skeletons/CardSkeleton.tsx +26 -0
- package/src/components/skeletons/CartItemSkeleton.tsx +26 -0
- package/src/components/skeletons/OrderItemSkeleton.tsx +26 -0
- package/src/components/skeletons/ProductCardSkeleton.tsx +26 -0
- package/src/components/skeletons/TableSkeleton.tsx +42 -0
- package/src/components/skeletons/index.ts +5 -0
- package/src/config/index.ts +22 -4
- package/src/config/server.ts +45 -0
- package/src/context/sdk-context.tsx +5 -2
- package/src/generated/auth-openapi.ts +2935 -0
- package/src/generated/cart-openapi.ts +652 -0
- package/src/generated/cms-openapi.ts +1668 -0
- package/src/generated/crm-openapi.ts +986 -0
- package/src/generated/graphql.ts +126 -0
- package/src/generated/index.ts +11 -0
- package/src/generated/media-openapi.ts +613 -0
- package/src/generated/notification-openapi.ts +862 -0
- package/src/generated/payment-openapi.ts +2713 -0
- package/src/generated/store-openapi.ts +9510 -0
- package/src/graphql/operations/collections.graphql +32 -0
- package/src/graphql/operations/products.graphql +197 -0
- package/src/graphql/operations/wishlist.graphql +25 -0
- package/src/hooks/index.ts +9 -2
- package/src/hooks/use-auth.ts +163 -69
- package/src/hooks/use-bespoke-availability.ts +39 -22
- package/src/hooks/use-business-config.ts +51 -0
- package/src/hooks/use-cart.ts +310 -238
- package/src/hooks/use-cms.ts +107 -127
- package/src/hooks/use-collections.ts +35 -55
- package/src/hooks/use-consultations.ts +9 -136
- package/src/hooks/use-countries.ts +19 -28
- package/src/hooks/use-currencies.ts +8 -20
- package/src/hooks/use-customer-address.ts +64 -0
- package/src/hooks/use-feedback.ts +34 -0
- package/src/hooks/use-languages.ts +26 -39
- package/src/hooks/use-media-upload.ts +23 -0
- package/src/hooks/use-notification-stream.ts +88 -0
- package/src/hooks/use-notifications.ts +163 -0
- package/src/hooks/use-order-stream.ts +29 -29
- package/src/hooks/use-orders.ts +91 -73
- package/src/hooks/use-payment.ts +116 -84
- package/src/hooks/use-products.ts +65 -269
- package/src/hooks/use-push-notifications.ts +122 -0
- package/src/hooks/use-reviews.ts +175 -0
- package/src/hooks/use-service-booking.ts +109 -132
- package/src/hooks/use-states.ts +16 -30
- package/src/hooks/use-wishlist.ts +44 -69
- package/src/index.ts +15 -11
- package/src/services/auth.service.ts +422 -132
- package/src/services/bespoke.service.ts +69 -10
- package/src/services/cart.service.ts +155 -186
- package/src/services/cms.service.ts +41 -50
- package/src/services/collection.service.ts +25 -63
- package/src/services/config.service.ts +10 -21
- package/src/services/consultation.service.ts +36 -93
- package/src/services/feedback.service.ts +76 -0
- package/src/services/index.ts +7 -1
- package/src/services/legal.service.ts +62 -0
- package/src/services/logistics.service.ts +235 -53
- package/src/services/media.service.ts +115 -0
- package/src/services/notifications.service.ts +204 -20
- package/src/services/order.service.ts +498 -127
- package/src/services/payment.service.ts +149 -100
- package/src/services/product.service.ts +157 -814
- package/src/services/review.service.ts +211 -0
- package/src/services/service-booking.service.ts +198 -99
- package/src/services/wishlist.service.ts +27 -74
- package/src/types/auth/index.ts +161 -18
- package/src/types/business/index.ts +9 -1
- package/src/types/cms/index.ts +91 -6
- package/src/types/cms/legal.ts +18 -0
- package/src/types/consultations/index.ts +60 -68
- package/src/types/index.ts +5 -3
- package/src/types/media/index.ts +35 -3
- package/src/types/payments/index.ts +80 -16
- package/src/types/reviews/index.ts +116 -0
- package/src/types/services/index.ts +113 -38
- package/src/types/store/checkout.ts +53 -0
- package/src/types/store/index.ts +273 -52
- package/src/types/store/invoice.ts +31 -0
- package/src/types/store/shipping.ts +84 -3
- package/src/types/ui/index.ts +1 -1
- package/src/utils/checkout.ts +19 -3
- package/src/utils/cookieConsent.ts +34 -0
- package/src/utils/format.ts +408 -0
- package/src/utils/geolocation.ts +134 -0
- package/src/utils/graphql-url.ts +47 -0
- package/src/utils/guest-session.ts +59 -0
- package/src/utils/http-client.ts +147 -0
- package/src/utils/index.ts +11 -4
- package/src/utils/status-colors.ts +79 -0
- package/src/utils/token-refresh.ts +115 -0
- package/src/utils/validators.ts +13 -0
- package/src/utils/youtube.ts +18 -0
- package/dist/index-C5YO9gTl.d.mts +0 -507
- package/dist/index-C5YO9gTl.d.ts +0 -507
- package/dist/index-CefG7_xq.d.mts +0 -793
- package/dist/index-DeHCf3zI.d.ts +0 -793
- package/src/graphql/collections.graphql.ts +0 -48
- package/src/graphql/index.ts +0 -7
- package/src/graphql/products.graphql.ts +0 -860
- package/src/graphql/wishlist.graphql.ts +0 -34
- package/src/hooks/use-consultation-stream.ts +0 -142
- 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 };
|
|
@@ -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 };
|