@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,1393 @@
|
|
|
1
|
+
import { S as SdkConfig } from './index-NkI10J_E.js';
|
|
2
|
+
import { O as Order, C as CreateOrderParams, F as FindOrderParams } from './index-CNW_LINy.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Simplified customer auth types for kasuvia-storefront.
|
|
6
|
+
* Customers only need enough to track their orders — no RBAC, MFA, or complex profiles.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Media System response object for avatar/profile picture.
|
|
10
|
+
* Stored as JSON in the backend Profile model.
|
|
11
|
+
*/
|
|
12
|
+
interface AvatarObject {
|
|
13
|
+
id: string;
|
|
14
|
+
alt: string;
|
|
15
|
+
url: string;
|
|
16
|
+
}
|
|
17
|
+
interface CustomerProfileFields {
|
|
18
|
+
firstname: string;
|
|
19
|
+
lastname: string;
|
|
20
|
+
phone: string;
|
|
21
|
+
}
|
|
22
|
+
interface CustomerUser {
|
|
23
|
+
/** Scoped to this business only — the same email is a fully separate identity (and id) at any other business/storefront. Never a platform-wide user id. */
|
|
24
|
+
id: string;
|
|
25
|
+
email: string;
|
|
26
|
+
firstname?: string;
|
|
27
|
+
lastname?: string;
|
|
28
|
+
phone?: string;
|
|
29
|
+
/** Derived display name — prefer firstname + lastname when available */
|
|
30
|
+
full_name?: string;
|
|
31
|
+
avatar: string | null;
|
|
32
|
+
provider: 'google' | 'facebook' | 'email';
|
|
33
|
+
}
|
|
34
|
+
/** GET/PUT /auth/profile/ — matches kasuvia-auth UserSerializer */
|
|
35
|
+
interface AuthUserResponse {
|
|
36
|
+
id: string;
|
|
37
|
+
email: string;
|
|
38
|
+
is_google_auth_enabled?: boolean;
|
|
39
|
+
is_facebook_auth_enabled?: boolean;
|
|
40
|
+
profile?: {
|
|
41
|
+
firstname?: string;
|
|
42
|
+
lastname?: string;
|
|
43
|
+
phone?: string;
|
|
44
|
+
profile_picture?: string | null;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
interface UpdateProfilePayload {
|
|
48
|
+
firstname?: string;
|
|
49
|
+
lastname?: string;
|
|
50
|
+
phone?: string;
|
|
51
|
+
profile_picture?: string;
|
|
52
|
+
}
|
|
53
|
+
interface NotificationPreferences {
|
|
54
|
+
email_enabled: boolean;
|
|
55
|
+
sms_enabled: boolean;
|
|
56
|
+
whatsapp_enabled: boolean;
|
|
57
|
+
push_enabled: boolean;
|
|
58
|
+
email_order_confirmations: boolean;
|
|
59
|
+
email_delivery_updates: boolean;
|
|
60
|
+
email_low_stock_alerts: boolean;
|
|
61
|
+
email_payment_received: boolean;
|
|
62
|
+
push_order_confirmations: boolean;
|
|
63
|
+
push_delivery_updates: boolean;
|
|
64
|
+
push_low_stock_alerts: boolean;
|
|
65
|
+
push_payment_received: boolean;
|
|
66
|
+
whatsapp_order_confirmations: boolean;
|
|
67
|
+
whatsapp_delivery_updates: boolean;
|
|
68
|
+
whatsapp_payment_received: boolean;
|
|
69
|
+
sms_order_confirmations: boolean;
|
|
70
|
+
sms_delivery_updates: boolean;
|
|
71
|
+
}
|
|
72
|
+
interface CustomerAuthResponse {
|
|
73
|
+
access: string;
|
|
74
|
+
refresh: string;
|
|
75
|
+
user: CustomerUser;
|
|
76
|
+
business: StorefrontBusinessInfo;
|
|
77
|
+
is_new?: boolean;
|
|
78
|
+
}
|
|
79
|
+
interface RefreshTokenResponse {
|
|
80
|
+
access: string;
|
|
81
|
+
refresh?: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* POST /auth/login/customer/ — business is identified by the
|
|
85
|
+
* X-Storefront-Key + X-Business-ID headers (config.storefrontApiKey /
|
|
86
|
+
* config.businessId), not a body field (see plan: Customer Storefront
|
|
87
|
+
* Identity Enforcement).
|
|
88
|
+
*/
|
|
89
|
+
interface CustomerLoginPayload {
|
|
90
|
+
email: string;
|
|
91
|
+
password: string;
|
|
92
|
+
}
|
|
93
|
+
/** POST /auth/register/customer/ — business identified via headers, see CustomerLoginPayload. */
|
|
94
|
+
interface CustomerRegisterPayload {
|
|
95
|
+
first_name?: string;
|
|
96
|
+
last_name?: string;
|
|
97
|
+
email: string;
|
|
98
|
+
password: string;
|
|
99
|
+
}
|
|
100
|
+
/** POST /auth/login/customer/passwordless/request/ — business identified via headers, see CustomerLoginPayload. */
|
|
101
|
+
interface CustomerPasswordlessRequestPayload {
|
|
102
|
+
email: string;
|
|
103
|
+
}
|
|
104
|
+
/** POST /auth/login/customer/passwordless/verify/ — business identified via headers, see CustomerLoginPayload. */
|
|
105
|
+
interface CustomerPasswordlessVerifyPayload {
|
|
106
|
+
email: string;
|
|
107
|
+
code: string;
|
|
108
|
+
}
|
|
109
|
+
/** POST /auth/verify-otp/ */
|
|
110
|
+
interface OTPVerifyPayload {
|
|
111
|
+
email: string;
|
|
112
|
+
code: string;
|
|
113
|
+
purpose?: 'verify' | 'password_reset';
|
|
114
|
+
}
|
|
115
|
+
/** POST /auth/resend-otp/ */
|
|
116
|
+
interface ResendOTPPayload {
|
|
117
|
+
email: string;
|
|
118
|
+
}
|
|
119
|
+
/** POST /auth/logout/ */
|
|
120
|
+
interface LogoutPayload {
|
|
121
|
+
refresh?: string;
|
|
122
|
+
}
|
|
123
|
+
/** POST /auth/forgot-password/customer/ */
|
|
124
|
+
interface CustomerForgotPasswordPayload {
|
|
125
|
+
email: string;
|
|
126
|
+
}
|
|
127
|
+
/** POST /auth/reset-password/customer/ */
|
|
128
|
+
interface CustomerResetPasswordPayload {
|
|
129
|
+
email: string;
|
|
130
|
+
code: string;
|
|
131
|
+
new_password: string;
|
|
132
|
+
}
|
|
133
|
+
/** POST /auth/customer/deactivate/ */
|
|
134
|
+
interface CustomerDeactivatePayload {
|
|
135
|
+
reason?: string;
|
|
136
|
+
confirmation_code?: string;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The real backend (require_destructive_confirmation, kasuvia-auth/common/
|
|
140
|
+
* utils/destructive_confirmation.py:76) ALWAYS returns this shape with
|
|
141
|
+
* HTTP 409 on the first deactivate call (no confirmation_code yet) — this
|
|
142
|
+
* is not an error case, it's step 1 of a required two-step confirmation.
|
|
143
|
+
* The code is generated and returned by the server itself (not sent via
|
|
144
|
+
* email) — it exists to require an explicit second, deliberate action in
|
|
145
|
+
* the UI, not to verify identity out-of-band. Resubmit the identical
|
|
146
|
+
* request with `confirmation_code` set to this value to actually deactivate.
|
|
147
|
+
*/
|
|
148
|
+
interface DeactivateConfirmationRequired {
|
|
149
|
+
message: string;
|
|
150
|
+
impact: string[];
|
|
151
|
+
confirmation_code: string;
|
|
152
|
+
expires_in_minutes: number;
|
|
153
|
+
}
|
|
154
|
+
type DeactivateAccountResult = {
|
|
155
|
+
status: 'confirmation_required';
|
|
156
|
+
data: DeactivateConfirmationRequired;
|
|
157
|
+
} | {
|
|
158
|
+
status: 'success';
|
|
159
|
+
detail: string;
|
|
160
|
+
};
|
|
161
|
+
/** POST /auth/change-password/ — identity-mode-agnostic (owner/staff/customer). */
|
|
162
|
+
interface ChangePasswordPayload {
|
|
163
|
+
/** Omit only when the account has no password yet (social/passwordless-only). */
|
|
164
|
+
old_password?: string;
|
|
165
|
+
new_password: string;
|
|
166
|
+
confirm_password: string;
|
|
167
|
+
}
|
|
168
|
+
/** POST /auth/customer/reactivate/ */
|
|
169
|
+
interface CustomerReactivatePayload {
|
|
170
|
+
email: string;
|
|
171
|
+
}
|
|
172
|
+
/** POST /auth/customer/reactivate/verify/ */
|
|
173
|
+
interface CustomerReactivateVerifyPayload {
|
|
174
|
+
email: string;
|
|
175
|
+
code: string;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* One entry in a customer's saved-address book.
|
|
179
|
+
* GET/POST /auth/profile/addresses/, PATCH/DELETE /auth/profile/addresses/{id}/.
|
|
180
|
+
* Field names mirror `DeliveryAddress`/`ShippingLocation` exactly so a saved
|
|
181
|
+
* address can be used directly at checkout with no remapping.
|
|
182
|
+
*/
|
|
183
|
+
interface CustomerAddress {
|
|
184
|
+
id: string;
|
|
185
|
+
label: string;
|
|
186
|
+
first_name: string;
|
|
187
|
+
last_name: string;
|
|
188
|
+
phone: string;
|
|
189
|
+
street: string;
|
|
190
|
+
city: string;
|
|
191
|
+
state: string;
|
|
192
|
+
lga: string;
|
|
193
|
+
country: string;
|
|
194
|
+
postal: string;
|
|
195
|
+
is_default: boolean;
|
|
196
|
+
created_at: string;
|
|
197
|
+
}
|
|
198
|
+
/** Fields a caller may set when creating a saved address - `id`/`created_at` are server-assigned. */
|
|
199
|
+
type CreateCustomerAddressPayload = Omit<CustomerAddress, "id" | "created_at">;
|
|
200
|
+
/** Partial update to an existing saved address. */
|
|
201
|
+
type UpdateCustomerAddressPayload = Partial<CreateCustomerAddressPayload>;
|
|
202
|
+
/**
|
|
203
|
+
* GET /auth/storefront/business-info/ response.
|
|
204
|
+
* Public, unauthenticated (storefront-key-gated) business info for a
|
|
205
|
+
* storefront to render — e.g. footer/about section. An explicit allow-list
|
|
206
|
+
* on the backend (kasuvia-auth's PublicBusinessInfoView) — never owner
|
|
207
|
+
* identity, financial, or internal integration/logistics fields.
|
|
208
|
+
*/
|
|
209
|
+
interface StorefrontBusinessInfo {
|
|
210
|
+
business_id: string;
|
|
211
|
+
name: string;
|
|
212
|
+
tagline: string | null;
|
|
213
|
+
business_type: string;
|
|
214
|
+
country: string;
|
|
215
|
+
business_contact_phone: string;
|
|
216
|
+
business_contact_email: string;
|
|
217
|
+
business_physical_address: string;
|
|
218
|
+
logo_picture: string | null;
|
|
219
|
+
social_links: Record<string, string>;
|
|
220
|
+
currency: string;
|
|
221
|
+
brand_color_primary: string | null;
|
|
222
|
+
brand_color_secondary: string | null;
|
|
223
|
+
brand_color_accent: string | null;
|
|
224
|
+
brand_color_tertiary: string | null;
|
|
225
|
+
}
|
|
226
|
+
interface AuthContextValue {
|
|
227
|
+
customer: CustomerUser | null;
|
|
228
|
+
isLoading: boolean;
|
|
229
|
+
isModalOpen: boolean;
|
|
230
|
+
openModal: () => void;
|
|
231
|
+
closeModal: () => void;
|
|
232
|
+
setCustomer: (user: CustomerUser | null) => void;
|
|
233
|
+
logout: () => Promise<void>;
|
|
234
|
+
login: (payload: CustomerLoginPayload) => Promise<void>;
|
|
235
|
+
register: (payload: CustomerRegisterPayload) => Promise<void>;
|
|
236
|
+
/** Current browser's guest cart session id — pass through to any auth call (e.g. OTP verify) not already routed through login()/register(), so kasuvia-auth's server-side post-login cart merge (see loginCustomer's doc comment) actually fires. */
|
|
237
|
+
guestSessionId: string | null;
|
|
238
|
+
/** Call after any auth flow not routed through login()/register() succeeds (e.g. OTP verify), once the server-side merge above has run — rotates to a fresh guest session id. */
|
|
239
|
+
rotateGuestSessionId: () => void;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* @file types/payments/index.ts
|
|
244
|
+
* @description All customer-facing payment types for the Kasuvia Payment System.
|
|
245
|
+
*
|
|
246
|
+
* Auth model:
|
|
247
|
+
* - X-Storefront-Key → identifies the business storefront
|
|
248
|
+
* - X-Business-ID → tenant context
|
|
249
|
+
* No business-owner JWT used here — these are CUSTOMER-facing types.
|
|
250
|
+
*
|
|
251
|
+
* Payment flow:
|
|
252
|
+
* Customer → Business Owner : Monnify (NGN) | Flutterwave (non-NGN)
|
|
253
|
+
* Business Owner → Kasuvia : Subscription (separate, JWT-auth)
|
|
254
|
+
* Kasuvia → Business Owner : Payout (separate, JWT-auth)
|
|
255
|
+
*/
|
|
256
|
+
interface Currency {
|
|
257
|
+
code: string;
|
|
258
|
+
name: string;
|
|
259
|
+
symbol: string;
|
|
260
|
+
decimals: number;
|
|
261
|
+
is_active: boolean;
|
|
262
|
+
}
|
|
263
|
+
interface SupportedCurrenciesResponse {
|
|
264
|
+
currencies: Currency[];
|
|
265
|
+
}
|
|
266
|
+
interface BackendLanguage {
|
|
267
|
+
code: string;
|
|
268
|
+
label: string;
|
|
269
|
+
flag: string;
|
|
270
|
+
}
|
|
271
|
+
interface SupportedLang {
|
|
272
|
+
code: string;
|
|
273
|
+
appCode: string;
|
|
274
|
+
label: string;
|
|
275
|
+
native: string;
|
|
276
|
+
flag: string;
|
|
277
|
+
}
|
|
278
|
+
interface SupportedLanguagesResponse {
|
|
279
|
+
languages: BackendLanguage[];
|
|
280
|
+
}
|
|
281
|
+
declare enum PaymentGatewayEnum {
|
|
282
|
+
MONNIFY = "monnify",
|
|
283
|
+
FLUTTERWAVE = "flutterwave",
|
|
284
|
+
PAYSTACK = "paystack"
|
|
285
|
+
}
|
|
286
|
+
type PaymentGateway = PaymentGatewayEnum | "monnify" | "flutterwave" | "paystack";
|
|
287
|
+
declare enum PaymentMethodTypeEnum {
|
|
288
|
+
CARD = "card",
|
|
289
|
+
TRANSFER = "transfer",
|
|
290
|
+
BANK_TRANSFER = "bank_transfer",
|
|
291
|
+
ACCOUNT = "account",
|
|
292
|
+
USSD = "ussd"
|
|
293
|
+
}
|
|
294
|
+
type PaymentMethodType = PaymentMethodTypeEnum | "card" | "transfer" | "bank_transfer" | "account" | "ussd";
|
|
295
|
+
interface PaymentMethodOption {
|
|
296
|
+
method: PaymentMethodType | string;
|
|
297
|
+
display_name: string;
|
|
298
|
+
description: string;
|
|
299
|
+
}
|
|
300
|
+
interface GatewayMethods {
|
|
301
|
+
gateway: PaymentGateway | string;
|
|
302
|
+
display_name: string;
|
|
303
|
+
methods: PaymentMethodOption[];
|
|
304
|
+
}
|
|
305
|
+
interface WalletBalanceResponse {
|
|
306
|
+
balance: number;
|
|
307
|
+
currency: string;
|
|
308
|
+
}
|
|
309
|
+
interface WalletLedgerEntry {
|
|
310
|
+
id: string;
|
|
311
|
+
entry_type: string;
|
|
312
|
+
amount: number;
|
|
313
|
+
currency: string;
|
|
314
|
+
refund_id?: string | null;
|
|
315
|
+
transaction_id?: string | null;
|
|
316
|
+
balance_after: number;
|
|
317
|
+
created_at: string;
|
|
318
|
+
}
|
|
319
|
+
interface WalletLedgerResponse {
|
|
320
|
+
items: WalletLedgerEntry[];
|
|
321
|
+
total: number;
|
|
322
|
+
page: number;
|
|
323
|
+
page_size: number;
|
|
324
|
+
}
|
|
325
|
+
interface ClaimWalletCreditRequest {
|
|
326
|
+
claim_token: string;
|
|
327
|
+
}
|
|
328
|
+
interface OutstandingClaimResponse {
|
|
329
|
+
wallet_id: string;
|
|
330
|
+
claim_email: string;
|
|
331
|
+
balance: number;
|
|
332
|
+
currency: string;
|
|
333
|
+
created_at: string;
|
|
334
|
+
}
|
|
335
|
+
interface DVACreateRequest {
|
|
336
|
+
order_id?: string;
|
|
337
|
+
/** Ignored by the backend — the real order total is always charged instead. Only meaningful (and required) if order_id is omitted. */
|
|
338
|
+
amount?: number;
|
|
339
|
+
customer_email: string;
|
|
340
|
+
customer_name?: string;
|
|
341
|
+
/** Defaults to NGN — DVA is Monnify-only */
|
|
342
|
+
currency?: string;
|
|
343
|
+
/** Gateway identifier — the backend requires this explicitly, no default */
|
|
344
|
+
gateway: string;
|
|
345
|
+
/** Window origin of the storefront */
|
|
346
|
+
storefront_origin?: string;
|
|
347
|
+
/** Idempotency key to prevent duplicate DVA creation */
|
|
348
|
+
idempotency_key?: string;
|
|
349
|
+
}
|
|
350
|
+
interface PaymentInitiateRequest {
|
|
351
|
+
/** Ignored by the backend when order_id is set — the real order total is always charged instead. Required only if order_id is omitted. */
|
|
352
|
+
amount?: number;
|
|
353
|
+
currency?: string;
|
|
354
|
+
customer_email: string;
|
|
355
|
+
customer_name?: string;
|
|
356
|
+
order_id?: string;
|
|
357
|
+
quote_id?: string;
|
|
358
|
+
/** ISO 2-letter country code (defaults to 'NG') */
|
|
359
|
+
country_code?: string;
|
|
360
|
+
/** Gateway chosen by customer (e.g., 'monnify', 'flutterwave', 'paystack') — the backend requires this explicitly, no default */
|
|
361
|
+
gateway: string;
|
|
362
|
+
/** Window origin of the storefront — used as gateway redirect base URL */
|
|
363
|
+
storefront_origin?: string;
|
|
364
|
+
metadata?: Record<string, string | number | boolean>;
|
|
365
|
+
/** Idempotency key to prevent duplicate payment initiation */
|
|
366
|
+
idempotency_key?: string;
|
|
367
|
+
}
|
|
368
|
+
interface DVADetails {
|
|
369
|
+
account_number: string;
|
|
370
|
+
bank_name: string;
|
|
371
|
+
account_name: string;
|
|
372
|
+
reference: string;
|
|
373
|
+
amount: number;
|
|
374
|
+
transaction_id: string;
|
|
375
|
+
expires_at: string;
|
|
376
|
+
}
|
|
377
|
+
interface PaymentInitiateResponse {
|
|
378
|
+
id: string;
|
|
379
|
+
gateway_ref: string;
|
|
380
|
+
gateway: string;
|
|
381
|
+
status: string;
|
|
382
|
+
/** Normalised top-level checkout URL for gateway redirect */
|
|
383
|
+
checkout_url: string;
|
|
384
|
+
}
|
|
385
|
+
interface TransactionVerifyResponse {
|
|
386
|
+
id: string;
|
|
387
|
+
status: string;
|
|
388
|
+
amount: number;
|
|
389
|
+
currency: string;
|
|
390
|
+
gateway_ref: string;
|
|
391
|
+
gateway?: string;
|
|
392
|
+
order_id?: string;
|
|
393
|
+
escrow_status?: string;
|
|
394
|
+
escrow_release_date?: string;
|
|
395
|
+
metadata_json?: Record<string, unknown>;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Bespoke commission types for the customer-facing storefront.
|
|
400
|
+
*
|
|
401
|
+
* REAL BUG FIXED (2026-09-21): this file used to also declare a fictional
|
|
402
|
+
* "Consultation" resource (ConsultationStatus/Consultation/ConsultationMessage/
|
|
403
|
+
* etc.) — confirmed there is no /social/consultations/* route or Consultation
|
|
404
|
+
* model anywhere in kasuvia-store-management. The owner confirmed the
|
|
405
|
+
* feature no longer exists there. Removed along with its dead SDK service,
|
|
406
|
+
* hooks, and storefront pages/components — only the real bespoke types
|
|
407
|
+
* (used by bespoke.service.ts against real backend endpoints) remain here.
|
|
408
|
+
*/
|
|
409
|
+
interface BespokeAvailability {
|
|
410
|
+
available_slots: number;
|
|
411
|
+
next_available_date: string | null;
|
|
412
|
+
period_end: string;
|
|
413
|
+
blocked_dates: string[];
|
|
414
|
+
production_days: number;
|
|
415
|
+
is_available: boolean;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Returned by all 3 bespoke deliverable-proofing action endpoints (POST
|
|
419
|
+
* .../bespoke/submit-deliverable, .../approve, .../request-revision) —
|
|
420
|
+
* matches BespokeStatusResponse (kasuvia-store-management/app/schemas/
|
|
421
|
+
* bespoke.py:120-128) exactly.
|
|
422
|
+
*/
|
|
423
|
+
interface BespokeDeliverableStatus {
|
|
424
|
+
id: string;
|
|
425
|
+
order_status: string;
|
|
426
|
+
bespoke_status: string;
|
|
427
|
+
bespoke_deliverable_submitted_at: string | null;
|
|
428
|
+
bespoke_deliverable_url: string | null;
|
|
429
|
+
bespoke_deliverable_notes: string | null;
|
|
430
|
+
bespoke_buyer_approved_at: string | null;
|
|
431
|
+
bespoke_revision_count: number;
|
|
432
|
+
/**
|
|
433
|
+
* REAL GAP FIXED (2026-09-23) via the REST codegen initiative: the real
|
|
434
|
+
* backend response (BespokeStatusResponse, kasuvia-store-management's
|
|
435
|
+
* app/schemas/bespoke.py) has always included this field - this hand-
|
|
436
|
+
* written interface simply never declared it, so it was silently
|
|
437
|
+
* unavailable to every consumer even though the backend was already
|
|
438
|
+
* returning it on every deliverable-status response.
|
|
439
|
+
*/
|
|
440
|
+
bespoke_revision_notes: string | null;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Embedded on an Order as `order.bespoke_fulfillment` — matches
|
|
444
|
+
* BespokeFulfillmentResponse (kasuvia-store-management/app/schemas/
|
|
445
|
+
* order.py:150-168) exactly. This is the real source of a bespoke order's
|
|
446
|
+
* current deliverable state; there is no separate list/GET endpoint for it.
|
|
447
|
+
*/
|
|
448
|
+
interface BespokeFulfillment {
|
|
449
|
+
brief: string | null;
|
|
450
|
+
reference_images: string[] | null;
|
|
451
|
+
measurements: Record<string, unknown> | null;
|
|
452
|
+
preferred_timeline: string | null;
|
|
453
|
+
special_instructions: string | null;
|
|
454
|
+
deposit_ratio: number | null;
|
|
455
|
+
deposit_amount: number | null;
|
|
456
|
+
balance_amount: number | null;
|
|
457
|
+
status: string | null;
|
|
458
|
+
deliverable_submitted_at: string | null;
|
|
459
|
+
deliverable_url: string | null;
|
|
460
|
+
deliverable_notes: string | null;
|
|
461
|
+
buyer_approved_at: string | null;
|
|
462
|
+
revision_count: number;
|
|
463
|
+
revision_notes: string | null;
|
|
464
|
+
timeline_breached_at: string | null;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Service booking types for customer-facing storefront.
|
|
469
|
+
*
|
|
470
|
+
* REAL BUG FIXED (2026-09-20): this entire file used to describe a fictional
|
|
471
|
+
* API shape that never matched kasuvia-store-management's real service-
|
|
472
|
+
* booking backend (`app/schemas/service.py`, `app/api/v1/endpoints/service/
|
|
473
|
+
* bookings.py`) — wrong field names (`appointment_date` vs the real
|
|
474
|
+
* `scheduled_date`), a status enum with values the backend never emits
|
|
475
|
+
* ("pending" vs the real "scheduled"), fields that don't exist on the real
|
|
476
|
+
* response (`location_type`, `customer_address`, `meeting_link`, `price`),
|
|
477
|
+
* and a whole "deliverables" concept (`ServiceDeliverable`,
|
|
478
|
+
* `DeliverableApprovalPayload`) that has no backend counterpart at all — the
|
|
479
|
+
* real analogous feature is the milestone/escrow system below, a different
|
|
480
|
+
* shape entirely. Rebuilt field-for-field against the real Pydantic schemas.
|
|
481
|
+
*/
|
|
482
|
+
type ServiceBookingStatus = "scheduled" | "confirmed" | "in_progress" | "completed" | "voided" | "no_show";
|
|
483
|
+
/** GET /catalog/products/{product_id}/available-slots response. */
|
|
484
|
+
interface AvailableSlotsResponse {
|
|
485
|
+
product_id: string;
|
|
486
|
+
date: string;
|
|
487
|
+
staff_id: string | null;
|
|
488
|
+
duration_minutes: number | null;
|
|
489
|
+
/** false when the business has no/ambiguous location config for this
|
|
490
|
+
* product — check `reason` for why, `available_slots` is always empty. */
|
|
491
|
+
serviceable: boolean;
|
|
492
|
+
reason: string | null;
|
|
493
|
+
/** ISO time strings (e.g. "14:30:00"), not slot objects. */
|
|
494
|
+
available_slots: string[];
|
|
495
|
+
}
|
|
496
|
+
/** Matches ServiceBookingResponse exactly (kasuvia-store-management/app/schemas/service.py:66-90). */
|
|
497
|
+
interface ServiceAppointment {
|
|
498
|
+
id: string;
|
|
499
|
+
business_id: string;
|
|
500
|
+
product_id: string;
|
|
501
|
+
customer_id: string;
|
|
502
|
+
order_id: string | null;
|
|
503
|
+
transaction_id: string | null;
|
|
504
|
+
scheduled_date: string;
|
|
505
|
+
scheduled_time: string;
|
|
506
|
+
duration_minutes: number | null;
|
|
507
|
+
status: ServiceBookingStatus;
|
|
508
|
+
notes: string | null;
|
|
509
|
+
reminder_sent: boolean;
|
|
510
|
+
reminder_scheduled_at: string | null;
|
|
511
|
+
location_id: string | null;
|
|
512
|
+
started_at: string | null;
|
|
513
|
+
completed_at: string | null;
|
|
514
|
+
buyer_confirmed_at: string | null;
|
|
515
|
+
no_show_at: string | null;
|
|
516
|
+
voided_at: string | null;
|
|
517
|
+
cancellation_reason: string | null;
|
|
518
|
+
cancellation_window_hours: number;
|
|
519
|
+
refund_due: boolean | null;
|
|
520
|
+
refund_processed_at: string | null;
|
|
521
|
+
is_milestone_based: boolean;
|
|
522
|
+
assigned_staff_id: string | null;
|
|
523
|
+
assigned_at: string | null;
|
|
524
|
+
assignment_method: string | null;
|
|
525
|
+
created_at: string;
|
|
526
|
+
updated_at: string;
|
|
527
|
+
}
|
|
528
|
+
/** POST /service/bookings/schedule payload (ScheduleServiceRequest). */
|
|
529
|
+
interface ServiceAppointmentCreatePayload {
|
|
530
|
+
product_id: string;
|
|
531
|
+
scheduled_date: string;
|
|
532
|
+
scheduled_time: string;
|
|
533
|
+
notes?: string;
|
|
534
|
+
staff_id?: string;
|
|
535
|
+
/** Required when the product is service_location_type='at_business' and the business runs more than one active location (see useAvailableSlots/logisticsService.listBusinessLocations). */
|
|
536
|
+
location_id?: string;
|
|
537
|
+
}
|
|
538
|
+
/** POST /service/bookings/{id}/cancel payload (CustomerCancelBookingRequest). */
|
|
539
|
+
interface CancelAppointmentPayload {
|
|
540
|
+
reason?: string;
|
|
541
|
+
}
|
|
542
|
+
/** POST /service/bookings/{id}/reschedule payload (CustomerRescheduleBookingRequest). */
|
|
543
|
+
interface RescheduleAppointmentPayload {
|
|
544
|
+
scheduled_date: string;
|
|
545
|
+
scheduled_time: string;
|
|
546
|
+
staff_id?: string;
|
|
547
|
+
}
|
|
548
|
+
/** POST /service/bookings/{id}/dispute payload (CustomerOpenDisputeRequest). */
|
|
549
|
+
interface DisputeAppointmentPayload {
|
|
550
|
+
reason: string;
|
|
551
|
+
}
|
|
552
|
+
/** POST /service/bookings/{id}/confirm payload (BuyerConfirmRequest). */
|
|
553
|
+
interface ConfirmAppointmentPayload {
|
|
554
|
+
notes?: string;
|
|
555
|
+
}
|
|
556
|
+
type MilestoneStatus = "pending" | "funded" | "submitted" | "approved" | "released" | "disputed" | "refunded";
|
|
557
|
+
/** Matches ServiceMilestoneResponse + its ServiceMilestoneBase parent
|
|
558
|
+
* (kasuvia-store-management/app/schemas/service.py:169-173,208-222). */
|
|
559
|
+
interface ServiceMilestone {
|
|
560
|
+
id: string;
|
|
561
|
+
booking_id: string;
|
|
562
|
+
title: string;
|
|
563
|
+
description: string | null;
|
|
564
|
+
/**
|
|
565
|
+
* Milestone amount in the order currency.
|
|
566
|
+
*
|
|
567
|
+
* REAL BUG FIXED (2026-09-23) via the REST codegen initiative: this was
|
|
568
|
+
* typed `number`, but the real backend field (ServiceMilestoneBase.amount,
|
|
569
|
+
* kasuvia-store-management's app/schemas/service.py) is a Pydantic
|
|
570
|
+
* `Decimal`, which serializes to JSON as a STRING (e.g. "150000.00"), not
|
|
571
|
+
* a number - confirmed against the generated OpenAPI schema
|
|
572
|
+
* (`ServiceMilestoneResponse.amount: string`). The one real consumer
|
|
573
|
+
* (ProjectDeliverables.tsx) called `.toLocaleString()` directly on it,
|
|
574
|
+
* which on a string just returns the string unchanged (no thousands
|
|
575
|
+
* separators) rather than the number-formatted value it looked like it
|
|
576
|
+
* was producing for any amount under 4 digits.
|
|
577
|
+
*/
|
|
578
|
+
amount: string;
|
|
579
|
+
sequence: number;
|
|
580
|
+
status: MilestoneStatus;
|
|
581
|
+
funded_at: string | null;
|
|
582
|
+
submitted_at: string | null;
|
|
583
|
+
approved_at: string | null;
|
|
584
|
+
completion_event_at: string | null;
|
|
585
|
+
released_at: string | null;
|
|
586
|
+
dispute_reason: string | null;
|
|
587
|
+
transaction_id: string | null;
|
|
588
|
+
created_at: string;
|
|
589
|
+
updated_at: string;
|
|
590
|
+
}
|
|
591
|
+
/** POST /service/bookings/{id}/milestones/{milestone_id}/approve payload. */
|
|
592
|
+
interface ApproveMilestonePayload {
|
|
593
|
+
notes?: string;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Review and Comment types for CRM service
|
|
598
|
+
*/
|
|
599
|
+
declare enum ModerationStatus {
|
|
600
|
+
PENDING = "pending",
|
|
601
|
+
APPROVED = "approved",
|
|
602
|
+
REJECTED = "rejected"
|
|
603
|
+
}
|
|
604
|
+
interface Review {
|
|
605
|
+
id: string;
|
|
606
|
+
business_id: string;
|
|
607
|
+
product_id: string;
|
|
608
|
+
order_id?: string;
|
|
609
|
+
customer_id: string;
|
|
610
|
+
/** Real field (kasuvia-crm-go's ReviewResponse.customer_name_masked) — the raw customer_id is never exposed to other storefront visitors. */
|
|
611
|
+
customer_name_masked: string;
|
|
612
|
+
rating: number;
|
|
613
|
+
body: string;
|
|
614
|
+
media: string[];
|
|
615
|
+
media_ids: string[];
|
|
616
|
+
verified_purchase: boolean;
|
|
617
|
+
moderation_status: ModerationStatus;
|
|
618
|
+
merchant_reply?: string;
|
|
619
|
+
merchant_reply_at?: string;
|
|
620
|
+
created_at: string;
|
|
621
|
+
edited_at?: string;
|
|
622
|
+
edit_count: number;
|
|
623
|
+
}
|
|
624
|
+
interface Comment {
|
|
625
|
+
id: string;
|
|
626
|
+
business_id: string;
|
|
627
|
+
product_id: string;
|
|
628
|
+
customer_id?: string;
|
|
629
|
+
/** Real field (kasuvia-crm-go's CommentResponse.customer_name_masked). */
|
|
630
|
+
customer_name_masked: string;
|
|
631
|
+
body: string;
|
|
632
|
+
parent_comment_id?: string;
|
|
633
|
+
moderation_status: ModerationStatus;
|
|
634
|
+
is_merchant_reply: boolean;
|
|
635
|
+
created_at: string;
|
|
636
|
+
updated_at: string;
|
|
637
|
+
}
|
|
638
|
+
interface ReviewCreate {
|
|
639
|
+
product_id: string;
|
|
640
|
+
/** Required: reviews are purchase-verified — must reference a completed order for this product. */
|
|
641
|
+
order_id: string;
|
|
642
|
+
rating: number;
|
|
643
|
+
body: string;
|
|
644
|
+
/**
|
|
645
|
+
* `media` (asset URLs) and `media_ids` (the matching MediaAsset ids) must
|
|
646
|
+
* be two parallel, order-paired arrays of the SAME length — the real
|
|
647
|
+
* backend (kasuvia-crm-go's validateMediaPairing) 400s otherwise. Omit
|
|
648
|
+
* both together, or populate both together in the same order.
|
|
649
|
+
*/
|
|
650
|
+
media?: string[];
|
|
651
|
+
media_ids?: string[];
|
|
652
|
+
}
|
|
653
|
+
interface ReviewUpdate {
|
|
654
|
+
rating?: number;
|
|
655
|
+
body?: string;
|
|
656
|
+
/** See ReviewCreate's identical doc comment — media/media_ids must be order-paired, same length. */
|
|
657
|
+
media?: string[];
|
|
658
|
+
media_ids?: string[];
|
|
659
|
+
}
|
|
660
|
+
interface CommentCreate {
|
|
661
|
+
product_id: string;
|
|
662
|
+
body: string;
|
|
663
|
+
parent_comment_id?: string;
|
|
664
|
+
}
|
|
665
|
+
interface CommentUpdate {
|
|
666
|
+
body?: string;
|
|
667
|
+
}
|
|
668
|
+
interface MerchantReplyCreate {
|
|
669
|
+
body: string;
|
|
670
|
+
}
|
|
671
|
+
interface ReviewModerationAction {
|
|
672
|
+
status: ModerationStatus;
|
|
673
|
+
reason?: string;
|
|
674
|
+
}
|
|
675
|
+
interface CommentModerationAction {
|
|
676
|
+
status: ModerationStatus;
|
|
677
|
+
reason?: string;
|
|
678
|
+
}
|
|
679
|
+
interface ProductReviewsResponse {
|
|
680
|
+
results: Review[];
|
|
681
|
+
count: number;
|
|
682
|
+
page: number;
|
|
683
|
+
page_size: number;
|
|
684
|
+
total_pages: number;
|
|
685
|
+
average_rating: number | null;
|
|
686
|
+
rating_distribution: Record<number, number>;
|
|
687
|
+
}
|
|
688
|
+
interface ProductCommentsResponse {
|
|
689
|
+
results: Comment[];
|
|
690
|
+
count: number;
|
|
691
|
+
page: number;
|
|
692
|
+
page_size: number;
|
|
693
|
+
total_pages: number;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* CMS Types
|
|
698
|
+
*
|
|
699
|
+
* Types for kasuvia-cms integration - dynamic content models and entries
|
|
700
|
+
*/
|
|
701
|
+
interface CmsField {
|
|
702
|
+
name: string;
|
|
703
|
+
label: string;
|
|
704
|
+
type: string;
|
|
705
|
+
required: boolean;
|
|
706
|
+
config: Record<string, unknown>;
|
|
707
|
+
sub_fields?: CmsField[];
|
|
708
|
+
}
|
|
709
|
+
interface CmsModelPermissions {
|
|
710
|
+
read: boolean;
|
|
711
|
+
create: boolean;
|
|
712
|
+
update: boolean;
|
|
713
|
+
delete: boolean;
|
|
714
|
+
}
|
|
715
|
+
interface CmsModelPublicApiPermissions {
|
|
716
|
+
public_api: CmsModelPermissions;
|
|
717
|
+
}
|
|
718
|
+
interface CmsModel {
|
|
719
|
+
id: string;
|
|
720
|
+
business_id: string;
|
|
721
|
+
model_slug: string;
|
|
722
|
+
display_name: string;
|
|
723
|
+
description: string | null;
|
|
724
|
+
fields: CmsField[];
|
|
725
|
+
permissions: CmsModelPublicApiPermissions;
|
|
726
|
+
}
|
|
727
|
+
interface CmsEntry {
|
|
728
|
+
id: string;
|
|
729
|
+
business_id: string;
|
|
730
|
+
model_slug: string;
|
|
731
|
+
data: Record<string, unknown>;
|
|
732
|
+
created_at: string;
|
|
733
|
+
updated_at: string;
|
|
734
|
+
created_by: string | null;
|
|
735
|
+
}
|
|
736
|
+
/** Real value shape of a CmsField with type "media" (kasuvia-media-system asset reference). */
|
|
737
|
+
interface CmsMediaValue {
|
|
738
|
+
id: string;
|
|
739
|
+
url: string;
|
|
740
|
+
alt?: string;
|
|
741
|
+
}
|
|
742
|
+
/** Real value shape of a CmsField with type "icon". */
|
|
743
|
+
interface CmsIconValue {
|
|
744
|
+
package: string;
|
|
745
|
+
name: string;
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* The "blogs" CMS model's real field shape, as created by a merchant through
|
|
749
|
+
* kasuvia-cms's dynamic model builder. Field names are merchant-defined
|
|
750
|
+
* (this is a dynamic CMS, not a fixed schema) — this type documents the
|
|
751
|
+
* specific field set kasuvia-storefront's dedicated /blog pages render,
|
|
752
|
+
* confirmed live against a real "blogs" model. A storefront whose merchant
|
|
753
|
+
* named these fields differently needs its own type — this is a rendering
|
|
754
|
+
* convenience, not a backend contract.
|
|
755
|
+
*/
|
|
756
|
+
interface BlogEntryData {
|
|
757
|
+
blog_title: string;
|
|
758
|
+
blog_slug: string;
|
|
759
|
+
blog_content: string;
|
|
760
|
+
excerpt?: string;
|
|
761
|
+
author: string;
|
|
762
|
+
category: string;
|
|
763
|
+
tags?: string;
|
|
764
|
+
featured_image?: CmsMediaValue;
|
|
765
|
+
published_date: string;
|
|
766
|
+
is_published: boolean;
|
|
767
|
+
is_featured?: boolean;
|
|
768
|
+
featured_icon?: CmsIconValue;
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* The "store-locations" CMS model's real field shape (kasuvia-cms/scripts/
|
|
772
|
+
* seed_dummy_models.py's STORE_LOCATIONS_MODEL — merchant-defined, dynamic
|
|
773
|
+
* CMS, this documents the real shape as configured, not a fixed schema).
|
|
774
|
+
*/
|
|
775
|
+
interface StoreLocationEntryData {
|
|
776
|
+
store_name: string;
|
|
777
|
+
address: string;
|
|
778
|
+
city: string;
|
|
779
|
+
store_type: 'Flagship' | 'Outlet' | 'Pop-up' | 'Franchise';
|
|
780
|
+
phone?: string;
|
|
781
|
+
is_open: boolean;
|
|
782
|
+
opening_time: string;
|
|
783
|
+
closing_time: string;
|
|
784
|
+
store_image?: CmsMediaValue;
|
|
785
|
+
store_icon?: CmsIconValue;
|
|
786
|
+
}
|
|
787
|
+
/** The "flash-sales" CMS model's real field shape (same source as above). */
|
|
788
|
+
interface FlashSaleEntryData {
|
|
789
|
+
event_title: string;
|
|
790
|
+
event_description: string;
|
|
791
|
+
start_date: string;
|
|
792
|
+
end_date: string;
|
|
793
|
+
countdown_datetime: string;
|
|
794
|
+
discount_percentage: number;
|
|
795
|
+
is_active: boolean;
|
|
796
|
+
banner_image?: CmsMediaValue;
|
|
797
|
+
}
|
|
798
|
+
/** The "product-faqs" CMS model's real field shape (same source as above). */
|
|
799
|
+
interface ProductFaqEntryData {
|
|
800
|
+
category: string;
|
|
801
|
+
question: string;
|
|
802
|
+
answer: string;
|
|
803
|
+
is_featured: boolean;
|
|
804
|
+
/** Free-text merchant-typed field (e.g. "Shipping Policy: /policies/shipping, Track Your Order: /orders/track") — not structured, rendered as plain text. */
|
|
805
|
+
related_links?: string;
|
|
806
|
+
}
|
|
807
|
+
interface CmsEntryListResponse {
|
|
808
|
+
results: CmsEntry[];
|
|
809
|
+
count: number;
|
|
810
|
+
page: number;
|
|
811
|
+
page_size: number;
|
|
812
|
+
total_pages: number;
|
|
813
|
+
}
|
|
814
|
+
interface CmsIcon {
|
|
815
|
+
id: string;
|
|
816
|
+
name: string;
|
|
817
|
+
category: string;
|
|
818
|
+
tags: string[];
|
|
819
|
+
}
|
|
820
|
+
interface CmsIconListResponse {
|
|
821
|
+
icons: CmsIcon[];
|
|
822
|
+
total: number;
|
|
823
|
+
}
|
|
824
|
+
interface ListCmsEntriesParams {
|
|
825
|
+
page?: number;
|
|
826
|
+
page_size?: number;
|
|
827
|
+
}
|
|
828
|
+
interface CreateCmsEntryParams {
|
|
829
|
+
data: Record<string, unknown>;
|
|
830
|
+
}
|
|
831
|
+
interface UpdateCmsEntryParams {
|
|
832
|
+
data: Record<string, unknown>;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* Media types for the storefront
|
|
837
|
+
*
|
|
838
|
+
* Mirrors `Affiliation` in `kasuvia-media-system/app/models/media.py`, the real
|
|
839
|
+
* source of truth. Re-synced 2026-09-04 (media affiliation recheck): this mirror
|
|
840
|
+
* was missing `Business` and `Review` entirely, and wrongly described
|
|
841
|
+
* `BusinessOwner` as covering logos too.
|
|
842
|
+
*
|
|
843
|
+
* Canonical affiliations:
|
|
844
|
+
* - Content: CMS and website builder content — the ONE shared tag for both
|
|
845
|
+
* - Product: Product images
|
|
846
|
+
* - Collection: Collection images
|
|
847
|
+
* - Chat: AI/customer chat interactions
|
|
848
|
+
* - Review: photos a customer attaches to a product review (kasuvia-crm) —
|
|
849
|
+
* distinct from Customer (a person's own identity photo, not
|
|
850
|
+
* customer-GENERATED content)
|
|
851
|
+
* - Business: a business's own logo
|
|
852
|
+
* - BusinessOwner: the business owner's OWN personal avatar — distinct from
|
|
853
|
+
* Business (the business's logo); never the same asset
|
|
854
|
+
* - Staff: staff avatars
|
|
855
|
+
* - Customer: customer avatars
|
|
856
|
+
* - General: General use cases
|
|
857
|
+
*/
|
|
858
|
+
type MediaAffiliation = 'Content' | 'Product' | 'Collection' | 'Chat' | 'Review' | 'Business' | 'BusinessOwner' | 'Staff' | 'Customer' | 'General';
|
|
859
|
+
interface MediaAsset {
|
|
860
|
+
id: string;
|
|
861
|
+
url: string;
|
|
862
|
+
filename: string;
|
|
863
|
+
content_type: string;
|
|
864
|
+
size: number;
|
|
865
|
+
business_id: string;
|
|
866
|
+
affiliation: MediaAffiliation;
|
|
867
|
+
created_at: string;
|
|
868
|
+
alt?: string;
|
|
869
|
+
description?: string;
|
|
870
|
+
}
|
|
871
|
+
interface MediaUploadParams {
|
|
872
|
+
business_id?: string;
|
|
873
|
+
owner_id?: string;
|
|
874
|
+
uploaded_by_name?: string;
|
|
875
|
+
affiliation?: MediaAffiliation;
|
|
876
|
+
context: string;
|
|
877
|
+
entity_id: string;
|
|
878
|
+
alt?: string;
|
|
879
|
+
description?: string;
|
|
880
|
+
idempotency_key?: string;
|
|
881
|
+
}
|
|
882
|
+
interface MediaAssetUpdatePayload {
|
|
883
|
+
alt?: string;
|
|
884
|
+
description?: string;
|
|
885
|
+
affiliation?: MediaAffiliation;
|
|
886
|
+
}
|
|
887
|
+
interface StorageStats {
|
|
888
|
+
total_bytes: number;
|
|
889
|
+
used_bytes: number;
|
|
890
|
+
available_bytes: number;
|
|
891
|
+
asset_count: number;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
interface BusinessConfig {
|
|
895
|
+
business_id: string;
|
|
896
|
+
storefront_business_id: string;
|
|
897
|
+
name: string;
|
|
898
|
+
currency: string;
|
|
899
|
+
settlement_currency: string;
|
|
900
|
+
country: string;
|
|
901
|
+
region: string;
|
|
902
|
+
has_completed_onboarding: boolean;
|
|
903
|
+
owner_kyc_verified: boolean;
|
|
904
|
+
is_active: boolean;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* Order Service
|
|
909
|
+
*
|
|
910
|
+
* Handles order operations including creation, lookup, and tracking.
|
|
911
|
+
* Stateless - all configuration passed as parameters.
|
|
912
|
+
*/
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* Request body for the real POST /orders/storefront/bespoke atomic checkout
|
|
916
|
+
* (kasuvia-store-management's BespokeBookingCheckoutRequest). Bespoke
|
|
917
|
+
* products can never be added to a cart (ErrBespokeNotCartable) — this is
|
|
918
|
+
* the only real path to a paid bespoke commission from the storefront.
|
|
919
|
+
*/
|
|
920
|
+
interface CreateBespokeOrderParams {
|
|
921
|
+
product_id: string;
|
|
922
|
+
brief: string;
|
|
923
|
+
reference_images?: string[];
|
|
924
|
+
measurements?: Record<string, string>;
|
|
925
|
+
preferred_timeline?: string;
|
|
926
|
+
special_instructions?: string;
|
|
927
|
+
deposit_ratio?: number;
|
|
928
|
+
physical?: {
|
|
929
|
+
shipping_address: Record<string, unknown>;
|
|
930
|
+
};
|
|
931
|
+
notes?: string;
|
|
932
|
+
discount_code?: string;
|
|
933
|
+
guest_email?: string;
|
|
934
|
+
guest_name?: string;
|
|
935
|
+
guest_phone?: string;
|
|
936
|
+
checkout_session_id?: string;
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Request body for the real POST /orders/storefront/service atomic PAID
|
|
940
|
+
* checkout (kasuvia-store-management's ServiceBookingCheckoutRequest) —
|
|
941
|
+
* distinct from the free self-service `bookAppointment` flow
|
|
942
|
+
* (service-booking.service.ts, POST /service/bookings/schedule). Service
|
|
943
|
+
* products can never be added to a cart (ErrServiceNotCartable) — this is
|
|
944
|
+
* the only path to a PAID service booking from the storefront.
|
|
945
|
+
*/
|
|
946
|
+
interface CreateServiceBookingOrderParams {
|
|
947
|
+
product_id: string;
|
|
948
|
+
scheduled_date: string;
|
|
949
|
+
scheduled_time: string;
|
|
950
|
+
staff_id?: string;
|
|
951
|
+
notes?: string;
|
|
952
|
+
discount_code?: string;
|
|
953
|
+
guest_email?: string;
|
|
954
|
+
guest_name?: string;
|
|
955
|
+
guest_phone?: string;
|
|
956
|
+
checkout_session_id?: string;
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* REAL BUG FIXED (2026-09-22): `accessToken` was mandatory (`string`, not
|
|
960
|
+
* optional) — the real backend endpoint (`POST /orders/storefront`,
|
|
961
|
+
* create_storefront_order) explicitly supports guest checkout: `if not
|
|
962
|
+
* user_id and not x_guest_session: raise 401`, matching the same
|
|
963
|
+
* X-Guest-Session pattern cart.service.ts already uses. This endpoint
|
|
964
|
+
* redeems the customer's real server-side cart (guest or authenticated) —
|
|
965
|
+
* `payload.items`/`payload.product_type` are ignored by the backend
|
|
966
|
+
* entirely regardless (see CreateOrderParams' own doc comment) — so a
|
|
967
|
+
* guest with items already in their guest cart had no way to check out at
|
|
968
|
+
* all through this SDK, even though the backend was built for exactly
|
|
969
|
+
* that. `guestSessionId` is a separate parameter (not a body field) since
|
|
970
|
+
* the backend reads it as a header, not JSON.
|
|
971
|
+
*/
|
|
972
|
+
declare function createOrder(config: SdkConfig, accessToken: string | undefined, payload: CreateOrderParams, guestSessionId?: string): Promise<Order>;
|
|
973
|
+
/** Atomic, cart-less bespoke commission checkout — POST /orders/storefront/bespoke. */
|
|
974
|
+
declare function createBespokeOrder(config: SdkConfig, accessToken: string | undefined, payload: CreateBespokeOrderParams): Promise<Order>;
|
|
975
|
+
/** Atomic, cart-less PAID service booking checkout — POST /orders/storefront/service. */
|
|
976
|
+
declare function createServiceBookingOrder(config: SdkConfig, accessToken: string | undefined, payload: CreateServiceBookingOrderParams): Promise<Order>;
|
|
977
|
+
/**
|
|
978
|
+
* REAL BUG FIXED (2026-09-22): called `GET /orders/find/?email=...&order_id=
|
|
979
|
+
* ...&guest_token=...` — this route does not exist anywhere on the real
|
|
980
|
+
* backend (confirmed against every route in app/api/v1/endpoints/sales/
|
|
981
|
+
* orders.py). Every real call 404'd — the entire "track my order by email +
|
|
982
|
+
* order ID" flow (`/track-order`, the actual page kasuvia-storefront's own
|
|
983
|
+
* checkout confirmation links to) has been broken. The real, working
|
|
984
|
+
* mechanism is `POST /orders/track` with a `GuestTrackRequest` body
|
|
985
|
+
* (`{order_id, email}` — both required, no `guest_token` field exists on
|
|
986
|
+
* this or any other real request shape). Fixed to match.
|
|
987
|
+
*/
|
|
988
|
+
declare function findOrder(config: SdkConfig, params: FindOrderParams): Promise<Order>;
|
|
989
|
+
declare function getOrders(config: SdkConfig, accessToken: string, params?: {
|
|
990
|
+
email?: string;
|
|
991
|
+
page?: number;
|
|
992
|
+
page_size?: number;
|
|
993
|
+
}): Promise<Order[]>;
|
|
994
|
+
declare function cancelOrder(config: SdkConfig, accessToken: string, orderId: string, reason: string): Promise<Order>;
|
|
995
|
+
/**
|
|
996
|
+
* REAL BUG FIXED (2026-09-22): called `GET /orders/track/{orderId}?token=
|
|
997
|
+
* ...` — this route does not exist on the real backend at all (confirmed
|
|
998
|
+
* against every route in orders.py). The `token` query param has no
|
|
999
|
+
* corresponding capability anywhere: the real single-order lookup (`GET
|
|
1000
|
+
* /{order_id}`) requires a genuine authenticated JWT
|
|
1001
|
+
* (`Depends(get_current_user_claims)`) and grants access only to the
|
|
1002
|
+
* order's own customer (matching customer_id, or matching guest_email
|
|
1003
|
+
* against the JWT's email for a guest-checkout order that later registered)
|
|
1004
|
+
* — it has no anonymous/guest-token path at all. There is no real backend
|
|
1005
|
+
* capability today for "look up one order by ID + a standalone token, no
|
|
1006
|
+
* login required" — the only real guest lookup is findOrder (email +
|
|
1007
|
+
* order_id via POST /orders/track, a different, plural-sounding but
|
|
1008
|
+
* distinct endpoint). Fixed to call the real endpoint with its real,
|
|
1009
|
+
* mandatory-JWT contract; the fictional guest-token parameter is removed
|
|
1010
|
+
* rather than kept as a parameter that can never do anything.
|
|
1011
|
+
*/
|
|
1012
|
+
declare function trackOrder(config: SdkConfig, orderId: string, accessToken: string): Promise<Order>;
|
|
1013
|
+
interface PromoValidationResult {
|
|
1014
|
+
valid: boolean;
|
|
1015
|
+
discount_amount: number;
|
|
1016
|
+
discount_type: 'percentage' | 'fixed';
|
|
1017
|
+
message: string;
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Validate a promo / discount code against kasuvia-store-management.
|
|
1021
|
+
*
|
|
1022
|
+
* Routes directly to POST /sales/discounts/validate on the store backend
|
|
1023
|
+
* using X-Storefront-Key + X-Business-ID for tenant isolation.
|
|
1024
|
+
* The backend is the single source of truth for discount validity,
|
|
1025
|
+
* amount calculation, and usage tracking.
|
|
1026
|
+
*/
|
|
1027
|
+
declare function validatePromoCode(config: SdkConfig, code: string, cartTotal: number): Promise<PromoValidationResult>;
|
|
1028
|
+
interface DigitalDownloadRedirect {
|
|
1029
|
+
type: 'redirect';
|
|
1030
|
+
url: string;
|
|
1031
|
+
}
|
|
1032
|
+
interface DigitalDownloadFileEntry {
|
|
1033
|
+
id: string;
|
|
1034
|
+
display_name: string;
|
|
1035
|
+
sort_order: number;
|
|
1036
|
+
/** Raw backend URL - never render this directly; resolve it via resolveDigitalDownloadFile instead. */
|
|
1037
|
+
download_url: string;
|
|
1038
|
+
}
|
|
1039
|
+
interface DigitalDownloadListing {
|
|
1040
|
+
type: 'listing';
|
|
1041
|
+
order_id: string;
|
|
1042
|
+
product_name: string;
|
|
1043
|
+
download_count: number;
|
|
1044
|
+
max_downloads: number;
|
|
1045
|
+
expires_at: string | null;
|
|
1046
|
+
files: DigitalDownloadFileEntry[];
|
|
1047
|
+
}
|
|
1048
|
+
type DigitalDownloadResult = DigitalDownloadRedirect | DigitalDownloadListing;
|
|
1049
|
+
/** GET /orders/{order_id}/download/{token} - server-only, no config beyond backendUrls.store needed. */
|
|
1050
|
+
declare function resolveDigitalDownload(config: Pick<SdkConfig, 'backendUrls'>, orderId: string, token: string): Promise<DigitalDownloadResult>;
|
|
1051
|
+
/** GET /orders/{order_id}/download/{token}/{file_id} - resolves ONE file's real, freshly-presigned URL. */
|
|
1052
|
+
declare function resolveDigitalDownloadFile(config: Pick<SdkConfig, 'backendUrls'>, orderId: string, token: string, fileId: string): Promise<string>;
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Consultation Service
|
|
1056
|
+
*
|
|
1057
|
+
* REAL BUG FIXED (2026-09-21): a "consultation" service existed earlier this
|
|
1058
|
+
* session pointed at a fictional `/social/consultations/...` route that
|
|
1059
|
+
* matched nothing in any backend — deleted along with its dead storefront
|
|
1060
|
+
* pages. That deletion was correct (the URL was wrong), but a later audit
|
|
1061
|
+
* of kasuvia-crm-go found the underlying feature is real:
|
|
1062
|
+
* `POST /api/v1/consultations/` (customer-JWT-gated, real bespoke-slot-
|
|
1063
|
+
* reservation side effect when product_id references a bespoke product).
|
|
1064
|
+
* There is deliberately no list/get function here — kasuvia-crm-go's own
|
|
1065
|
+
* code comment confirms "there is no customer-facing GET/list consultation
|
|
1066
|
+
* endpoint at all" (admin_consultations.go). Create-only, by design.
|
|
1067
|
+
*/
|
|
1068
|
+
|
|
1069
|
+
interface CreateConsultationParams {
|
|
1070
|
+
product_id?: string;
|
|
1071
|
+
structured_details?: Record<string, unknown>;
|
|
1072
|
+
}
|
|
1073
|
+
interface Consultation {
|
|
1074
|
+
id: string;
|
|
1075
|
+
business_id: string;
|
|
1076
|
+
customer_id: string | null;
|
|
1077
|
+
product_id: string | null;
|
|
1078
|
+
status: string;
|
|
1079
|
+
quote_amount: number | null;
|
|
1080
|
+
structured_details: Record<string, unknown>;
|
|
1081
|
+
capacity_config_id: string | null;
|
|
1082
|
+
slot_booking_id: string | null;
|
|
1083
|
+
created_at: string;
|
|
1084
|
+
updated_at: string;
|
|
1085
|
+
}
|
|
1086
|
+
declare function createConsultation(config: SdkConfig, accessToken: string, params: CreateConsultationParams): Promise<Consultation>;
|
|
1087
|
+
|
|
1088
|
+
/**
|
|
1089
|
+
* Feedback Service
|
|
1090
|
+
*
|
|
1091
|
+
* REAL FEATURE WIRED (2026-09-21): kasuvia-crm-go's feedback.go (`POST
|
|
1092
|
+
* /api/v1/feedback/`, `GET /api/v1/feedback/my`) is a complete, real,
|
|
1093
|
+
* customer-JWT-gated support-ticket system — private business<->customer
|
|
1094
|
+
* correspondence, distinct from a public, purchase-verified product Review —
|
|
1095
|
+
* with zero SDK coverage anywhere before this file.
|
|
1096
|
+
*/
|
|
1097
|
+
|
|
1098
|
+
/** Mirrors kasuvia-crm-go's models.ValidFeedbackCategories exactly. */
|
|
1099
|
+
type FeedbackCategory = 'general' | 'complaint' | 'suggestion';
|
|
1100
|
+
/** Mirrors kasuvia-crm-go's models.ValidFeedbackStatuses exactly. */
|
|
1101
|
+
type FeedbackStatus = 'open' | 'in_progress' | 'resolved';
|
|
1102
|
+
interface CreateFeedbackParams {
|
|
1103
|
+
subject: string;
|
|
1104
|
+
body: string;
|
|
1105
|
+
/** Defaults to 'general' server-side if omitted. */
|
|
1106
|
+
category?: FeedbackCategory;
|
|
1107
|
+
order_id?: string;
|
|
1108
|
+
}
|
|
1109
|
+
interface Feedback {
|
|
1110
|
+
id: string;
|
|
1111
|
+
business_id: string;
|
|
1112
|
+
customer_id: string;
|
|
1113
|
+
order_id: string | null;
|
|
1114
|
+
category: FeedbackCategory;
|
|
1115
|
+
subject: string;
|
|
1116
|
+
body: string;
|
|
1117
|
+
status: FeedbackStatus;
|
|
1118
|
+
merchant_reply: string | null;
|
|
1119
|
+
merchant_reply_at: string | null;
|
|
1120
|
+
replied_by: string | null;
|
|
1121
|
+
created_at: string;
|
|
1122
|
+
updated_at: string;
|
|
1123
|
+
}
|
|
1124
|
+
interface FeedbackListResponse {
|
|
1125
|
+
results: Feedback[];
|
|
1126
|
+
count: number;
|
|
1127
|
+
page: number;
|
|
1128
|
+
page_size: number;
|
|
1129
|
+
total_pages: number;
|
|
1130
|
+
}
|
|
1131
|
+
declare function createFeedback(config: SdkConfig, accessToken: string, params: CreateFeedbackParams): Promise<Feedback>;
|
|
1132
|
+
declare function getMyFeedback(config: SdkConfig, accessToken: string, params?: {
|
|
1133
|
+
page?: number;
|
|
1134
|
+
page_size?: number;
|
|
1135
|
+
}): Promise<FeedbackListResponse>;
|
|
1136
|
+
|
|
1137
|
+
/**
|
|
1138
|
+
* Service Booking Service
|
|
1139
|
+
*
|
|
1140
|
+
* Handles service appointments (bookings) and their milestone/escrow
|
|
1141
|
+
* sub-resource. Stateless - all configuration passed as parameters.
|
|
1142
|
+
*
|
|
1143
|
+
* REAL BUGS FIXED (2026-09-20) — every function in this file was rewritten
|
|
1144
|
+
* against the real backend (kasuvia-store-management/app/api/v1/endpoints/
|
|
1145
|
+
* service/bookings.py, app/schemas/service.py). Before this fix:
|
|
1146
|
+
* - getAvailableSlots called a nonexistent route (/service/available-slots/
|
|
1147
|
+
* {id}) with the wrong params (date_from/date_to) — the real route is
|
|
1148
|
+
* GET /catalog/products/{id}/available-slots?date=..., a single date.
|
|
1149
|
+
* - bookAppointment POSTed to a nonexistent route (/service/appointments/)
|
|
1150
|
+
* — the real route is POST /service/bookings/schedule.
|
|
1151
|
+
* - getAppointments typed its result as a plain array, but the real
|
|
1152
|
+
* response is the standard Kasuvia paginated envelope
|
|
1153
|
+
* ({results,count,page,page_size,total_pages}) — this was a CONFIRMED
|
|
1154
|
+
* LIVE CRASH: DashboardClient.tsx/DashboardAppointments.tsx called
|
|
1155
|
+
* .length/.filter() directly on the envelope object.
|
|
1156
|
+
* - cancelAppointment sent DELETE /service/bookings/{id} — that route is
|
|
1157
|
+
* owner/staff-only (require_permission("services:manage")), so a
|
|
1158
|
+
* customer got a 403; the real customer route is POST .../{id}/cancel.
|
|
1159
|
+
* It also never checked response.ok at all, silently swallowing failures.
|
|
1160
|
+
* - getDeliverables/approveDeliverable/requestRevision referenced a
|
|
1161
|
+
* "/service/projects/{order_id}/deliverables/..." resource that does not
|
|
1162
|
+
* exist anywhere in the codebase — replaced with the real milestone
|
|
1163
|
+
* endpoints (a different resource: escrow-style payment milestones on
|
|
1164
|
+
* a booking, not free-form deliverable files).
|
|
1165
|
+
* - No coverage existed for reschedule, dispute, or buyer-confirm — all
|
|
1166
|
+
* real, customer-facing routes.
|
|
1167
|
+
*/
|
|
1168
|
+
|
|
1169
|
+
/** Standard Kasuvia pagination envelope — matches app/core/pagination.py's PaginatedResponse exactly. */
|
|
1170
|
+
interface ServiceBookingsPage {
|
|
1171
|
+
results: ServiceAppointment[];
|
|
1172
|
+
count: number;
|
|
1173
|
+
page: number;
|
|
1174
|
+
page_size: number;
|
|
1175
|
+
total_pages: number;
|
|
1176
|
+
}
|
|
1177
|
+
/**
|
|
1178
|
+
* GET /catalog/products/{product_id}/available-slots — real "what times are
|
|
1179
|
+
* open" for a SERVICE product on one date. `serviceable: false` means the
|
|
1180
|
+
* business has no/ambiguous location config for this product (check
|
|
1181
|
+
* `reason`); `available_slots` is always empty in that case, not an error.
|
|
1182
|
+
*/
|
|
1183
|
+
declare function getAvailableSlots(config: SdkConfig, productId: string, date: string, params?: {
|
|
1184
|
+
staffId?: string;
|
|
1185
|
+
locationId?: string;
|
|
1186
|
+
customerLatitude?: number;
|
|
1187
|
+
customerLongitude?: number;
|
|
1188
|
+
}): Promise<AvailableSlotsResponse>;
|
|
1189
|
+
/** POST /service/bookings/schedule */
|
|
1190
|
+
declare function bookAppointment(config: SdkConfig, accessToken: string, payload: ServiceAppointmentCreatePayload): Promise<ServiceAppointment>;
|
|
1191
|
+
/** GET /service/bookings/my — paginated. */
|
|
1192
|
+
declare function getAppointments(config: SdkConfig, accessToken: string, params?: {
|
|
1193
|
+
status?: ServiceAppointment['status'];
|
|
1194
|
+
page?: number;
|
|
1195
|
+
page_size?: number;
|
|
1196
|
+
}): Promise<ServiceBookingsPage>;
|
|
1197
|
+
/**
|
|
1198
|
+
* GET /service/bookings/{id} — customer-reachable single-booking lookup,
|
|
1199
|
+
* used by the paginated list's detail view (PATCH .../{id} is a separate,
|
|
1200
|
+
* owner/staff-only route).
|
|
1201
|
+
*
|
|
1202
|
+
* REAL BUG FIXED (2026-09-22): this call shape was already correct, but the
|
|
1203
|
+
* backend route it targeted didn't exist at all — `ServiceBookingRepository
|
|
1204
|
+
* .get_by_id_and_business` was used internally by every merchant action
|
|
1205
|
+
* (cancel/reschedule/dispute/assign/etc.) but never exposed as a customer
|
|
1206
|
+
* GET route. Every real call to `AppointmentDetail.tsx` (via `useAppointment`)
|
|
1207
|
+
* 404'd. Fixed by adding `GET /{booking_id}` to kasuvia-store-management's
|
|
1208
|
+
* `service/bookings.py` (customer_id-scoped, same pattern as
|
|
1209
|
+
* `customer_cancel_booking` — service bookings have no guest-checkout path,
|
|
1210
|
+
* so no guest_email fallback is needed here unlike orders).
|
|
1211
|
+
*/
|
|
1212
|
+
declare function getAppointment(config: SdkConfig, accessToken: string, id: string): Promise<ServiceAppointment>;
|
|
1213
|
+
/** POST /service/bookings/{id}/cancel — the real customer-cancel route (DELETE .../{id} is owner/staff-only). */
|
|
1214
|
+
declare function cancelAppointment(config: SdkConfig, accessToken: string, id: string, payload?: CancelAppointmentPayload): Promise<ServiceAppointment>;
|
|
1215
|
+
/** POST /service/bookings/{id}/reschedule — subject to the same cancellation_window_hours as a cancel. */
|
|
1216
|
+
declare function rescheduleAppointment(config: SdkConfig, accessToken: string, id: string, payload: RescheduleAppointmentPayload): Promise<ServiceAppointment>;
|
|
1217
|
+
/** POST /service/bookings/{id}/dispute — freezes the escrow auto-release timer; requires a real reason. */
|
|
1218
|
+
declare function disputeAppointment(config: SdkConfig, accessToken: string, id: string, payload: DisputeAppointmentPayload): Promise<ServiceAppointment>;
|
|
1219
|
+
/** POST /service/bookings/{id}/confirm — buyer confirms the service was completed. */
|
|
1220
|
+
declare function confirmAppointmentCompletion(config: SdkConfig, accessToken: string, id: string, payload?: ConfirmAppointmentPayload): Promise<ServiceAppointment>;
|
|
1221
|
+
/** GET /service/bookings/{id}/milestones — escrow-style payment milestones for a milestone-based booking. */
|
|
1222
|
+
declare function getMilestones(config: SdkConfig, accessToken: string, bookingId: string): Promise<ServiceMilestone[]>;
|
|
1223
|
+
/** POST /service/bookings/{id}/milestones/{milestone_id}/approve — buyer approves a submitted milestone, triggering escrow release. */
|
|
1224
|
+
declare function approveMilestone(config: SdkConfig, accessToken: string, bookingId: string, milestoneId: string, payload?: ApproveMilestonePayload): Promise<ServiceMilestone>;
|
|
1225
|
+
declare const serviceBookingService: {
|
|
1226
|
+
getAvailableSlots: typeof getAvailableSlots;
|
|
1227
|
+
bookAppointment: typeof bookAppointment;
|
|
1228
|
+
getAppointments: typeof getAppointments;
|
|
1229
|
+
getAppointment: typeof getAppointment;
|
|
1230
|
+
cancelAppointment: typeof cancelAppointment;
|
|
1231
|
+
rescheduleAppointment: typeof rescheduleAppointment;
|
|
1232
|
+
disputeAppointment: typeof disputeAppointment;
|
|
1233
|
+
confirmAppointmentCompletion: typeof confirmAppointmentCompletion;
|
|
1234
|
+
getMilestones: typeof getMilestones;
|
|
1235
|
+
approveMilestone: typeof approveMilestone;
|
|
1236
|
+
};
|
|
1237
|
+
|
|
1238
|
+
/**
|
|
1239
|
+
* Notification Service
|
|
1240
|
+
*
|
|
1241
|
+
* Handles contact form submissions, email notifications, and notification
|
|
1242
|
+
* channel preferences (customer self-service + merchant-level policy).
|
|
1243
|
+
* Stateless - all configuration passed as parameters.
|
|
1244
|
+
*/
|
|
1245
|
+
|
|
1246
|
+
interface ContactFormData {
|
|
1247
|
+
name: string;
|
|
1248
|
+
email: string;
|
|
1249
|
+
subject: string;
|
|
1250
|
+
message: string;
|
|
1251
|
+
source?: string;
|
|
1252
|
+
company_name?: string;
|
|
1253
|
+
current_year?: number;
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Send contact email to Kasuvia team.
|
|
1257
|
+
* POST /contact/send-contact-email
|
|
1258
|
+
*/
|
|
1259
|
+
declare function sendContactEmail(config: SdkConfig, payload: ContactFormData): Promise<{
|
|
1260
|
+
detail: string;
|
|
1261
|
+
}>;
|
|
1262
|
+
/**
|
|
1263
|
+
* Send confirmation email to user.
|
|
1264
|
+
* POST /contact/send-contact-confirmation
|
|
1265
|
+
*/
|
|
1266
|
+
declare function sendContactConfirmation(config: SdkConfig, payload: ContactFormData): Promise<{
|
|
1267
|
+
detail: string;
|
|
1268
|
+
}>;
|
|
1269
|
+
/**
|
|
1270
|
+
* Get the caller's own notification preferences (customer or business
|
|
1271
|
+
* owner self-service — whoever's access token is passed).
|
|
1272
|
+
* GET /notifications/preferences/
|
|
1273
|
+
*/
|
|
1274
|
+
declare function getNotificationPreferences(config: SdkConfig, accessToken: string): Promise<NotificationPreferences>;
|
|
1275
|
+
/**
|
|
1276
|
+
* Update the caller's own notification preferences.
|
|
1277
|
+
* PATCH /notifications/preferences/
|
|
1278
|
+
*/
|
|
1279
|
+
declare function updateNotificationPreferences(config: SdkConfig, accessToken: string, payload: Partial<NotificationPreferences>): Promise<NotificationPreferences>;
|
|
1280
|
+
interface VapidPublicKeyResponse {
|
|
1281
|
+
public_key: string;
|
|
1282
|
+
subject: string;
|
|
1283
|
+
}
|
|
1284
|
+
interface PushSubscriptionKeys {
|
|
1285
|
+
p256dh: string;
|
|
1286
|
+
auth: string;
|
|
1287
|
+
}
|
|
1288
|
+
interface SubscribeToPushParams {
|
|
1289
|
+
subscription: {
|
|
1290
|
+
endpoint: string;
|
|
1291
|
+
keys: PushSubscriptionKeys;
|
|
1292
|
+
};
|
|
1293
|
+
user_agent: string;
|
|
1294
|
+
}
|
|
1295
|
+
declare function getVapidPublicKey(config: SdkConfig): Promise<VapidPublicKeyResponse>;
|
|
1296
|
+
declare function subscribeToPush(config: SdkConfig, accessToken: string, params: SubscribeToPushParams): Promise<{
|
|
1297
|
+
status: string;
|
|
1298
|
+
subscription_id: string;
|
|
1299
|
+
vapid_key_version: number;
|
|
1300
|
+
}>;
|
|
1301
|
+
declare function unsubscribeFromPush(config: SdkConfig, accessToken: string, endpoint: string): Promise<{
|
|
1302
|
+
status: string;
|
|
1303
|
+
}>;
|
|
1304
|
+
type NotificationPriority = 'urgent' | 'normal' | 'low';
|
|
1305
|
+
interface NotificationInboxItem {
|
|
1306
|
+
id: string;
|
|
1307
|
+
title: string;
|
|
1308
|
+
body: string;
|
|
1309
|
+
icon_url?: string | null;
|
|
1310
|
+
image_url?: string | null;
|
|
1311
|
+
priority: NotificationPriority;
|
|
1312
|
+
action_type?: string | null;
|
|
1313
|
+
action_url?: string | null;
|
|
1314
|
+
entity_id?: string | null;
|
|
1315
|
+
entity_type?: string | null;
|
|
1316
|
+
category: string;
|
|
1317
|
+
source_event_type: string;
|
|
1318
|
+
read: boolean;
|
|
1319
|
+
read_at?: string | null;
|
|
1320
|
+
clicked: boolean;
|
|
1321
|
+
clicked_at?: string | null;
|
|
1322
|
+
action_performed: boolean;
|
|
1323
|
+
created_at: string;
|
|
1324
|
+
expires_at?: string | null;
|
|
1325
|
+
}
|
|
1326
|
+
interface NotificationInboxResponse {
|
|
1327
|
+
results: NotificationInboxItem[];
|
|
1328
|
+
count: number;
|
|
1329
|
+
page: number;
|
|
1330
|
+
page_size: number;
|
|
1331
|
+
total_pages: number;
|
|
1332
|
+
}
|
|
1333
|
+
declare function getNotificationInbox(config: SdkConfig, accessToken: string, params?: {
|
|
1334
|
+
page?: number;
|
|
1335
|
+
limit?: number;
|
|
1336
|
+
unread_only?: boolean;
|
|
1337
|
+
}): Promise<NotificationInboxResponse>;
|
|
1338
|
+
declare function markNotificationRead(config: SdkConfig, accessToken: string, notificationId: string): Promise<{
|
|
1339
|
+
status: string;
|
|
1340
|
+
}>;
|
|
1341
|
+
declare function markAllNotificationsRead(config: SdkConfig, accessToken: string): Promise<{
|
|
1342
|
+
status: string;
|
|
1343
|
+
}>;
|
|
1344
|
+
declare function trackNotificationClick(config: SdkConfig, accessToken: string, notificationId: string): Promise<{
|
|
1345
|
+
status: string;
|
|
1346
|
+
}>;
|
|
1347
|
+
declare const notificationsService: {
|
|
1348
|
+
readonly sendContactEmail: typeof sendContactEmail;
|
|
1349
|
+
readonly sendContactConfirmation: typeof sendContactConfirmation;
|
|
1350
|
+
readonly getNotificationPreferences: typeof getNotificationPreferences;
|
|
1351
|
+
readonly updateNotificationPreferences: typeof updateNotificationPreferences;
|
|
1352
|
+
readonly getVapidPublicKey: typeof getVapidPublicKey;
|
|
1353
|
+
readonly subscribeToPush: typeof subscribeToPush;
|
|
1354
|
+
readonly unsubscribeFromPush: typeof unsubscribeFromPush;
|
|
1355
|
+
readonly getNotificationInbox: typeof getNotificationInbox;
|
|
1356
|
+
readonly markNotificationRead: typeof markNotificationRead;
|
|
1357
|
+
readonly markAllNotificationsRead: typeof markAllNotificationsRead;
|
|
1358
|
+
readonly trackNotificationClick: typeof trackNotificationClick;
|
|
1359
|
+
};
|
|
1360
|
+
|
|
1361
|
+
interface UploadMediaFileParams {
|
|
1362
|
+
file: File;
|
|
1363
|
+
/** e.g. "review", "digital_product" — matches kasuvia-media-system's context_validation.py. */
|
|
1364
|
+
context: string;
|
|
1365
|
+
entityId: string;
|
|
1366
|
+
affiliation?: string;
|
|
1367
|
+
ownerId?: string;
|
|
1368
|
+
presignedUrlEndpoint?: string;
|
|
1369
|
+
confirmUploadEndpoint?: string;
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Upload one file end-to-end: request a presigned URL, PUT the file
|
|
1373
|
+
* directly to R2, then confirm the upload to get back a real MediaAsset.
|
|
1374
|
+
*/
|
|
1375
|
+
declare function uploadMediaFile(params: UploadMediaFileParams): Promise<MediaAsset>;
|
|
1376
|
+
interface UploadMediaFilesResult {
|
|
1377
|
+
assets: MediaAsset[];
|
|
1378
|
+
errors: {
|
|
1379
|
+
file: string;
|
|
1380
|
+
message: string;
|
|
1381
|
+
}[];
|
|
1382
|
+
}
|
|
1383
|
+
/**
|
|
1384
|
+
* Upload several files, one at a time (sequential — real progress feedback
|
|
1385
|
+
* per file rather than an opaque Promise.all batch). A single file's
|
|
1386
|
+
* failure does not abort the rest: matches the original BespokeStep/
|
|
1387
|
+
* ProductReviews behaviour of keeping whatever succeeded before a later
|
|
1388
|
+
* file failed, rather than discarding it. The caller decides how to present
|
|
1389
|
+
* `errors` (e.g. one toast per failed filename).
|
|
1390
|
+
*/
|
|
1391
|
+
declare function uploadMediaFiles(files: File[], params: Omit<UploadMediaFileParams, 'file'>): Promise<UploadMediaFilesResult>;
|
|
1392
|
+
|
|
1393
|
+
export { type DVADetails as $, type AuthUserResponse as A, type BespokeDeliverableStatus as B, type CreateBespokeOrderParams as C, type DeactivateAccountResult as D, type ApproveMilestonePayload as E, type Feedback as F, type AvailableSlotsResponse as G, type ServiceAppointmentCreatePayload as H, type CancelAppointmentPayload as I, type ConfirmAppointmentPayload as J, type DisputeAppointmentPayload as K, type Comment as L, type CommentCreate as M, type Review as N, type ReviewCreate as O, type MerchantReplyCreate as P, type CommentModerationAction as Q, type RescheduleAppointmentPayload as R, type StorefrontBusinessInfo as S, type ReviewModerationAction as T, type UpdateCustomerAddressPayload as U, type ProductCommentsResponse as V, type ProductReviewsResponse as W, type CommentUpdate as X, type ReviewUpdate as Y, type GatewayMethods as Z, type WalletBalanceResponse as _, type CreateServiceBookingOrderParams as a, type StorageStats as a$, type DVACreateRequest as a0, type PaymentInitiateResponse as a1, type PaymentInitiateRequest as a2, type TransactionVerifyResponse as a3, type WalletLedgerResponse as a4, type CmsEntry as a5, type CreateCmsEntryParams as a6, type UpdateCmsEntryParams as a7, type ListCmsEntriesParams as a8, type BusinessConfig as a9, type DeactivateConfirmationRequired as aA, type DigitalDownloadFileEntry as aB, type DigitalDownloadListing as aC, type DigitalDownloadRedirect as aD, type DigitalDownloadResult as aE, type FeedbackCategory as aF, type FeedbackStatus as aG, type FlashSaleEntryData as aH, type LogoutPayload as aI, type MediaAffiliation as aJ, type MediaAssetUpdatePayload as aK, type MediaUploadParams as aL, ModerationStatus as aM, type NotificationInboxItem as aN, type NotificationPriority as aO, type OTPVerifyPayload as aP, type OutstandingClaimResponse as aQ, type PaymentGateway as aR, PaymentGatewayEnum as aS, type PaymentMethodOption as aT, type PaymentMethodType as aU, PaymentMethodTypeEnum as aV, type ProductFaqEntryData as aW, type PromoValidationResult as aX, type PushSubscriptionKeys as aY, type RefreshTokenResponse as aZ, type ResendOTPPayload as a_, type NotificationInboxResponse as aa, type NotificationPreferences as ab, type ContactFormData as ac, type SubscribeToPushParams as ad, type VapidPublicKeyResponse as ae, type MediaAsset as af, type UploadMediaFileParams as ag, type UploadMediaFilesResult as ah, type ServiceBookingStatus as ai, type MilestoneStatus as aj, type AuthContextValue as ak, type AvatarObject as al, type BackendLanguage as am, type BespokeFulfillment as an, type BlogEntryData as ao, type ClaimWalletCreditRequest as ap, type CmsEntryListResponse as aq, type CmsField as ar, type CmsIcon as as, type CmsIconListResponse as at, type CmsIconValue as au, type CmsMediaValue as av, type CmsModel as aw, type CmsModelPermissions as ax, type CmsModelPublicApiPermissions as ay, type CustomerProfileFields as az, type Consultation as b, type StoreLocationEntryData as b0, type SupportedCurrenciesResponse as b1, type SupportedLanguagesResponse as b2, type WalletLedgerEntry as b3, approveMilestone as b4, bookAppointment as b5, cancelAppointment as b6, cancelOrder as b7, confirmAppointmentCompletion as b8, createBespokeOrder as b9, trackOrder as bA, unsubscribeFromPush as bB, updateNotificationPreferences as bC, uploadMediaFile as bD, uploadMediaFiles as bE, validatePromoCode as bF, createConsultation as ba, createFeedback as bb, createOrder as bc, createServiceBookingOrder as bd, disputeAppointment as be, findOrder as bf, getAppointment as bg, getAppointments as bh, getAvailableSlots as bi, getMilestones as bj, getMyFeedback as bk, getNotificationInbox as bl, getNotificationPreferences as bm, getOrders as bn, getVapidPublicKey as bo, markAllNotificationsRead as bp, markNotificationRead as bq, notificationsService as br, rescheduleAppointment as bs, resolveDigitalDownload as bt, resolveDigitalDownloadFile as bu, sendContactConfirmation as bv, sendContactEmail as bw, serviceBookingService as bx, subscribeToPush as by, trackNotificationClick as bz, type CreateConsultationParams as c, type CreateFeedbackParams as d, type FeedbackListResponse as e, type CustomerAddress as f, type CreateCustomerAddressPayload as g, type ChangePasswordPayload as h, type CustomerDeactivatePayload as i, type CustomerForgotPasswordPayload as j, type CustomerReactivatePayload as k, type CustomerReactivateVerifyPayload as l, type CustomerResetPasswordPayload as m, type CustomerAuthResponse as n, type CustomerLoginPayload as o, type CustomerRegisterPayload as p, type CustomerPasswordlessRequestPayload as q, type CustomerUser as r, type UpdateProfilePayload as s, type CustomerPasswordlessVerifyPayload as t, type SupportedLang as u, type Currency as v, type BespokeAvailability as w, type ServiceAppointment as x, type ServiceBookingsPage as y, type ServiceMilestone as z };
|