@behio/storefront-sdk 0.37.0 → 0.41.0
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/dist/{chunk-QKEW2EU5.js → chunk-3TPJG2WV.js} +589 -145
- package/dist/{chunk-5C6MNGGB.mjs → chunk-QOZYQMK2.mjs} +587 -143
- package/dist/{client-BgYibdTK.d.mts → client-sN7fZvjG.d.mts} +363 -7
- package/dist/{client-BgYibdTK.d.ts → client-sN7fZvjG.d.ts} +363 -7
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +142 -40
- package/dist/index.mjs +111 -9
- package/dist/next.d.mts +1 -1
- package/dist/next.d.ts +1 -1
- package/dist/next.js +2 -2
- package/dist/next.mjs +1 -1
- package/dist/react.d.mts +3026 -4
- package/dist/react.d.ts +3026 -4
- package/dist/react.js +2612 -467
- package/dist/react.mjs +2128 -86
- package/package.json +2 -2
- package/dist/chunk-CZRSJULD.js +0 -118
- package/dist/chunk-QUU76QUB.mjs +0 -118
package/dist/react.d.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
3
3
|
import { QueryClient } from '@tanstack/react-query';
|
|
4
|
-
import { a as BehioStorefront, P as ProductsQuery, b as PaginatedResponse, c as ProductListItem, d as ProductDetail, C as Category, e as CategoryDetail, M as Menu, f as ProductLabel, F as FilterField, g as FacetsResponse, h as Cart, i as CustomerProfile, R as RegisterInput, j as CustomerAddress, A as AddressSuggestion, k as AddressDetail, L as LoyaltySummary, S as Subscription, l as SubscriptionAction, m as PickupPointsInput, n as PickupPoint, o as ShippingMethodSummary, p as ShippingQuoteInput, q as ShippingQuote, r as CheckoutPaymentMethod, N as NewsletterSubscribeResult, s as NewsletterSubscribeInput, t as NewsletterUnsubscribeResult, O as OrderListItem, u as OrderDetail, v as OrderAccessRequestResponse, w as OrderAccessVerifyResponse, x as CheckoutInput, y as PageDetail, z as Page, D as ShopInfo, E as ShopScripts, G as ShopSeo, H as Bundle, I as ProductGroup, J as CrossSellItem, K as ActivePromotion, Q as GiftCardBalance, W as WishlistItem, T as ProductReviewsResponse, U as SubmitReviewInput, V as ReturnableOrder, X as ReturnStatus, Y as ReturnRequest, Z as SubmitReturnInput, _ as CookieConsent, $ as CookieConsentInput, a0 as QuoteRequest, a1 as SubmitQuoteInput, a2 as BackInStockSubscription } from './client-BgYibdTK.js';
|
|
5
|
-
export { a3 as AddToCartInput, a4 as AuthTokens, a5 as BehioApiError, a6 as BundleItem, a7 as CartDiscount, a8 as CartItem, a9 as CheckoutAddress, aa as FulfillmentStatus, ab as LoginInput, ac as MessageResponse, ad as OrderItem, ae as OrderStatus, af as PaymentStatus, ag as ProductPrice, ah as ProductReview, ai as ProductVariant } from './client-BgYibdTK.js';
|
|
6
4
|
import * as _tanstack_query_core from '@tanstack/query-core';
|
|
7
|
-
export { EcommerceEventName, EcommerceItem, EcommercePayload, formatPrice, generateVisitorId, getStoredVisitorId, grantAnalyticsConsent, revokeAnalyticsConsent, trackEcommerceEvent } from './index.js';
|
|
8
5
|
|
|
9
6
|
interface StorageAdapter {
|
|
10
7
|
get(key: string): string | null;
|
|
@@ -57,6 +54,2760 @@ interface BehioProviderProps {
|
|
|
57
54
|
}
|
|
58
55
|
declare function BehioProvider({ apiKey, baseUrl, shopDomain, locale, currency, defaultCurrency, currencies, onCurrencyChange, persistCurrency, currencyCookieName, storage: storageOption, queryClient: externalQueryClient, children, }: BehioProviderProps): react_jsx_runtime.JSX.Element;
|
|
59
56
|
|
|
57
|
+
interface BehioStorefrontConfig {
|
|
58
|
+
/** API key (public: pk_live_xxx or private: sk_live_xxx) */
|
|
59
|
+
apiKey: string;
|
|
60
|
+
/** Backend base URL. Default: https://be.behio.com */
|
|
61
|
+
baseUrl?: string;
|
|
62
|
+
/**
|
|
63
|
+
* The domain this storefront is served on (e.g. "mujshop.cz"), sent as
|
|
64
|
+
* X-Shop-Domain. Only needed when ONE deployment serves several domains with
|
|
65
|
+
* a single "all domains" API key (e.g. a Vercel app behind mujshop.cz +
|
|
66
|
+
* mujshop.sk) AND there's no Origin header (server-side rendering). A
|
|
67
|
+
* domain-bound key, or a browser request (Origin), doesn't need it.
|
|
68
|
+
*/
|
|
69
|
+
shopDomain?: string;
|
|
70
|
+
/** Default locale for catalog requests. Default: none (uses shop default) */
|
|
71
|
+
locale?: string;
|
|
72
|
+
/** Default currency for price resolution. Default: none (uses shop default) */
|
|
73
|
+
currency?: string;
|
|
74
|
+
/** Custom fetch implementation (for Node.js < 18 or testing) */
|
|
75
|
+
fetch?: typeof fetch;
|
|
76
|
+
/** Request timeout in milliseconds. Default: 30000 (30s) */
|
|
77
|
+
timeout?: number;
|
|
78
|
+
/** Number of retries on network/5xx errors. Default: 1 */
|
|
79
|
+
retries?: number;
|
|
80
|
+
/** Base delay between retries in ms (multiplied by attempt). Default: 1000 */
|
|
81
|
+
retryDelay?: number;
|
|
82
|
+
}
|
|
83
|
+
interface PaginatedResponse<T> {
|
|
84
|
+
items: T[];
|
|
85
|
+
total: number;
|
|
86
|
+
page: number;
|
|
87
|
+
limit: number;
|
|
88
|
+
totalPages: number;
|
|
89
|
+
}
|
|
90
|
+
interface MessageResponse {
|
|
91
|
+
message: string;
|
|
92
|
+
}
|
|
93
|
+
/** How the shop wants the newsletter opt-in rendered at checkout. */
|
|
94
|
+
type NewsletterOptInDefault = "CHECKED" | "UNCHECKED" | "HIDDEN";
|
|
95
|
+
/** How sold-out products behave in the catalog. */
|
|
96
|
+
type StockBehavior = "HIDE" | "BACKORDER" | "SHOW_SOLD_OUT";
|
|
97
|
+
/**
|
|
98
|
+
* Shop-level stock mode preset. ALWAYS_AVAILABLE (reseller) and MADE_TO_ORDER
|
|
99
|
+
* (production) shops sell regardless of stock: `inStock` is always true,
|
|
100
|
+
* availability derives to "in-stock" / "on-order" and stock counts are hidden.
|
|
101
|
+
* Templates can hide stock UI entirely when the mode is not TRACKED.
|
|
102
|
+
*/
|
|
103
|
+
type StockMode = "TRACKED" | "ALWAYS_AVAILABLE" | "MADE_TO_ORDER";
|
|
104
|
+
/**
|
|
105
|
+
* Merchant-configured checkout & cart rules the storefront MUST honour so the
|
|
106
|
+
* shop behaves exactly as it was configured in the admin. Mirrors the backend
|
|
107
|
+
* Eshop settings; the server also enforces the enforceable rules, so these are
|
|
108
|
+
* for UX (render required fields, consent checkboxes, cart limits, free-shipping
|
|
109
|
+
* progress) rather than a security boundary.
|
|
110
|
+
*/
|
|
111
|
+
interface CheckoutSettings {
|
|
112
|
+
/** Guests may order without an account (also on ShopInfo for back-compat). */
|
|
113
|
+
allowGuestCheckout: boolean;
|
|
114
|
+
/** Checkout requires a logged-in / registered account. */
|
|
115
|
+
requireAccount: boolean;
|
|
116
|
+
/** New registrations wait for merchant approval before ordering (B2B). */
|
|
117
|
+
requireRegistrationApproval: boolean;
|
|
118
|
+
/** Phone number is a required checkout field. */
|
|
119
|
+
requirePhone: boolean;
|
|
120
|
+
/** Tax id (IČO/DIČ) is a required checkout field. */
|
|
121
|
+
requireTaxId: boolean;
|
|
122
|
+
/** Customer may leave an order note. */
|
|
123
|
+
allowOrderNote: boolean;
|
|
124
|
+
/** Discount / coupon codes may be applied in the cart. */
|
|
125
|
+
allowDiscountCodes: boolean;
|
|
126
|
+
/** Gift cards may be applied in the cart / checkout. */
|
|
127
|
+
allowGiftCards: boolean;
|
|
128
|
+
/** Terms & conditions consent checkbox is required to place an order. */
|
|
129
|
+
requireTermsConsent: boolean;
|
|
130
|
+
/** GDPR / privacy consent checkbox is required to place an order. */
|
|
131
|
+
requireGdprConsent: boolean;
|
|
132
|
+
/** Default state of the newsletter opt-in on the checkout (or hide it). */
|
|
133
|
+
newsletterOptInDefault: NewsletterOptInDefault;
|
|
134
|
+
/** Minimum order value in the shop default currency, or null when unset. */
|
|
135
|
+
minOrderValue: number | null;
|
|
136
|
+
/** Maximum order value in the shop default currency, or null when unset. */
|
|
137
|
+
maxOrderValue: number | null;
|
|
138
|
+
/** Free-shipping threshold (shop default currency) for the cart progress bar. */
|
|
139
|
+
freeShippingThreshold: number | null;
|
|
140
|
+
/** Minimum number of items required in the cart to check out. */
|
|
141
|
+
minItemsInCart: number;
|
|
142
|
+
/** Maximum quantity of a single product per order, or null when unlimited. */
|
|
143
|
+
maxItemsPerProduct: number | null;
|
|
144
|
+
/**
|
|
145
|
+
* How sold-out products behave. The SERVER enforces the buying rules; the
|
|
146
|
+
* template mirrors them in UX:
|
|
147
|
+
* - `HIDE`: sold-out products are already filtered out of browse/search/
|
|
148
|
+
* featured responses server-side; PDP direct links still resolve — render
|
|
149
|
+
* them as sold out with the buy button disabled.
|
|
150
|
+
* - `SHOW_SOLD_OUT`: sold-out products render with a "Vyprodáno" state and
|
|
151
|
+
* a disabled buy button; the API rejects over-stock adds with a 400.
|
|
152
|
+
* - `BACKORDER`: out-of-stock products stay purchasable (any quantity);
|
|
153
|
+
* render "Na objednávku" instead of disabling the button.
|
|
154
|
+
* For HIDE/SHOW_SOLD_OUT cap quantity steppers at `stockQuantity` — the
|
|
155
|
+
* cart API 400s on anything above it.
|
|
156
|
+
*/
|
|
157
|
+
stockBehavior: StockBehavior;
|
|
158
|
+
/** Stock mode preset; non-TRACKED shops are always purchasable. */
|
|
159
|
+
stockMode: StockMode;
|
|
160
|
+
/**
|
|
161
|
+
* Merchant enabled the "only X left" nudge. When true, products whose stock
|
|
162
|
+
* is within `lowStockThreshold` carry `lowStockRemaining` — render the badge
|
|
163
|
+
* from that field alone (it is null everywhere else).
|
|
164
|
+
*/
|
|
165
|
+
showLowStock: boolean;
|
|
166
|
+
/** Stock level at (and below) which the low-stock nudge shows. */
|
|
167
|
+
lowStockThreshold: number;
|
|
168
|
+
/** Google Places address autocomplete is enabled; mount the UX when true. */
|
|
169
|
+
addressAutocompleteEnabled: boolean;
|
|
170
|
+
/**
|
|
171
|
+
* How prices are presented to the customer (GAP-30):
|
|
172
|
+
* - `INCL_VAT` (default, B2C): catalog/cart prices already include VAT; the
|
|
173
|
+
* VAT breakdown is the portion contained within.
|
|
174
|
+
* - `EXCL_VAT` (B2B): prices are net; render "bez DPH" labels and show VAT
|
|
175
|
+
* added on top.
|
|
176
|
+
* - `CUSTOMER_CHOICE`: the customer toggles incl/excl.
|
|
177
|
+
* Pair with per-line `taxRate` + cart/order `taxBreakdown` to render VAT rows.
|
|
178
|
+
*/
|
|
179
|
+
priceDisplay: PriceDisplay;
|
|
180
|
+
/** Shop default VAT rate (percent, e.g. 21) for labelling a single-rate cart. */
|
|
181
|
+
vatRate: number;
|
|
182
|
+
}
|
|
183
|
+
/** Price presentation mode (Eshop.priceDisplay). See `CheckoutSettings.priceDisplay`. */
|
|
184
|
+
type PriceDisplay = "INCL_VAT" | "EXCL_VAT" | "CUSTOMER_CHOICE";
|
|
185
|
+
interface ShopInfo {
|
|
186
|
+
id: string;
|
|
187
|
+
name: string;
|
|
188
|
+
domain: string;
|
|
189
|
+
logo?: string;
|
|
190
|
+
favicon?: string;
|
|
191
|
+
isActive: boolean;
|
|
192
|
+
defaultLanguage: string;
|
|
193
|
+
supportedLanguages: string[];
|
|
194
|
+
defaultCurrency: string;
|
|
195
|
+
supportedCurrencies: string[];
|
|
196
|
+
metaTitle?: string;
|
|
197
|
+
metaDescription?: string;
|
|
198
|
+
allowGuestCheckout: boolean;
|
|
199
|
+
/** Shop runs in B2B / wholesale mode (unlocks B2B-oriented UX). */
|
|
200
|
+
b2bMode: boolean;
|
|
201
|
+
/**
|
|
202
|
+
* Whether quote requests ("Poptat množstevní cenu") make sense for this shop.
|
|
203
|
+
* Currently follows B2B mode. Gate the request-quote CTA on this flag rather
|
|
204
|
+
* than hardcoded template config.
|
|
205
|
+
*/
|
|
206
|
+
quotesEnabled: boolean;
|
|
207
|
+
/** Full merchant checkout & cart contract. Honour these in cart + checkout. */
|
|
208
|
+
checkout: CheckoutSettings;
|
|
209
|
+
/**
|
|
210
|
+
* Public shop identity for SEO / structured data (GAP-31). Reads of existing
|
|
211
|
+
* merchant data — feed into the Organization JSON-LD and degrade gracefully
|
|
212
|
+
* on nulls. Optional because cached ShopInfo payloads predating the field
|
|
213
|
+
* may still be served.
|
|
214
|
+
*/
|
|
215
|
+
seo?: ShopSeoIdentity;
|
|
216
|
+
}
|
|
217
|
+
/** Public shop identity for SEO / structured data (GAP-31). */
|
|
218
|
+
interface ShopSeoIdentity {
|
|
219
|
+
/** Merchant shop description — Organization JSON-LD `description`. */
|
|
220
|
+
description: string | null;
|
|
221
|
+
/** Public contact e-mail (shop e-mail sender config) for ContactPoint. */
|
|
222
|
+
contactEmail: string | null;
|
|
223
|
+
}
|
|
224
|
+
interface NewsletterSubscribeInput {
|
|
225
|
+
email: string;
|
|
226
|
+
/** Preferred locale (ISO-639-1) captured at signup. */
|
|
227
|
+
locale?: string;
|
|
228
|
+
/** Where the opt-in came from, e.g. "footer" or "checkout". */
|
|
229
|
+
source?: string;
|
|
230
|
+
/** Honeypot: keep empty. A filled value is treated as a bot and ignored. */
|
|
231
|
+
website?: string;
|
|
232
|
+
}
|
|
233
|
+
interface NewsletterSubscribeResult {
|
|
234
|
+
success: boolean;
|
|
235
|
+
/** True when this email was already an active subscriber. */
|
|
236
|
+
alreadySubscribed: boolean;
|
|
237
|
+
}
|
|
238
|
+
interface NewsletterUnsubscribeResult {
|
|
239
|
+
success: boolean;
|
|
240
|
+
}
|
|
241
|
+
interface ShopSeo {
|
|
242
|
+
locale: string;
|
|
243
|
+
title: string | null;
|
|
244
|
+
description: string | null;
|
|
245
|
+
keywords: string | null;
|
|
246
|
+
ogTitle: string | null;
|
|
247
|
+
ogDescription: string | null;
|
|
248
|
+
ogImage: string | null;
|
|
249
|
+
}
|
|
250
|
+
/** Kind of merchant-defined script. Typed presets render the right snippet from
|
|
251
|
+
* an id; RAW carries literal markup. */
|
|
252
|
+
type ShopScriptType = "GA4" | "GTM" | "META_PIXEL" | "GOOGLE_VERIFICATION" | "RAW";
|
|
253
|
+
/** Where in the document the script is injected. */
|
|
254
|
+
type ShopScriptPlacement = "HEAD" | "BODY_START" | "BODY_END";
|
|
255
|
+
/**
|
|
256
|
+
* A merchant-defined script delivered to the storefront for injection
|
|
257
|
+
* (analytics, pixels, verification, or arbitrary head/body markup).
|
|
258
|
+
* `value` is the id for typed entries, or the literal markup for RAW.
|
|
259
|
+
* When `consentRequired` is true the storefront must gate it behind the
|
|
260
|
+
* visitor's analytics cookie consent.
|
|
261
|
+
*/
|
|
262
|
+
interface ShopScript {
|
|
263
|
+
id: string;
|
|
264
|
+
type: ShopScriptType;
|
|
265
|
+
placement: ShopScriptPlacement;
|
|
266
|
+
value: string;
|
|
267
|
+
consentRequired: boolean;
|
|
268
|
+
}
|
|
269
|
+
interface ShopScripts {
|
|
270
|
+
scripts: ShopScript[];
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Money amount displayed to a customer in a chosen currency.
|
|
274
|
+
*
|
|
275
|
+
* Two cases:
|
|
276
|
+
* - **Fixed price** (preferred): merchant configured an explicit price for
|
|
277
|
+
* this currency. `isApproximate` is `false`/absent and `fxSource` is `null`.
|
|
278
|
+
* - **Approximate / FX-converted**: no fixed price for the requested
|
|
279
|
+
* currency, so Behio converted from the eshop's default currency using
|
|
280
|
+
* today's rate from `fxSource` (CNB or Frankfurter/ECB) plus the eshop's
|
|
281
|
+
* safety margin. UI should show a `≈` hint and offer the base price too.
|
|
282
|
+
*/
|
|
283
|
+
/**
|
|
284
|
+
* Payment method available at checkout. Returned by
|
|
285
|
+
* `GET /storefront/v1/catalog/payment-methods` filtered for the customer's
|
|
286
|
+
* chosen currency. Credentials (API keys, merchant ids) stay server-side
|
|
287
|
+
* — only customer-safe fields appear here.
|
|
288
|
+
*/
|
|
289
|
+
interface CheckoutPaymentMethod {
|
|
290
|
+
id: string;
|
|
291
|
+
/** Merchant-chosen label, e.g. "Kartou (Stripe)" or "Převodem na účet". */
|
|
292
|
+
name: string;
|
|
293
|
+
description?: string | null;
|
|
294
|
+
/** Provider id: "stripe" | "gopay" | "comgate" | "bank_transfer" | "cod" | "custom". */
|
|
295
|
+
provider: string;
|
|
296
|
+
/** Currencies this method accepts. Empty = any. */
|
|
297
|
+
currencies: string[];
|
|
298
|
+
/** Optional fee added to the order total (e.g. COD surcharge). */
|
|
299
|
+
fee?: number | null;
|
|
300
|
+
feeCurrency?: string | null;
|
|
301
|
+
/** Customer-safe slice of config: bank account, IBAN, instructions, … */
|
|
302
|
+
publicConfig?: Record<string, unknown>;
|
|
303
|
+
}
|
|
304
|
+
interface ProductPrice {
|
|
305
|
+
amount: number;
|
|
306
|
+
currency: string;
|
|
307
|
+
compareAtPrice?: number | null;
|
|
308
|
+
/** `true` when this amount was FX-converted from the eshop default currency. */
|
|
309
|
+
isApproximate?: boolean;
|
|
310
|
+
/** Provider id ("cnb" | "frankfurter" | "manual") when FX-converted. */
|
|
311
|
+
fxSource?: string | null;
|
|
312
|
+
/** Original amount in the eshop default currency before conversion. */
|
|
313
|
+
baseAmount?: number | null;
|
|
314
|
+
/** ISO code of the currency `baseAmount` is denominated in. */
|
|
315
|
+
baseCurrency?: string | null;
|
|
316
|
+
}
|
|
317
|
+
interface ProductVolumePrice {
|
|
318
|
+
minQuantity: number;
|
|
319
|
+
price: number;
|
|
320
|
+
currency?: string;
|
|
321
|
+
}
|
|
322
|
+
interface ProductVariant {
|
|
323
|
+
/**
|
|
324
|
+
* Eshop product ID of this variant (each variant is its own sellable eshop
|
|
325
|
+
* product). Pass it straight to `cart.addItem({productId: variant.id})` to add
|
|
326
|
+
* the chosen variant.
|
|
327
|
+
*/
|
|
328
|
+
id: string;
|
|
329
|
+
sku: string;
|
|
330
|
+
name: string;
|
|
331
|
+
/**
|
|
332
|
+
* Axis name/value pairs identifying this variant (e.g.
|
|
333
|
+
* `[{name: 'Barva', value: 'červená'}]`) — matches the wire shape the API
|
|
334
|
+
* actually sends. Join to `ProductDetail.variantAxes` by name + value.
|
|
335
|
+
*/
|
|
336
|
+
attributes: Array<{
|
|
337
|
+
name: string;
|
|
338
|
+
value: string;
|
|
339
|
+
}>;
|
|
340
|
+
/** `null` when prices are gated behind login for guests (B2B mode). */
|
|
341
|
+
price: ProductPrice | null;
|
|
342
|
+
inStock: boolean;
|
|
343
|
+
/** Exact remaining stock, or `null` when the merchant hides the count
|
|
344
|
+
* (showStockCount off) — treat null as "unknown", never as 0. */
|
|
345
|
+
stockQuantity?: number | null;
|
|
346
|
+
/** "Only X left" for this variant — same contract as ProductListItem.lowStockRemaining. */
|
|
347
|
+
lowStockRemaining?: number | null;
|
|
348
|
+
/**
|
|
349
|
+
* Cover image URL for the variant. Falls back to the parent product's
|
|
350
|
+
* cover when the variant has no photo of its own — see `imageIsInherited`.
|
|
351
|
+
*/
|
|
352
|
+
imageUrl?: string | null;
|
|
353
|
+
/**
|
|
354
|
+
* `true` when `imageUrl` is borrowed from the parent product because the
|
|
355
|
+
* variant has no cover image of its own. Use this to render a hint like
|
|
356
|
+
* "default photo" or to render the picture in a subtler style.
|
|
357
|
+
*/
|
|
358
|
+
imageIsInherited: boolean;
|
|
359
|
+
}
|
|
360
|
+
interface ProductLabel {
|
|
361
|
+
id: string;
|
|
362
|
+
slug: string;
|
|
363
|
+
name: string;
|
|
364
|
+
color?: string;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Resolved availability status of a product. Either a merchant preset
|
|
368
|
+
* ("skladem", "na objednávku", "předobjednávka", custom) or, when the product
|
|
369
|
+
* has none assigned, a status DERIVED from stock server-side. Render `label`
|
|
370
|
+
* as-is — it is already localized to the requested locale.
|
|
371
|
+
*/
|
|
372
|
+
interface ProductAvailability {
|
|
373
|
+
/**
|
|
374
|
+
* Stable machine code for styling hooks: a merchant preset slug (e.g.
|
|
375
|
+
* "preorder") or the derived `"in-stock"` / `"sold-out"`.
|
|
376
|
+
*/
|
|
377
|
+
code: string;
|
|
378
|
+
/** Localized display label (requested locale → shop default → slug). */
|
|
379
|
+
label: string;
|
|
380
|
+
/** Optional merchant-configured hex badge color (e.g. "#f59e0b"). */
|
|
381
|
+
color?: string | null;
|
|
382
|
+
/**
|
|
383
|
+
* "Available from" date (epoch ms) for preorder / on-order style states.
|
|
384
|
+
* Render as "Skladem od 20. 7." when present; null when not scheduled.
|
|
385
|
+
*/
|
|
386
|
+
restockAt?: number | null;
|
|
387
|
+
}
|
|
388
|
+
interface ProductListItem {
|
|
389
|
+
id: string;
|
|
390
|
+
slug: string;
|
|
391
|
+
name: string;
|
|
392
|
+
shortDescription?: string;
|
|
393
|
+
sku: string;
|
|
394
|
+
gtin?: string;
|
|
395
|
+
/** `null` when prices are gated behind login for guests (B2B mode). */
|
|
396
|
+
price: ProductPrice | null;
|
|
397
|
+
inStock: boolean;
|
|
398
|
+
/**
|
|
399
|
+
* Launch okno: sale window opens at this time (epoch ms); null/undefined =
|
|
400
|
+
* on sale since publish. Before it the product is visible but NOT
|
|
401
|
+
* purchasable — render a "Prodej startuje za ..." countdown instead of the
|
|
402
|
+
* buy button.
|
|
403
|
+
*/
|
|
404
|
+
saleStartAt?: number | null;
|
|
405
|
+
/** Sale window closes at this time (epoch ms); null/undefined = never closes. */
|
|
406
|
+
saleEndAt?: number | null;
|
|
407
|
+
/**
|
|
408
|
+
* Server-resolved "can this be bought RIGHT NOW": the sale window is open
|
|
409
|
+
* AND the product can be ordered (in stock, or the shop sells beyond
|
|
410
|
+
* stock). The cart/checkout enforce the same rule server-side — use this to
|
|
411
|
+
* disable the buy button, never re-derive the rule client-side.
|
|
412
|
+
*/
|
|
413
|
+
isPurchasable: boolean;
|
|
414
|
+
/**
|
|
415
|
+
* Early bird (time-based launch price) is active: `price.amount` already IS
|
|
416
|
+
* the discounted early-bird amount and the regular price sits in
|
|
417
|
+
* `price.compareAtPrice`. Applies in the eshop default currency only.
|
|
418
|
+
*/
|
|
419
|
+
earlyBirdActive: boolean;
|
|
420
|
+
/** When the active early bird ends (epoch ms) — render "Early bird do ...".
|
|
421
|
+
* Null when no early bird is active. */
|
|
422
|
+
earlyBirdUntil?: number | null;
|
|
423
|
+
/** Exact remaining stock, or `null` when the merchant hides the count
|
|
424
|
+
* (showStockCount off) — treat null as "unknown", never as 0. */
|
|
425
|
+
stockQuantity?: number | null;
|
|
426
|
+
/**
|
|
427
|
+
* "Zbývá posledních X kusů" nudge, computed SERVER-side. Non-null ONLY when
|
|
428
|
+
* the merchant enabled the low-stock indicator AND 0 < stock <= threshold;
|
|
429
|
+
* the value is the exact remaining quantity. Render the badge whenever this
|
|
430
|
+
* is a number — no client-side threshold math needed.
|
|
431
|
+
*/
|
|
432
|
+
lowStockRemaining?: number | null;
|
|
433
|
+
/** Resolved availability status (merchant preset or derived from stock). */
|
|
434
|
+
availability: ProductAvailability;
|
|
435
|
+
/** Cover image of the listing. The API returns an object (url + alt + order), never a bare string. */
|
|
436
|
+
image?: {
|
|
437
|
+
url: string;
|
|
438
|
+
alt: string | null;
|
|
439
|
+
order: number;
|
|
440
|
+
} | null;
|
|
441
|
+
labels: ProductLabel[];
|
|
442
|
+
isFeatured: boolean;
|
|
443
|
+
/**
|
|
444
|
+
* Minimum order quantity (units); null/undefined = no minimum. Start the
|
|
445
|
+
* quantity stepper here — the server rejects add-to-cart / checkout below it.
|
|
446
|
+
*/
|
|
447
|
+
minOrderQuantity?: number | null;
|
|
448
|
+
/**
|
|
449
|
+
* Order quantity step / multiple (units); null/undefined = any quantity. The
|
|
450
|
+
* stepper moves by this amount and the server rejects non-multiple quantities.
|
|
451
|
+
*/
|
|
452
|
+
orderQuantityStep?: number | null;
|
|
453
|
+
/**
|
|
454
|
+
* Cheapest applicable auto-promotion for this product (GAP-13), or null. Same
|
|
455
|
+
* priority-based selection the checkout uses, so a card badge matches what the
|
|
456
|
+
* customer pays. Render a badge chip + a STATIC end date ("do 20. 7.") on
|
|
457
|
+
* cards; keep the live countdown on the PDP only (no per-card tickers).
|
|
458
|
+
*/
|
|
459
|
+
activePromotion?: ProductPromotionSummary | null;
|
|
460
|
+
/**
|
|
461
|
+
* Rollover image URL for the card (GAP-27), from the product's HOVER-role
|
|
462
|
+
* image when the merchant set one. Null/absent = no hover image (show the
|
|
463
|
+
* cover only). Crossfade to it on desktop hover (opacity only, no transform).
|
|
464
|
+
*/
|
|
465
|
+
hoverImageUrl?: string | null;
|
|
466
|
+
/**
|
|
467
|
+
* Aggregate rating from APPROVED reviews (GAP-23): mean 1-5 rating, or null
|
|
468
|
+
* when the product has no approved reviews. Server-computed + cached. Render
|
|
469
|
+
* gold stars only when `ratingCount > 0`; do NOT compute this from the
|
|
470
|
+
* paginated reviews endpoint.
|
|
471
|
+
*/
|
|
472
|
+
ratingAverage?: number | null;
|
|
473
|
+
/** Number of approved reviews behind `ratingAverage` (0 when none). */
|
|
474
|
+
ratingCount?: number;
|
|
475
|
+
/**
|
|
476
|
+
* Last modification of the product record (epoch ms) — sitemap `lastmod`
|
|
477
|
+
* and `dateModified` structured data (GAP-31).
|
|
478
|
+
*/
|
|
479
|
+
updatedAt?: number;
|
|
480
|
+
}
|
|
481
|
+
/** Display-only summary of the promotion winning for a card (GAP-13). */
|
|
482
|
+
interface ProductPromotionSummary {
|
|
483
|
+
promotionId: string;
|
|
484
|
+
/** Merchant badge label ("1+1"); null → render "-{discountValue} %" from the discount. */
|
|
485
|
+
badgeText: string | null;
|
|
486
|
+
/** Merchant hex badge color; null falls back to the shop's sale color. */
|
|
487
|
+
badgeColor: string | null;
|
|
488
|
+
discountType: "PERCENTAGE" | "FIXED_AMOUNT" | "BUY_X_GET_Y";
|
|
489
|
+
discountValue: number;
|
|
490
|
+
/** Promotion end (epoch ms), or null for open-ended. */
|
|
491
|
+
endsAt: number | null;
|
|
492
|
+
/** Merchant opted into a countdown (the PDP shows a ticker; cards stay static). */
|
|
493
|
+
showCountdown: boolean;
|
|
494
|
+
}
|
|
495
|
+
/** A single responsive derivative (size + format) of a media image. */
|
|
496
|
+
interface ProductMediaVariant {
|
|
497
|
+
variant: "thumb" | "medium" | "large" | "xlarge";
|
|
498
|
+
format: "jpeg" | "webp" | "avif";
|
|
499
|
+
url: string;
|
|
500
|
+
width: number;
|
|
501
|
+
height: number;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* A product gallery entry (image or video), sourced from the inventory item
|
|
505
|
+
* so it is shared across every storefront listing the product. Images carry
|
|
506
|
+
* responsive `variants` (webp/avif/jpeg in three sizes) for fast LCP; pick
|
|
507
|
+
* the smallest format the client supports.
|
|
508
|
+
*/
|
|
509
|
+
interface ProductMedia {
|
|
510
|
+
id: string;
|
|
511
|
+
type: "IMAGE" | "VIDEO";
|
|
512
|
+
/** Original uploaded file URL. */
|
|
513
|
+
url: string;
|
|
514
|
+
alt?: string | null;
|
|
515
|
+
isCover: boolean;
|
|
516
|
+
order: number;
|
|
517
|
+
variants: ProductMediaVariant[];
|
|
518
|
+
}
|
|
519
|
+
/** One value on a variant axis, with optional merchant-configured swatch data. */
|
|
520
|
+
interface VariantAxisValue {
|
|
521
|
+
/** Human-readable value; matches `variant.attributes[].value` on this axis. */
|
|
522
|
+
value: string;
|
|
523
|
+
/** Hex color for SWATCH_COLOR rendering. */
|
|
524
|
+
swatchColor: string | null;
|
|
525
|
+
/** Image URL for SWATCH_IMAGE rendering. */
|
|
526
|
+
swatchImage: string | null;
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* A variant axis ("Barva", "Velikost") with the merchant's display
|
|
530
|
+
* configuration. `displayType` is "BUTTON" when the merchant has not
|
|
531
|
+
* configured the axis (the storefront's historical default). Join to
|
|
532
|
+
* `variants[].attributes` by axis `name` + `value`.
|
|
533
|
+
*/
|
|
534
|
+
interface VariantAxis {
|
|
535
|
+
name: string;
|
|
536
|
+
displayType: "DROPDOWN" | "BUTTON" | "SWATCH_COLOR" | "SWATCH_IMAGE";
|
|
537
|
+
order: number;
|
|
538
|
+
/** Values present among the purchasable variants, in admin-defined order. */
|
|
539
|
+
values: VariantAxisValue[];
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* One custom-field (data-group value) rendered as a spec-table row. BOOLEAN
|
|
543
|
+
* carries a typed `booleanValue` (value is null) so the storefront can localize
|
|
544
|
+
* Ano/Ne; MONEY carries its currency in `unit`; PERCENTAGE carries "%" in
|
|
545
|
+
* `unit`.
|
|
546
|
+
*/
|
|
547
|
+
interface ProductCustomField {
|
|
548
|
+
key: string;
|
|
549
|
+
name: string;
|
|
550
|
+
/** TEXT | NUMBER | DECIMAL | BOOLEAN | DATE | TIME | DATETIME | PERCENTAGE | MONEY | ITEM_LIST | ... */
|
|
551
|
+
type: string;
|
|
552
|
+
value: string | null;
|
|
553
|
+
booleanValue: boolean | null;
|
|
554
|
+
unit: string | null;
|
|
555
|
+
}
|
|
556
|
+
/** A spec-table section (one inventory data group) with its fields. */
|
|
557
|
+
interface ProductCustomFieldGroup {
|
|
558
|
+
key: string;
|
|
559
|
+
name: string;
|
|
560
|
+
fields: ProductCustomField[];
|
|
561
|
+
}
|
|
562
|
+
interface ProductDetail extends ProductListItem {
|
|
563
|
+
longDescription?: string;
|
|
564
|
+
/**
|
|
565
|
+
* @deprecated Legacy per-listing images. Prefer `media`. Each carries its
|
|
566
|
+
* `role` (COVER | LISTING | HOVER | GALLERY) so the storefront can pick a
|
|
567
|
+
* specific image deliberately (GAP-27).
|
|
568
|
+
*/
|
|
569
|
+
images: Array<{
|
|
570
|
+
url: string;
|
|
571
|
+
alt?: string;
|
|
572
|
+
order: number;
|
|
573
|
+
role?: string;
|
|
574
|
+
}>;
|
|
575
|
+
/** Product gallery (images + videos) with responsive derivatives. */
|
|
576
|
+
media: ProductMedia[];
|
|
577
|
+
categories: Array<{
|
|
578
|
+
id: string;
|
|
579
|
+
slug: string;
|
|
580
|
+
name: string;
|
|
581
|
+
}>;
|
|
582
|
+
variants: ProductVariant[];
|
|
583
|
+
/**
|
|
584
|
+
* Variant axes with display config (dropdown / buttons / swatches).
|
|
585
|
+
* Empty when the product has no variants.
|
|
586
|
+
*/
|
|
587
|
+
variantAxes: VariantAxis[];
|
|
588
|
+
volumePricing: ProductVolumePrice[];
|
|
589
|
+
/**
|
|
590
|
+
* Structured product parameters from custom fields (inventory data groups),
|
|
591
|
+
* grouped into spec-table sections (GAP-12). Empty when the product has no
|
|
592
|
+
* data-group values. Distinct from `longDescription` (free HTML): this is
|
|
593
|
+
* machine-readable key/value data for a "Parametry" table + comparison
|
|
594
|
+
* engines. (Corrected from the old untyped `Record<string, unknown>` — the
|
|
595
|
+
* API never populated that; it now sends this structured shape.)
|
|
596
|
+
*/
|
|
597
|
+
customFields: ProductCustomFieldGroup[];
|
|
598
|
+
seo: {
|
|
599
|
+
title?: string | null;
|
|
600
|
+
description?: string | null;
|
|
601
|
+
keywords?: string | null;
|
|
602
|
+
ogTitle?: string | null;
|
|
603
|
+
ogDescription?: string | null;
|
|
604
|
+
ogImage?: string | null;
|
|
605
|
+
};
|
|
606
|
+
productGroups?: Array<{
|
|
607
|
+
slug: string;
|
|
608
|
+
name: string;
|
|
609
|
+
products: ProductListItem[];
|
|
610
|
+
}>;
|
|
611
|
+
/** Product weight (from warehouse item) */
|
|
612
|
+
weight?: number | null;
|
|
613
|
+
/** Weight unit: GRAM, KILOGRAM, TONNE */
|
|
614
|
+
weightUnit?: string | null;
|
|
615
|
+
/**
|
|
616
|
+
* Digital product delivery (GAP-07): true when the product has at least one
|
|
617
|
+
* active digital asset (PDF, MP3, ...) delivered instantly after purchase.
|
|
618
|
+
*/
|
|
619
|
+
isDigital?: boolean;
|
|
620
|
+
}
|
|
621
|
+
interface Category {
|
|
622
|
+
id: string;
|
|
623
|
+
slug: string;
|
|
624
|
+
name: string;
|
|
625
|
+
description?: string;
|
|
626
|
+
imageUrl?: string;
|
|
627
|
+
children: Category[];
|
|
628
|
+
productCount?: number;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Navigation menu built in the admin (Navigace). Matches the backend
|
|
632
|
+
* `GET /storefront/v1/catalog/menu/{handle}` response exactly. Item labels are
|
|
633
|
+
* resolved in the requested locale; typed refs resolve to {type, slug} at read
|
|
634
|
+
* time so category/page/product renames flow through automatically.
|
|
635
|
+
*/
|
|
636
|
+
type MenuItemType = "CATEGORY" | "PAGE" | "LINK" | "COLLECTION" | "PRODUCT";
|
|
637
|
+
/** Resolved target of a typed menu item. Null on LINK items (use `url`). */
|
|
638
|
+
interface MenuItemRef {
|
|
639
|
+
type: MenuItemType;
|
|
640
|
+
slug: string;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Badge tone preset for a menu item chip. Maps to storefront design tokens on
|
|
644
|
+
* the template side (SALE -> danger, NEW -> success, ACCENT -> primary,
|
|
645
|
+
* NEUTRAL -> current text color). Custom hex colors override the preset.
|
|
646
|
+
*/
|
|
647
|
+
type BadgeTone = "NEUTRAL" | "SALE" | "NEW" | "ACCENT";
|
|
648
|
+
interface MenuItem {
|
|
649
|
+
id: string;
|
|
650
|
+
type: MenuItemType;
|
|
651
|
+
/** Resolved label in the requested locale. */
|
|
652
|
+
label: string;
|
|
653
|
+
description?: string | null;
|
|
654
|
+
/** LINK items only: the raw URL to navigate to. Null on typed items. */
|
|
655
|
+
url?: string | null;
|
|
656
|
+
/** Typed items (CATEGORY/PAGE/COLLECTION/PRODUCT): resolved {type, slug}. Null on LINK. */
|
|
657
|
+
ref?: MenuItemRef | null;
|
|
658
|
+
/** Optional badge chip text (e.g. "Novinka", "Sleva"). */
|
|
659
|
+
badgeText?: string | null;
|
|
660
|
+
/**
|
|
661
|
+
* Badge tone preset driving the chip colors from storefront tokens. Always
|
|
662
|
+
* present. Custom `badgeColor`/`badgeTextColor` override it when set.
|
|
663
|
+
*/
|
|
664
|
+
badgeTone: BadgeTone;
|
|
665
|
+
/** Custom badge background hex (overrides `badgeTone`), or null. */
|
|
666
|
+
badgeColor?: string | null;
|
|
667
|
+
/** Custom badge text hex, or null. */
|
|
668
|
+
badgeTextColor?: string | null;
|
|
669
|
+
/** Custom hex for the item label text itself, or null to inherit. */
|
|
670
|
+
labelColor?: string | null;
|
|
671
|
+
/** Lucide icon slug rendered next to the label, or null. */
|
|
672
|
+
icon?: string | null;
|
|
673
|
+
/** Emphasize this item (bold/accent). */
|
|
674
|
+
isHighlighted: boolean;
|
|
675
|
+
/** LINK items: open the target in a new browser tab. Always false on typed items. */
|
|
676
|
+
openInNewTab: boolean;
|
|
677
|
+
/** Processed image URL for mega-menu tiles (null when no image set). */
|
|
678
|
+
imageUrl?: string | null;
|
|
679
|
+
/** Nested items, up to depth 3. */
|
|
680
|
+
children: MenuItem[];
|
|
681
|
+
}
|
|
682
|
+
interface Menu {
|
|
683
|
+
handle: string;
|
|
684
|
+
name: string;
|
|
685
|
+
/** Locale the labels are resolved in. */
|
|
686
|
+
locale: string;
|
|
687
|
+
items: MenuItem[];
|
|
688
|
+
}
|
|
689
|
+
interface CategoryDetail extends Category {
|
|
690
|
+
/**
|
|
691
|
+
* SEO/Open Graph for the category page. Matches the backend's nested `seo`
|
|
692
|
+
* shape (the old flat `seoTitle`/`seoDescription` never matched what the API
|
|
693
|
+
* returned). `keywords` is always null for categories.
|
|
694
|
+
*/
|
|
695
|
+
seo?: {
|
|
696
|
+
title?: string | null;
|
|
697
|
+
description?: string | null;
|
|
698
|
+
keywords?: string | null;
|
|
699
|
+
ogTitle?: string | null;
|
|
700
|
+
ogDescription?: string | null;
|
|
701
|
+
ogImage?: string | null;
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
type DataGroupFieldType = "TEXT" | "NUMBER" | "DECIMAL" | "BOOLEAN" | "DATE" | "TIME" | "DATETIME" | "PERCENTAGE" | "MONEY" | "ASSET" | "ITEM_LIST" | "DYNAMIC_NUMBER_CALCULATION_FROM_OTHERS";
|
|
705
|
+
interface FilterField {
|
|
706
|
+
key: string;
|
|
707
|
+
name: string;
|
|
708
|
+
type: DataGroupFieldType | string;
|
|
709
|
+
groupKey: string;
|
|
710
|
+
groupName: string;
|
|
711
|
+
values?: string[];
|
|
712
|
+
}
|
|
713
|
+
interface FacetValue {
|
|
714
|
+
/** Raw stored value (normalized), for exact filtering. */
|
|
715
|
+
value: string;
|
|
716
|
+
/** Human-readable label. */
|
|
717
|
+
label: string;
|
|
718
|
+
/** Stable URL slug for SEO landing pages (e.g. "cerna"); pass back via
|
|
719
|
+
* `ProductsQuery.facets`. */
|
|
720
|
+
slug: string;
|
|
721
|
+
/** Count under the current selection (this facet excluded). 0 = present in
|
|
722
|
+
* context but excluded by other filters — render disabled, don't hide. */
|
|
723
|
+
count: number;
|
|
724
|
+
}
|
|
725
|
+
interface FacetRange {
|
|
726
|
+
min: number | null;
|
|
727
|
+
max: number | null;
|
|
728
|
+
}
|
|
729
|
+
interface Facet {
|
|
730
|
+
key: string;
|
|
731
|
+
name: string;
|
|
732
|
+
/** "enum" (checkboxes), "range" (slider) or "boolean". */
|
|
733
|
+
type: "enum" | "range" | "boolean" | string;
|
|
734
|
+
groupKey: string;
|
|
735
|
+
groupName: string;
|
|
736
|
+
/** Underlying data-group field type (TEXT, NUMBER, MONEY, ...). */
|
|
737
|
+
fieldType: string;
|
|
738
|
+
/** enum/boolean facets: selectable values with counts. */
|
|
739
|
+
values?: FacetValue[];
|
|
740
|
+
/** range facets: numeric bounds within the current context. */
|
|
741
|
+
range?: FacetRange | null;
|
|
742
|
+
/** currency for MONEY range facets, "%" for PERCENTAGE, else null. */
|
|
743
|
+
unit?: string | null;
|
|
744
|
+
}
|
|
745
|
+
interface FacetPriceRange {
|
|
746
|
+
min: number | null;
|
|
747
|
+
max: number | null;
|
|
748
|
+
currency: string;
|
|
749
|
+
}
|
|
750
|
+
interface FacetRatingBucket {
|
|
751
|
+
from: number;
|
|
752
|
+
count: number;
|
|
753
|
+
}
|
|
754
|
+
interface FacetLabel {
|
|
755
|
+
slug: string;
|
|
756
|
+
name: string;
|
|
757
|
+
color?: string | null;
|
|
758
|
+
count: number;
|
|
759
|
+
}
|
|
760
|
+
interface FacetCategory {
|
|
761
|
+
slug: string;
|
|
762
|
+
name: string;
|
|
763
|
+
count: number;
|
|
764
|
+
}
|
|
765
|
+
interface FacetAvailability {
|
|
766
|
+
inStockCount: number;
|
|
767
|
+
outOfStockCount: number;
|
|
768
|
+
}
|
|
769
|
+
interface FacetsResponse {
|
|
770
|
+
priceRange: FacetPriceRange | null;
|
|
771
|
+
facets: Facet[];
|
|
772
|
+
availability: FacetAvailability;
|
|
773
|
+
rating: FacetRatingBucket[];
|
|
774
|
+
labels: FacetLabel[];
|
|
775
|
+
/** Child subcategories of the current category (or top-level), with counts. */
|
|
776
|
+
categories: FacetCategory[];
|
|
777
|
+
}
|
|
778
|
+
declare const ProductSort: {
|
|
779
|
+
readonly PRICE_ASC: "price_asc";
|
|
780
|
+
readonly PRICE_DESC: "price_desc";
|
|
781
|
+
readonly NAME_ASC: "name_asc";
|
|
782
|
+
readonly NAME_DESC: "name_desc";
|
|
783
|
+
readonly NEWEST: "newest";
|
|
784
|
+
readonly FEATURED: "featured";
|
|
785
|
+
readonly BESTSELLING: "bestselling";
|
|
786
|
+
readonly RATING: "rating";
|
|
787
|
+
};
|
|
788
|
+
type ProductSortValue = (typeof ProductSort)[keyof typeof ProductSort];
|
|
789
|
+
declare const OrderStatuses: {
|
|
790
|
+
readonly PENDING: "PENDING";
|
|
791
|
+
readonly CONFIRMED: "CONFIRMED";
|
|
792
|
+
readonly PROCESSING: "PROCESSING";
|
|
793
|
+
readonly SHIPPED: "SHIPPED";
|
|
794
|
+
readonly DELIVERED: "DELIVERED";
|
|
795
|
+
readonly CANCELLED: "CANCELLED";
|
|
796
|
+
readonly REFUNDED: "REFUNDED";
|
|
797
|
+
};
|
|
798
|
+
declare const PaymentStatuses: {
|
|
799
|
+
readonly UNPAID: "UNPAID";
|
|
800
|
+
readonly PAID: "PAID";
|
|
801
|
+
readonly PARTIALLY_REFUNDED: "PARTIALLY_REFUNDED";
|
|
802
|
+
readonly REFUNDED: "REFUNDED";
|
|
803
|
+
};
|
|
804
|
+
declare const FulfillmentStatuses: {
|
|
805
|
+
readonly UNFULFILLED: "UNFULFILLED";
|
|
806
|
+
readonly PARTIALLY_FULFILLED: "PARTIALLY_FULFILLED";
|
|
807
|
+
readonly FULFILLED: "FULFILLED";
|
|
808
|
+
};
|
|
809
|
+
declare const AddressTypes: {
|
|
810
|
+
readonly SHIPPING: "SHIPPING";
|
|
811
|
+
readonly BILLING: "BILLING";
|
|
812
|
+
};
|
|
813
|
+
type AddressType = (typeof AddressTypes)[keyof typeof AddressTypes];
|
|
814
|
+
interface ProductsQuery {
|
|
815
|
+
page?: number;
|
|
816
|
+
limit?: number;
|
|
817
|
+
/** Single category slug (OR logic with categories array) */
|
|
818
|
+
category?: string;
|
|
819
|
+
/** Multiple category slugs (OR logic — product in ANY of these categories) */
|
|
820
|
+
categories?: string[];
|
|
821
|
+
/** Single label slug */
|
|
822
|
+
label?: string;
|
|
823
|
+
priceMin?: number;
|
|
824
|
+
priceMax?: number;
|
|
825
|
+
currency?: string;
|
|
826
|
+
locale?: string;
|
|
827
|
+
sort?: ProductSortValue;
|
|
828
|
+
inStock?: boolean;
|
|
829
|
+
/** Minimum aggregate rating, e.g. 4 for "4 and up". */
|
|
830
|
+
ratingMin?: number;
|
|
831
|
+
search?: string;
|
|
832
|
+
/** Custom-field filters. A value may be an array = multi-select (OR within
|
|
833
|
+
* the key), e.g. {"barva": ["cerna", "bila"]}. */
|
|
834
|
+
customFields?: Record<string, string | number | boolean | string[] | unknown>;
|
|
835
|
+
/** Slug-based facet selection for SEO URLs: facet key -> value slugs, e.g.
|
|
836
|
+
* {"barva": ["cerna"]}. Resolved server-side to the underlying values. */
|
|
837
|
+
facets?: Record<string, string[]>;
|
|
838
|
+
/** Filter by specific product IDs (comma-separated in URL) */
|
|
839
|
+
ids?: string[];
|
|
840
|
+
/** Filter by specific product slugs */
|
|
841
|
+
slugs?: string[];
|
|
842
|
+
/** Multiple labels (AND logic — product must have ALL) */
|
|
843
|
+
labels?: string[];
|
|
844
|
+
/** Exclude specific product IDs (e.g. for "related products" excluding current) */
|
|
845
|
+
excludeIds?: string[];
|
|
846
|
+
/** Exclude products in specific categories */
|
|
847
|
+
excludeCategories?: string[];
|
|
848
|
+
/** Only products with compareAtPrice (on sale) */
|
|
849
|
+
hasDiscount?: boolean;
|
|
850
|
+
/** Only featured products */
|
|
851
|
+
isFeatured?: boolean;
|
|
852
|
+
/** Products created after timestamp (epoch ms) */
|
|
853
|
+
createdAfter?: number;
|
|
854
|
+
}
|
|
855
|
+
interface AuthTokens {
|
|
856
|
+
accessToken: string;
|
|
857
|
+
refreshToken: string;
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Result of a registration. When the eshop requires admin approval,
|
|
861
|
+
* `pendingApproval` is true and the tokens are null (the account is created but
|
|
862
|
+
* inactive and can't log in until approved) — the storefront should show a
|
|
863
|
+
* "waiting for approval" message instead of a logged-in session.
|
|
864
|
+
*/
|
|
865
|
+
interface RegisterResult {
|
|
866
|
+
pendingApproval: boolean;
|
|
867
|
+
accessToken: string | null;
|
|
868
|
+
refreshToken: string | null;
|
|
869
|
+
}
|
|
870
|
+
interface RegisterInput {
|
|
871
|
+
email: string;
|
|
872
|
+
password: string;
|
|
873
|
+
firstName?: string;
|
|
874
|
+
lastName?: string;
|
|
875
|
+
}
|
|
876
|
+
interface LoginInput {
|
|
877
|
+
email: string;
|
|
878
|
+
password: string;
|
|
879
|
+
}
|
|
880
|
+
interface CartItemProduct {
|
|
881
|
+
slug: string;
|
|
882
|
+
name: string;
|
|
883
|
+
sku: string;
|
|
884
|
+
imageUrl?: string;
|
|
885
|
+
inStock: boolean;
|
|
886
|
+
currentPrice: number;
|
|
887
|
+
/** Minimum order quantity (units); null = no minimum. Clamp the cart
|
|
888
|
+
* stepper's lower bound to this (GAP-48). */
|
|
889
|
+
minOrderQuantity?: number | null;
|
|
890
|
+
/** Order quantity step/multiple (units); null = any. Move the cart stepper
|
|
891
|
+
* by this amount so quantities stay valid. */
|
|
892
|
+
orderQuantityStep?: number | null;
|
|
893
|
+
}
|
|
894
|
+
interface CartItem {
|
|
895
|
+
id: string;
|
|
896
|
+
/**
|
|
897
|
+
* Eshop product ID of the sellable unit on this line. A variant is its own
|
|
898
|
+
* product, so this is the exact product/variant the customer added — use it
|
|
899
|
+
* to deep-link back to the product page.
|
|
900
|
+
*/
|
|
901
|
+
productId: string;
|
|
902
|
+
product: CartItemProduct;
|
|
903
|
+
quantity: number;
|
|
904
|
+
unitPrice: number;
|
|
905
|
+
totalPrice: number;
|
|
906
|
+
priceChanged: boolean;
|
|
907
|
+
volumePriceApplied: boolean;
|
|
908
|
+
/** VAT rate for this line in percent (e.g. 21). Estimated from the shop /
|
|
909
|
+
* product rate; refined by the shipping country at checkout (GAP-30). */
|
|
910
|
+
taxRate: number;
|
|
911
|
+
/** Net amount for this line (without VAT) = totalPrice. */
|
|
912
|
+
netAmount: number;
|
|
913
|
+
/** VAT amount for this line at `taxRate`. */
|
|
914
|
+
taxAmount: number;
|
|
915
|
+
/** Gross amount for this line (net + VAT). */
|
|
916
|
+
grossAmount: number;
|
|
917
|
+
}
|
|
918
|
+
/** One VAT rate's slice of a cart or order (GAP-30). Render "DPH {rate} %:
|
|
919
|
+
* {taxAmount}" summary rows from these. `netAmount + taxAmount = grossAmount`. */
|
|
920
|
+
interface TaxBreakdownLine {
|
|
921
|
+
/** VAT rate in percent, e.g. 21 or 12 or 0. */
|
|
922
|
+
rate: number;
|
|
923
|
+
/** Base amount (net, without VAT) taxed at this rate. */
|
|
924
|
+
netAmount: number;
|
|
925
|
+
/** VAT amount charged at this rate. */
|
|
926
|
+
taxAmount: number;
|
|
927
|
+
/** Gross amount (net + VAT) at this rate. */
|
|
928
|
+
grossAmount: number;
|
|
929
|
+
}
|
|
930
|
+
interface CartDiscount {
|
|
931
|
+
code: string;
|
|
932
|
+
type: string;
|
|
933
|
+
value: number;
|
|
934
|
+
}
|
|
935
|
+
/** One automatically applied promotion, surfaced as a discount line on the cart.
|
|
936
|
+
* Covers PERCENTAGE / FIXED_AMOUNT / BUY_X_GET_Y promos; the amount is already
|
|
937
|
+
* netted into `grandTotal`. */
|
|
938
|
+
interface CartPromotion {
|
|
939
|
+
slug: string;
|
|
940
|
+
name: string;
|
|
941
|
+
/** Total money saved on the cart by this promotion. */
|
|
942
|
+
discountAmount: number;
|
|
943
|
+
}
|
|
944
|
+
interface Cart {
|
|
945
|
+
id: string;
|
|
946
|
+
sessionToken?: string;
|
|
947
|
+
items: CartItem[];
|
|
948
|
+
subtotal: number;
|
|
949
|
+
discountTotal: number;
|
|
950
|
+
discount?: CartDiscount;
|
|
951
|
+
/** Auto-apply promotion discount lines (sale/BOGO). */
|
|
952
|
+
appliedPromotions: CartPromotion[];
|
|
953
|
+
/** Sum of `appliedPromotions[].discountAmount`; already reflected in `grandTotal`. */
|
|
954
|
+
promotionDiscountTotal: number;
|
|
955
|
+
grandTotal: number;
|
|
956
|
+
/** Total VAT contained in / added to the cart across all lines (GAP-30). An
|
|
957
|
+
* estimate finalized at checkout once the shipping country is known. */
|
|
958
|
+
taxTotal: number;
|
|
959
|
+
/** VAT split by rate for "DPH 21 %: X Kč" summary rows. Empty for a
|
|
960
|
+
* non-VAT-payer shop. */
|
|
961
|
+
taxBreakdown: TaxBreakdownLine[];
|
|
962
|
+
currency: string;
|
|
963
|
+
itemCount: number;
|
|
964
|
+
/** Applied gift cards (multi). They deduct at checkout (consumed in order, each
|
|
965
|
+
* min(balance, remaining due), last one partially), so they do not change
|
|
966
|
+
* `grandTotal` here; use them to list applied cards + balances in the cart. */
|
|
967
|
+
giftCards: GiftCardSummary[];
|
|
968
|
+
/** Bundle lines in the cart, separate from `items`. Manage with
|
|
969
|
+
* `cart.updateBundleQuantity` / `cart.removeBundle`. */
|
|
970
|
+
bundleLines: CartBundleLine[];
|
|
971
|
+
}
|
|
972
|
+
/** One product inside a bundle line. */
|
|
973
|
+
interface CartBundleLineItem {
|
|
974
|
+
productId: string;
|
|
975
|
+
name: string;
|
|
976
|
+
sku: string;
|
|
977
|
+
quantity: number;
|
|
978
|
+
}
|
|
979
|
+
/** A bundle added to the cart, with its own quantity + price snapshot. */
|
|
980
|
+
interface CartBundleLine {
|
|
981
|
+
id: string;
|
|
982
|
+
bundleId: string;
|
|
983
|
+
bundleSlug: string;
|
|
984
|
+
bundleName: string;
|
|
985
|
+
quantity: number;
|
|
986
|
+
/** Snapshot of the bundle's per-unit price when it was added. */
|
|
987
|
+
bundlePriceSnapshot: number;
|
|
988
|
+
currency: string;
|
|
989
|
+
items: CartBundleLineItem[];
|
|
990
|
+
}
|
|
991
|
+
/** A gift card applied to the cart, with its current balance. */
|
|
992
|
+
interface GiftCardSummary {
|
|
993
|
+
code: string;
|
|
994
|
+
balance: number;
|
|
995
|
+
currency: string;
|
|
996
|
+
}
|
|
997
|
+
interface AddToCartInput {
|
|
998
|
+
/**
|
|
999
|
+
* Eshop product ID of the sellable unit. A variant is its own eshop product,
|
|
1000
|
+
* so to add a chosen variant just pass that variant's `id` (from
|
|
1001
|
+
* `ProductDetail.variants[].id`) here — there is no separate variant field.
|
|
1002
|
+
*/
|
|
1003
|
+
productId: string;
|
|
1004
|
+
quantity: number;
|
|
1005
|
+
}
|
|
1006
|
+
interface CheckoutAddress {
|
|
1007
|
+
firstName: string;
|
|
1008
|
+
lastName: string;
|
|
1009
|
+
company?: string;
|
|
1010
|
+
/** Company registration number (IČO). Required when `ShopInfo.checkout`
|
|
1011
|
+
* requires tax ids; loosely validated (6-12 digits). */
|
|
1012
|
+
companyId?: string;
|
|
1013
|
+
/** VAT id (DIČ). Required alongside `companyId` when tax ids are required;
|
|
1014
|
+
* loosely validated (optional 2-letter country prefix + 6-12 digits). */
|
|
1015
|
+
vatId?: string;
|
|
1016
|
+
street: string;
|
|
1017
|
+
city: string;
|
|
1018
|
+
zip: string;
|
|
1019
|
+
country: string;
|
|
1020
|
+
phone?: string;
|
|
1021
|
+
}
|
|
1022
|
+
interface CheckoutInput {
|
|
1023
|
+
/**
|
|
1024
|
+
* Consent-gated Behio Analytics visitor id (behio_visitor_id). Optional;
|
|
1025
|
+
* lets the backend attribute the order to the visitor journey. Send it only
|
|
1026
|
+
* when the visitor granted analytics consent.
|
|
1027
|
+
*/
|
|
1028
|
+
analyticsVisitorId?: string;
|
|
1029
|
+
shippingAddress: CheckoutAddress;
|
|
1030
|
+
billingAddress: CheckoutAddress;
|
|
1031
|
+
email: string;
|
|
1032
|
+
phone?: string;
|
|
1033
|
+
customerNote?: string;
|
|
1034
|
+
/**
|
|
1035
|
+
* Legal / marketing consent echoed from the checkout checkboxes. Render the
|
|
1036
|
+
* boxes from `ShopInfo.checkout` (requireTermsConsent / requireGdprConsent /
|
|
1037
|
+
* newsletterOptInDefault) and send the customer's choice. The backend rejects
|
|
1038
|
+
* the order when a required consent is not `true`.
|
|
1039
|
+
*/
|
|
1040
|
+
termsConsent?: boolean;
|
|
1041
|
+
gdprConsent?: boolean;
|
|
1042
|
+
newsletterOptIn?: boolean;
|
|
1043
|
+
/**
|
|
1044
|
+
* Chosen shipping method. Required whenever the eshop has at least one
|
|
1045
|
+
* enabled shipping method — the backend rejects the order without it.
|
|
1046
|
+
* Prefer also sending `shippingQuoteId` from `shipping.quote()`; with only
|
|
1047
|
+
* the method id the backend re-quotes the cart server-side.
|
|
1048
|
+
*/
|
|
1049
|
+
shippingMethodId?: string;
|
|
1050
|
+
/**
|
|
1051
|
+
* Quote id from `shipping.quote()` — pins the exact server-computed price
|
|
1052
|
+
* the customer saw. Expired quotes are re-quoted automatically; a consumed
|
|
1053
|
+
* or foreign quote is rejected.
|
|
1054
|
+
*/
|
|
1055
|
+
shippingQuoteId?: string;
|
|
1056
|
+
/**
|
|
1057
|
+
* Chosen pickup point `externalId` from `shipping.getPickupPoints()`.
|
|
1058
|
+
* REQUIRED when the resolved shipping method has `supportsPickupPoints`;
|
|
1059
|
+
* the backend rejects the order without it. Snapshotted onto the order.
|
|
1060
|
+
*/
|
|
1061
|
+
pickupPointId?: string;
|
|
1062
|
+
paymentMethodId?: string;
|
|
1063
|
+
/**
|
|
1064
|
+
* Loyalty points to redeem on this order. Validated server-side against the
|
|
1065
|
+
* customer's actual balance and the program's redemption cap; ignored for
|
|
1066
|
+
* guests. See `customer.getLoyalty()` for the available balance.
|
|
1067
|
+
*/
|
|
1068
|
+
redeemLoyaltyPoints?: number;
|
|
1069
|
+
}
|
|
1070
|
+
type OrderStatus = (typeof OrderStatuses)[keyof typeof OrderStatuses];
|
|
1071
|
+
type PaymentStatus = (typeof PaymentStatuses)[keyof typeof PaymentStatuses];
|
|
1072
|
+
type FulfillmentStatus = (typeof FulfillmentStatuses)[keyof typeof FulfillmentStatuses];
|
|
1073
|
+
interface OrderListItem {
|
|
1074
|
+
id: string;
|
|
1075
|
+
orderNumber: string;
|
|
1076
|
+
status: OrderStatus;
|
|
1077
|
+
paymentStatus: PaymentStatus;
|
|
1078
|
+
grandTotal: number;
|
|
1079
|
+
currency: string;
|
|
1080
|
+
itemCount: number;
|
|
1081
|
+
createdAt: number;
|
|
1082
|
+
}
|
|
1083
|
+
interface OrderItem {
|
|
1084
|
+
productName: string;
|
|
1085
|
+
sku: string;
|
|
1086
|
+
imageUrl?: string;
|
|
1087
|
+
quantity: number;
|
|
1088
|
+
unitPrice: number;
|
|
1089
|
+
totalPrice: number;
|
|
1090
|
+
totalPriceWithTax: number;
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* PII-minimized order view returned by `orders.track(token)`. The tracking
|
|
1094
|
+
* token is shared in URLs and e-mails, so this deliberately omits full
|
|
1095
|
+
* address, phone, billing and customer note, and masks the email.
|
|
1096
|
+
*/
|
|
1097
|
+
interface OrderTracking {
|
|
1098
|
+
orderNumber: string;
|
|
1099
|
+
status: OrderStatus;
|
|
1100
|
+
paymentStatus: PaymentStatus;
|
|
1101
|
+
fulfillmentStatus: FulfillmentStatus;
|
|
1102
|
+
currency: string;
|
|
1103
|
+
grandTotal: number;
|
|
1104
|
+
/** Masked, e.g. "j***@e***.cz" */
|
|
1105
|
+
emailMasked: string;
|
|
1106
|
+
shippingCity: string | null;
|
|
1107
|
+
shippingCountry: string | null;
|
|
1108
|
+
items: OrderItem[];
|
|
1109
|
+
createdAt: number;
|
|
1110
|
+
}
|
|
1111
|
+
interface OrderStatusHistory {
|
|
1112
|
+
fromStatus?: OrderStatus;
|
|
1113
|
+
toStatus: OrderStatus;
|
|
1114
|
+
note?: string;
|
|
1115
|
+
changedBy?: string;
|
|
1116
|
+
createdAt: number;
|
|
1117
|
+
}
|
|
1118
|
+
interface OrderDetail extends OrderListItem {
|
|
1119
|
+
items: OrderItem[];
|
|
1120
|
+
shippingAddress: CheckoutAddress;
|
|
1121
|
+
billingAddress: CheckoutAddress;
|
|
1122
|
+
email: string;
|
|
1123
|
+
phone?: string;
|
|
1124
|
+
customerNote?: string;
|
|
1125
|
+
subtotal: number;
|
|
1126
|
+
taxTotal: number;
|
|
1127
|
+
/** VAT split by rate (GAP-30), summed from the order lines. Render
|
|
1128
|
+
* "DPH 21 %: X Kč" rows. Empty for a non-VAT order. */
|
|
1129
|
+
taxBreakdown: TaxBreakdownLine[];
|
|
1130
|
+
shippingTotal: number;
|
|
1131
|
+
discountTotal: number;
|
|
1132
|
+
fulfillmentStatus: FulfillmentStatus;
|
|
1133
|
+
statusHistory: OrderStatusHistory[];
|
|
1134
|
+
trackingToken?: string;
|
|
1135
|
+
/**
|
|
1136
|
+
* Digital product delivery (GAP-07): download grants for any digital assets
|
|
1137
|
+
* on this order. Populated only for PAID orders; empty otherwise. Mint a
|
|
1138
|
+
* short-lived signed URL with `customer.getDownloadUrl(id)` (logged in) or the
|
|
1139
|
+
* guest order-access URL flow.
|
|
1140
|
+
*/
|
|
1141
|
+
downloads: DigitalDownload[];
|
|
1142
|
+
/**
|
|
1143
|
+
* For redirect payment gateways (GoPay, ...), the hosted URL the
|
|
1144
|
+
* storefront must send the customer to in order to pay. Present only on
|
|
1145
|
+
* the order returned by `checkout.createOrder()`. Null/absent for
|
|
1146
|
+
* offline methods (bank transfer, COD) and zero-total orders.
|
|
1147
|
+
*/
|
|
1148
|
+
paymentRedirectUrl?: string | null;
|
|
1149
|
+
}
|
|
1150
|
+
/** Generic response to `orders.requestAccessCode` — never reveals existence. */
|
|
1151
|
+
interface OrderAccessRequestResponse {
|
|
1152
|
+
success: boolean;
|
|
1153
|
+
message: string;
|
|
1154
|
+
}
|
|
1155
|
+
/** Response to a successful `orders.verifyAccessCode`. */
|
|
1156
|
+
interface OrderAccessVerifyResponse {
|
|
1157
|
+
/** Short-lived JWT scoped to this single order (use with `getByAccessToken`). */
|
|
1158
|
+
accessToken: string;
|
|
1159
|
+
/** Token lifetime in seconds. */
|
|
1160
|
+
expiresIn: number;
|
|
1161
|
+
order: OrderDetail;
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* A download grant: the right to fetch one digital asset (PDF, MP3, ...) that
|
|
1165
|
+
* a customer purchased. Enforced budget: `downloadCount` of `maxDownloads`
|
|
1166
|
+
* (null = unlimited), optional `expiresAt`.
|
|
1167
|
+
*/
|
|
1168
|
+
interface DigitalDownload {
|
|
1169
|
+
id: string;
|
|
1170
|
+
/** Order this grant originates from (null for legacy/manual grants). */
|
|
1171
|
+
orderId: string | null;
|
|
1172
|
+
fileName: string;
|
|
1173
|
+
/** Localized product name the file belongs to (may be null). */
|
|
1174
|
+
productName: string | null;
|
|
1175
|
+
/** Product slug for linking back to the PDP (may be null). */
|
|
1176
|
+
productSlug: string | null;
|
|
1177
|
+
fileSize: number;
|
|
1178
|
+
mimeType: string;
|
|
1179
|
+
version: string | null;
|
|
1180
|
+
downloadCount: number;
|
|
1181
|
+
/** Max downloads allowed (null = unlimited). */
|
|
1182
|
+
maxDownloads: number | null;
|
|
1183
|
+
/** Remaining downloads (null = unlimited). */
|
|
1184
|
+
remainingDownloads: number | null;
|
|
1185
|
+
lastDownloadAt: number | null;
|
|
1186
|
+
/** Access expiry (epoch ms, null = never expires). */
|
|
1187
|
+
expiresAt: number | null;
|
|
1188
|
+
isExpired: boolean;
|
|
1189
|
+
isMaxedOut: boolean;
|
|
1190
|
+
createdAt: number;
|
|
1191
|
+
}
|
|
1192
|
+
/** One enrolled course on the customer's "My courses" list. */
|
|
1193
|
+
interface CourseListItem {
|
|
1194
|
+
courseId: string;
|
|
1195
|
+
/** Localized course (product) name, best-effort. */
|
|
1196
|
+
name: string | null;
|
|
1197
|
+
/** Product slug for linking to the PDP. */
|
|
1198
|
+
slug: string;
|
|
1199
|
+
imageUrl: string | null;
|
|
1200
|
+
totalLessons: number;
|
|
1201
|
+
completedLessons: number;
|
|
1202
|
+
enrolledAt: number;
|
|
1203
|
+
/** Access expiry (epoch ms, null = never expires). */
|
|
1204
|
+
expiresAt: number | null;
|
|
1205
|
+
isExpired: boolean;
|
|
1206
|
+
/**
|
|
1207
|
+
* Course content opens at this time (epoch ms); null/undefined = already
|
|
1208
|
+
* open. While in the future, render "Startujeme ..." + countdown.
|
|
1209
|
+
*/
|
|
1210
|
+
contentAvailableFrom?: number | null;
|
|
1211
|
+
}
|
|
1212
|
+
/** Downloadable attachment on a course lesson. */
|
|
1213
|
+
interface CourseAttachment {
|
|
1214
|
+
name: string;
|
|
1215
|
+
url: string;
|
|
1216
|
+
fileSize?: number;
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* One lesson in the course player. Locked lessons (drip unlocking) expose
|
|
1220
|
+
* only the title and `unlockAt` — `videoUrl`/`content`/`attachments` are
|
|
1221
|
+
* null/empty until the lesson unlocks server-side.
|
|
1222
|
+
*/
|
|
1223
|
+
interface CourseLesson {
|
|
1224
|
+
id: string;
|
|
1225
|
+
title: string;
|
|
1226
|
+
isPreview: boolean;
|
|
1227
|
+
isUnlocked: boolean;
|
|
1228
|
+
/** When a locked lesson unlocks (epoch ms). Null once unlocked. */
|
|
1229
|
+
unlockAt: number | null;
|
|
1230
|
+
isCompleted: boolean;
|
|
1231
|
+
videoUrl: string | null;
|
|
1232
|
+
content: string | null;
|
|
1233
|
+
attachments: CourseAttachment[];
|
|
1234
|
+
/**
|
|
1235
|
+
* Number of quiz questions on this lesson (0 = no quiz). Load the quiz via
|
|
1236
|
+
* `customer.getLessonQuiz()` once the lesson is unlocked.
|
|
1237
|
+
*/
|
|
1238
|
+
quizQuestionCount: number;
|
|
1239
|
+
}
|
|
1240
|
+
interface CourseModule {
|
|
1241
|
+
id: string;
|
|
1242
|
+
title: string;
|
|
1243
|
+
lessons: CourseLesson[];
|
|
1244
|
+
}
|
|
1245
|
+
/** Full course player payload for an enrolled customer. */
|
|
1246
|
+
interface CourseDetail {
|
|
1247
|
+
courseId: string;
|
|
1248
|
+
name: string | null;
|
|
1249
|
+
slug: string;
|
|
1250
|
+
imageUrl: string | null;
|
|
1251
|
+
/** Welcome text shown at the top of the member area (markdown). */
|
|
1252
|
+
welcomeText: string | null;
|
|
1253
|
+
/**
|
|
1254
|
+
* AI tutor ("Ask about this lesson") is available on unlocked lessons —
|
|
1255
|
+
* render the tutor widget only when true.
|
|
1256
|
+
*/
|
|
1257
|
+
aiTutorEnabled: boolean;
|
|
1258
|
+
/**
|
|
1259
|
+
* Lesson discussion (comments) is available on unlocked lessons — render
|
|
1260
|
+
* the discussion widget only when true.
|
|
1261
|
+
*/
|
|
1262
|
+
discussionEnabled: boolean;
|
|
1263
|
+
/**
|
|
1264
|
+
* Course content opens at this time (epoch ms); null/undefined = already
|
|
1265
|
+
* open. While in the future EVERY lesson (including previews) is locked
|
|
1266
|
+
* with `unlockAt >= contentAvailableFrom` — render "Startujeme ..." +
|
|
1267
|
+
* countdown in the member area.
|
|
1268
|
+
*/
|
|
1269
|
+
contentAvailableFrom?: number | null;
|
|
1270
|
+
enrolledAt: number;
|
|
1271
|
+
expiresAt: number | null;
|
|
1272
|
+
totalLessons: number;
|
|
1273
|
+
completedLessons: number;
|
|
1274
|
+
modules: CourseModule[];
|
|
1275
|
+
/**
|
|
1276
|
+
* Completion certificate, present once the course is 100 % finished and the
|
|
1277
|
+
* merchant has certificates enabled. Verify the code publicly via
|
|
1278
|
+
* `certificates.verify(code)`.
|
|
1279
|
+
*/
|
|
1280
|
+
certificate?: {
|
|
1281
|
+
code: string;
|
|
1282
|
+
issuedAt: number;
|
|
1283
|
+
} | null;
|
|
1284
|
+
}
|
|
1285
|
+
/** Progress snapshot returned after completing a lesson. */
|
|
1286
|
+
interface CourseProgress {
|
|
1287
|
+
courseId: string;
|
|
1288
|
+
lessonId: string;
|
|
1289
|
+
totalLessons: number;
|
|
1290
|
+
completedLessons: number;
|
|
1291
|
+
}
|
|
1292
|
+
/** One quiz question. Correct answers are never exposed before submitting. */
|
|
1293
|
+
interface QuizQuestion {
|
|
1294
|
+
id: string;
|
|
1295
|
+
question: string;
|
|
1296
|
+
/** Option texts in order; submit the chosen option's index. */
|
|
1297
|
+
options: string[];
|
|
1298
|
+
}
|
|
1299
|
+
interface LessonQuiz {
|
|
1300
|
+
courseId: string;
|
|
1301
|
+
lessonId: string;
|
|
1302
|
+
/** Minimum score (in %) that completes the lesson automatically. */
|
|
1303
|
+
passPercent: number;
|
|
1304
|
+
questions: QuizQuestion[];
|
|
1305
|
+
}
|
|
1306
|
+
interface QuizAnswerInput {
|
|
1307
|
+
questionId: string;
|
|
1308
|
+
/** Index of the chosen option (0-based). */
|
|
1309
|
+
selectedIndex: number;
|
|
1310
|
+
}
|
|
1311
|
+
interface QuizAnswerResult {
|
|
1312
|
+
questionId: string;
|
|
1313
|
+
/** Echo of the submitted choice; null when unanswered or out of range. */
|
|
1314
|
+
selectedIndex: number | null;
|
|
1315
|
+
/** Correct option index, revealed only after submitting. */
|
|
1316
|
+
correctIndex: number;
|
|
1317
|
+
correct: boolean;
|
|
1318
|
+
}
|
|
1319
|
+
interface QuizResult {
|
|
1320
|
+
courseId: string;
|
|
1321
|
+
lessonId: string;
|
|
1322
|
+
totalQuestions: number;
|
|
1323
|
+
correctCount: number;
|
|
1324
|
+
scorePercent: number;
|
|
1325
|
+
passPercent: number;
|
|
1326
|
+
passed: boolean;
|
|
1327
|
+
/** True when the passing score marked the lesson completed. */
|
|
1328
|
+
lessonCompleted: boolean;
|
|
1329
|
+
results: QuizAnswerResult[];
|
|
1330
|
+
/** Course progress after a passing submit; null when not passed. */
|
|
1331
|
+
progress: {
|
|
1332
|
+
totalLessons: number;
|
|
1333
|
+
completedLessons: number;
|
|
1334
|
+
} | null;
|
|
1335
|
+
}
|
|
1336
|
+
/** One exchange in the private AI tutor thread: question + answer. */
|
|
1337
|
+
interface CourseTutorMessage {
|
|
1338
|
+
id: string;
|
|
1339
|
+
/** The student's question. */
|
|
1340
|
+
question: string;
|
|
1341
|
+
/** The AI tutor's answer (plain text / light markdown). */
|
|
1342
|
+
answer: string;
|
|
1343
|
+
createdAt: number;
|
|
1344
|
+
}
|
|
1345
|
+
/** The student's private tutor thread for one lesson. */
|
|
1346
|
+
interface CourseTutorThread {
|
|
1347
|
+
courseId: string;
|
|
1348
|
+
lessonId: string;
|
|
1349
|
+
/** False when the merchant disabled the AI tutor — hide the widget. */
|
|
1350
|
+
enabled: boolean;
|
|
1351
|
+
/** Oldest first. */
|
|
1352
|
+
items: CourseTutorMessage[];
|
|
1353
|
+
}
|
|
1354
|
+
/** A one-level reply under a top-level lesson comment. */
|
|
1355
|
+
interface CourseCommentReply {
|
|
1356
|
+
id: string;
|
|
1357
|
+
/** Id of the parent (top-level) comment. */
|
|
1358
|
+
parentId: string;
|
|
1359
|
+
body: string;
|
|
1360
|
+
/** Author's first name, or a masked e-mail when no name is known. */
|
|
1361
|
+
authorName: string;
|
|
1362
|
+
/** True when the logged-in customer wrote this reply (can delete it). */
|
|
1363
|
+
isMine: boolean;
|
|
1364
|
+
createdAt: number;
|
|
1365
|
+
}
|
|
1366
|
+
/** A top-level comment under a lesson, with one level of replies. */
|
|
1367
|
+
interface CourseComment {
|
|
1368
|
+
id: string;
|
|
1369
|
+
body: string;
|
|
1370
|
+
/** Author's first name, or a masked e-mail when no name is known. */
|
|
1371
|
+
authorName: string;
|
|
1372
|
+
/** True when the logged-in customer wrote this comment (can delete it). */
|
|
1373
|
+
isMine: boolean;
|
|
1374
|
+
createdAt: number;
|
|
1375
|
+
/** Oldest first. */
|
|
1376
|
+
replies: CourseCommentReply[];
|
|
1377
|
+
}
|
|
1378
|
+
/** Paginated lesson discussion (top-level comments, newest first). */
|
|
1379
|
+
interface CourseCommentsList {
|
|
1380
|
+
courseId: string;
|
|
1381
|
+
lessonId: string;
|
|
1382
|
+
/** False when the merchant disabled the discussion — hide the widget. */
|
|
1383
|
+
enabled: boolean;
|
|
1384
|
+
/** 1-based page of top-level comments. */
|
|
1385
|
+
page: number;
|
|
1386
|
+
pageSize: number;
|
|
1387
|
+
/** Total count of top-level comments on the lesson. */
|
|
1388
|
+
totalCount: number;
|
|
1389
|
+
items: CourseComment[];
|
|
1390
|
+
}
|
|
1391
|
+
/** The comment (or reply) just posted by the logged-in customer. */
|
|
1392
|
+
interface CoursePostedComment {
|
|
1393
|
+
id: string;
|
|
1394
|
+
/** Id of the parent comment when this is a reply; null for top-level. */
|
|
1395
|
+
parentId?: string | null;
|
|
1396
|
+
body: string;
|
|
1397
|
+
authorName: string;
|
|
1398
|
+
isMine: boolean;
|
|
1399
|
+
createdAt: number;
|
|
1400
|
+
}
|
|
1401
|
+
/** The student's private note for one lesson (visible only to them). */
|
|
1402
|
+
interface LessonNote {
|
|
1403
|
+
courseId: string;
|
|
1404
|
+
lessonId: string;
|
|
1405
|
+
/** The note text; empty string when no note exists yet. */
|
|
1406
|
+
body: string;
|
|
1407
|
+
/** Last save time (epoch ms); null when no note exists yet. */
|
|
1408
|
+
updatedAt: number | null;
|
|
1409
|
+
}
|
|
1410
|
+
/** One completion certificate on the customer's account. */
|
|
1411
|
+
interface CourseCertificate {
|
|
1412
|
+
courseId: string;
|
|
1413
|
+
courseName: string | null;
|
|
1414
|
+
/** Public verification code (share it, verify via `certificates.verify`). */
|
|
1415
|
+
code: string;
|
|
1416
|
+
issuedAt: number;
|
|
1417
|
+
}
|
|
1418
|
+
/** Public verification payload for a certificate code. */
|
|
1419
|
+
interface CertificateVerification {
|
|
1420
|
+
valid: boolean;
|
|
1421
|
+
code: string;
|
|
1422
|
+
courseId: string;
|
|
1423
|
+
courseName: string | null;
|
|
1424
|
+
/** Student's name, or a masked e-mail when no name is known. */
|
|
1425
|
+
studentName: string;
|
|
1426
|
+
issuedAt: number;
|
|
1427
|
+
}
|
|
1428
|
+
/** Short-lived signed URL to fetch a purchased digital file. */
|
|
1429
|
+
interface DownloadUrl {
|
|
1430
|
+
/** Short-lived (15 min) signed URL. */
|
|
1431
|
+
url: string;
|
|
1432
|
+
fileName: string;
|
|
1433
|
+
mimeType: string;
|
|
1434
|
+
fileSize: number;
|
|
1435
|
+
/** Remaining downloads after this one is counted (null = unlimited). */
|
|
1436
|
+
remainingDownloads: number | null;
|
|
1437
|
+
expiresAt: number | null;
|
|
1438
|
+
}
|
|
1439
|
+
interface CustomerProfile {
|
|
1440
|
+
id: string;
|
|
1441
|
+
email: string;
|
|
1442
|
+
firstName?: string;
|
|
1443
|
+
lastName?: string;
|
|
1444
|
+
phone?: string;
|
|
1445
|
+
emailVerified: boolean;
|
|
1446
|
+
/**
|
|
1447
|
+
* B2B approval gate (GAP-19). `false` = the account is awaiting merchant
|
|
1448
|
+
* approval (or was deactivated) — show a "pending approval" banner and gate
|
|
1449
|
+
* ordering. `true` = approved / active. New registrations on a shop with
|
|
1450
|
+
* `requireRegistrationApproval` start unapproved and cannot log in until
|
|
1451
|
+
* approved (register returns `pendingApproval`).
|
|
1452
|
+
*/
|
|
1453
|
+
isApproved: boolean;
|
|
1454
|
+
}
|
|
1455
|
+
interface CustomerAddress {
|
|
1456
|
+
id: string;
|
|
1457
|
+
type: AddressType;
|
|
1458
|
+
isDefault: boolean;
|
|
1459
|
+
firstName: string;
|
|
1460
|
+
lastName: string;
|
|
1461
|
+
company?: string;
|
|
1462
|
+
street: string;
|
|
1463
|
+
city: string;
|
|
1464
|
+
zip: string;
|
|
1465
|
+
country: string;
|
|
1466
|
+
phone?: string;
|
|
1467
|
+
}
|
|
1468
|
+
interface Page {
|
|
1469
|
+
slug: string;
|
|
1470
|
+
title: string;
|
|
1471
|
+
isActive: boolean;
|
|
1472
|
+
/** Last modification of the page record (epoch ms) — sitemap `lastmod` (GAP-31). */
|
|
1473
|
+
updatedAt?: number;
|
|
1474
|
+
}
|
|
1475
|
+
interface PageDetail {
|
|
1476
|
+
slug: string;
|
|
1477
|
+
title: string;
|
|
1478
|
+
content: unknown;
|
|
1479
|
+
seoTitle?: string;
|
|
1480
|
+
seoDescription?: string;
|
|
1481
|
+
ogTitle?: string;
|
|
1482
|
+
ogDescription?: string;
|
|
1483
|
+
ogImage?: string;
|
|
1484
|
+
/** Downloadable files attached to the page (e.g. legal form PDFs). */
|
|
1485
|
+
attachments: PageAttachment[];
|
|
1486
|
+
}
|
|
1487
|
+
interface PageAttachment {
|
|
1488
|
+
name: string;
|
|
1489
|
+
description: string | null;
|
|
1490
|
+
url: string;
|
|
1491
|
+
mimeType: string;
|
|
1492
|
+
fileSize: number;
|
|
1493
|
+
}
|
|
1494
|
+
type BehioErrorCode = "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "VALIDATION_ERROR" | "CONFLICT" | "RATE_LIMITED" | "CART_EMPTY" | "PRODUCT_NOT_FOUND" | "INVALID_CREDENTIALS" | "INVALID_DISCOUNT" | "DISCOUNT_EXPIRED" | "TOKEN_EXPIRED" | "TOKEN_INVALID" | "EMAIL_ALREADY_EXISTS" | "ORDER_NOT_CANCELLABLE" | "INTERNAL_ERROR" | "NETWORK_ERROR" | "TIMEOUT" | "UNKNOWN";
|
|
1495
|
+
declare class BehioApiError extends Error {
|
|
1496
|
+
readonly code: BehioErrorCode;
|
|
1497
|
+
readonly status: number;
|
|
1498
|
+
readonly body: unknown;
|
|
1499
|
+
readonly isRetryable: boolean;
|
|
1500
|
+
constructor(status: number, body: unknown, message?: string);
|
|
1501
|
+
static resolveCode(status: number, body: unknown): BehioErrorCode;
|
|
1502
|
+
/** Check if this is a specific error type */
|
|
1503
|
+
is(code: BehioErrorCode): boolean;
|
|
1504
|
+
}
|
|
1505
|
+
/**
|
|
1506
|
+
* Shape every SDK call returns. Destructure `{data, error}` — exactly
|
|
1507
|
+
* one of them is non-null on any given call. No more try/catch for
|
|
1508
|
+
* expected failures; the type system forces you to handle `error`
|
|
1509
|
+
* before touching `data`.
|
|
1510
|
+
*
|
|
1511
|
+
* const {data, error} = await behio.catalog.getProduct(slug);
|
|
1512
|
+
* if (error) return <ErrorState code={error.code} />;
|
|
1513
|
+
* return <ProductView product={data} />;
|
|
1514
|
+
*/
|
|
1515
|
+
type SdkResult<T> = {
|
|
1516
|
+
data: T;
|
|
1517
|
+
error: null;
|
|
1518
|
+
} | {
|
|
1519
|
+
data: null;
|
|
1520
|
+
error: SdkError;
|
|
1521
|
+
};
|
|
1522
|
+
/**
|
|
1523
|
+
* Canonical error shape returned from every SDK call. Always carries a
|
|
1524
|
+
* `code` you can branch on without parsing messages.
|
|
1525
|
+
*/
|
|
1526
|
+
interface SdkError {
|
|
1527
|
+
/**
|
|
1528
|
+
* High-level category. `BehioErrorCode` covers API errors; additional
|
|
1529
|
+
* buckets are network/timeout/abort/unknown.
|
|
1530
|
+
*/
|
|
1531
|
+
code: BehioErrorCode;
|
|
1532
|
+
/** Human-readable message (fallback for unknown codes / dev logging). */
|
|
1533
|
+
message: string;
|
|
1534
|
+
/** HTTP status, if the error came from the API. Null for network / abort. */
|
|
1535
|
+
status: number | null;
|
|
1536
|
+
/** Raw API body, if present. */
|
|
1537
|
+
body?: unknown;
|
|
1538
|
+
/** Whether the operation is safe to retry (true for 5xx / 429 / network). */
|
|
1539
|
+
isRetryable: boolean;
|
|
1540
|
+
/** Preserves the original thrown instance for stack traces + rethrows. */
|
|
1541
|
+
cause?: unknown;
|
|
1542
|
+
}
|
|
1543
|
+
type BehioEventType = "auth:login" | "auth:logout" | "auth:token-refresh" | "auth:token-refresh-failed" | "cart:updated" | "cart:cleared" | "order:created" | "error" | "request" | "response" | "rate-limit-warning";
|
|
1544
|
+
type BehioEventHandler = (data?: unknown) => void;
|
|
1545
|
+
interface RequestInterceptorConfig {
|
|
1546
|
+
url: string;
|
|
1547
|
+
method: string;
|
|
1548
|
+
headers: Record<string, string>;
|
|
1549
|
+
body?: string;
|
|
1550
|
+
}
|
|
1551
|
+
interface RequestInterceptor {
|
|
1552
|
+
(config: RequestInterceptorConfig): RequestInterceptorConfig | Promise<RequestInterceptorConfig>;
|
|
1553
|
+
}
|
|
1554
|
+
interface ResponseInterceptorData {
|
|
1555
|
+
status: number;
|
|
1556
|
+
data: unknown;
|
|
1557
|
+
headers: Headers;
|
|
1558
|
+
}
|
|
1559
|
+
interface ResponseInterceptor {
|
|
1560
|
+
(response: ResponseInterceptorData): void | Promise<void>;
|
|
1561
|
+
}
|
|
1562
|
+
/** One product group ("collection") with its products as standard list items.
|
|
1563
|
+
* Groups are curated in the admin (Product groups); storefronts render them
|
|
1564
|
+
* as product bands, e.g. a home "collection" section. */
|
|
1565
|
+
interface ProductGroup {
|
|
1566
|
+
id: string;
|
|
1567
|
+
slug: string;
|
|
1568
|
+
/** Group type, e.g. "similar" / "upsell" / "recommended" / "collection". */
|
|
1569
|
+
type: string;
|
|
1570
|
+
/** Name in the requested locale, falling back to the shop default language. */
|
|
1571
|
+
name: string;
|
|
1572
|
+
description: string | null;
|
|
1573
|
+
items: ProductListItem[];
|
|
1574
|
+
}
|
|
1575
|
+
interface BundleItem {
|
|
1576
|
+
productId: string;
|
|
1577
|
+
slug: string | null;
|
|
1578
|
+
name: string;
|
|
1579
|
+
sku: string;
|
|
1580
|
+
quantity: number;
|
|
1581
|
+
imageUrl: string | null;
|
|
1582
|
+
defaultPrice: number | null;
|
|
1583
|
+
}
|
|
1584
|
+
interface Bundle {
|
|
1585
|
+
id: string;
|
|
1586
|
+
slug: string;
|
|
1587
|
+
name: string;
|
|
1588
|
+
description: string | null;
|
|
1589
|
+
bundlePrice: number;
|
|
1590
|
+
currency: string;
|
|
1591
|
+
coverImage: string | null;
|
|
1592
|
+
endsAt: number | null;
|
|
1593
|
+
itemsSum: number;
|
|
1594
|
+
/** Absolute saving vs buying the components separately, in `currency`. */
|
|
1595
|
+
savings: number;
|
|
1596
|
+
/** Percentage saving, 0–100. 0 when `itemsSum` is zero. */
|
|
1597
|
+
savingsPercent: number;
|
|
1598
|
+
/** Minimum bundles per order. Default 1. */
|
|
1599
|
+
minQuantity: number;
|
|
1600
|
+
/** Maximum bundles per order. `null` = uncapped. */
|
|
1601
|
+
maxQuantity: number | null;
|
|
1602
|
+
/** Lifetime stock limit. `null` = uncapped. Once exceeded, add-to-cart fails. */
|
|
1603
|
+
stockLimit: number | null;
|
|
1604
|
+
/** Lifetime units sold (materialized counter). Used for "X sold" badges. */
|
|
1605
|
+
soldCount: number;
|
|
1606
|
+
items: BundleItem[];
|
|
1607
|
+
}
|
|
1608
|
+
/**
|
|
1609
|
+
* Shape returned by `behio.shipping.listMethods()` — the merchant's
|
|
1610
|
+
* configured shipping methods filtered by cart currency + destination
|
|
1611
|
+
* country. Use this for the "always-on" picker; for live quotes, prefer
|
|
1612
|
+
* `behio.shipping.quote()` which can dispatch to the meta-provider
|
|
1613
|
+
* (Zaslat, Shippo, …) for a live carrier rate per address.
|
|
1614
|
+
*/
|
|
1615
|
+
interface ShippingMethodSummary {
|
|
1616
|
+
id: string;
|
|
1617
|
+
name: string;
|
|
1618
|
+
description: string | null;
|
|
1619
|
+
/** Internal routing id ("zaslat", "ppl_direct", "manual", …). Not for display. */
|
|
1620
|
+
provider: string;
|
|
1621
|
+
/** "fixed" = price known upfront; "live_quote" = must call shipping.quote() with address. */
|
|
1622
|
+
priceStrategy: "fixed" | "live_quote";
|
|
1623
|
+
currency: string | null;
|
|
1624
|
+
/** Final customer-facing price. Null for live_quote methods (call quote() to resolve). */
|
|
1625
|
+
price: number | null;
|
|
1626
|
+
/** Per-currency base price from the merchant's config. Null for live_quote. */
|
|
1627
|
+
basePrice: number | null;
|
|
1628
|
+
isFreeShipping: boolean;
|
|
1629
|
+
freeShippingThreshold: number | null;
|
|
1630
|
+
/** "address" | "pickup_point" | "in_store" | "digital". */
|
|
1631
|
+
deliveryType: string;
|
|
1632
|
+
supportsPickupPoints: boolean;
|
|
1633
|
+
etaDaysMin: number | null;
|
|
1634
|
+
etaDaysMax: number | null;
|
|
1635
|
+
allowedCountries: string[];
|
|
1636
|
+
/** Customer-safe config fields the merchant filled in (pickup address, instructions). */
|
|
1637
|
+
publicConfig: Record<string, unknown>;
|
|
1638
|
+
}
|
|
1639
|
+
/**
|
|
1640
|
+
* Input for `behio.shipping.quote()`. At minimum requires the destination
|
|
1641
|
+
* country — passing more (zip, weight per item, cart total) lets the
|
|
1642
|
+
* meta-provider return better-fitting carriers and triggers free-shipping
|
|
1643
|
+
* thresholds correctly.
|
|
1644
|
+
*/
|
|
1645
|
+
interface ShippingQuoteInput {
|
|
1646
|
+
destinationAddress: {
|
|
1647
|
+
country: string;
|
|
1648
|
+
zip?: string;
|
|
1649
|
+
city?: string;
|
|
1650
|
+
street?: string;
|
|
1651
|
+
};
|
|
1652
|
+
items?: Array<{
|
|
1653
|
+
whItemId: string;
|
|
1654
|
+
quantity: number;
|
|
1655
|
+
weightKg?: number;
|
|
1656
|
+
}>;
|
|
1657
|
+
cartTotal?: number;
|
|
1658
|
+
currency?: string;
|
|
1659
|
+
}
|
|
1660
|
+
/**
|
|
1661
|
+
* One option returned by `behio.shipping.quote()`. Methods configured for
|
|
1662
|
+
* fixed pricing always come back with `available: true` and the merchant's
|
|
1663
|
+
* configured price. Methods configured for live quoting come back available
|
|
1664
|
+
* only when the upstream meta-provider returned a rate for the destination
|
|
1665
|
+
* — otherwise `available: false` with a `reason` (e.g. `"no_rate_returned"`,
|
|
1666
|
+
* `"live_quote_not_implemented"`). Filter `available: true` in your
|
|
1667
|
+
* checkout picker.
|
|
1668
|
+
*/
|
|
1669
|
+
interface ShippingQuote extends ShippingMethodSummary {
|
|
1670
|
+
/** `"fixed"` uses `pricing` rows; `"live_quote"` came from the upstream provider. */
|
|
1671
|
+
strategy: "fixed" | "live_quote";
|
|
1672
|
+
available: boolean;
|
|
1673
|
+
reason: string | null;
|
|
1674
|
+
/** Server-generated quote ID. Null for fixed-price methods. Pass to checkout for tamper-proof pricing. */
|
|
1675
|
+
quoteId: string | null;
|
|
1676
|
+
/** Quote expiry (epoch ms). Null for fixed-price methods. */
|
|
1677
|
+
expiresAt: number | null;
|
|
1678
|
+
}
|
|
1679
|
+
/**
|
|
1680
|
+
* A pickup point (parcel shop / locker) for a shipping method with
|
|
1681
|
+
* `supportsPickupPoints`. Fetch with `behio.shipping.getPickupPoints()`,
|
|
1682
|
+
* then send the chosen `externalId` as `checkout.pickupPointId`.
|
|
1683
|
+
*/
|
|
1684
|
+
interface PickupPoint {
|
|
1685
|
+
/** Carrier-native id. Send this back as `checkout.pickupPointId`. */
|
|
1686
|
+
externalId: string;
|
|
1687
|
+
name: string;
|
|
1688
|
+
street: string | null;
|
|
1689
|
+
city: string;
|
|
1690
|
+
zip: string;
|
|
1691
|
+
country: string;
|
|
1692
|
+
latitude: number | null;
|
|
1693
|
+
longitude: number | null;
|
|
1694
|
+
cashOnDelivery: boolean;
|
|
1695
|
+
cardPayment: boolean;
|
|
1696
|
+
/** Per-day opening hours; empty when the provider gives none. */
|
|
1697
|
+
openingHours: PickupPointHours[];
|
|
1698
|
+
}
|
|
1699
|
+
/** One day's opening-hours block for a pickup point. */
|
|
1700
|
+
interface PickupPointHours {
|
|
1701
|
+
/** Provider-native day key (e.g. weekday name or index). */
|
|
1702
|
+
day: string;
|
|
1703
|
+
/** Morning open time. */
|
|
1704
|
+
from1: string | null;
|
|
1705
|
+
/** Morning close time. */
|
|
1706
|
+
to1: string | null;
|
|
1707
|
+
/** Afternoon open time. */
|
|
1708
|
+
from2: string | null;
|
|
1709
|
+
/** Afternoon close time. */
|
|
1710
|
+
to2: string | null;
|
|
1711
|
+
}
|
|
1712
|
+
/** Input for `behio.shipping.getPickupPoints()`. */
|
|
1713
|
+
interface PickupPointsInput {
|
|
1714
|
+
/** Shipping method id (must have `supportsPickupPoints`). */
|
|
1715
|
+
methodId: string;
|
|
1716
|
+
/** Free-text search over name / city / zip. */
|
|
1717
|
+
query?: string;
|
|
1718
|
+
/** ISO 3166-1 alpha-2 country filter; defaults to the method's first
|
|
1719
|
+
* allowed country or CZ. */
|
|
1720
|
+
country?: string;
|
|
1721
|
+
/** Max results (default 30, capped at 100). */
|
|
1722
|
+
limit?: number;
|
|
1723
|
+
}
|
|
1724
|
+
/** Public terms of the eshop's loyalty program. */
|
|
1725
|
+
interface LoyaltyProgram {
|
|
1726
|
+
name: string;
|
|
1727
|
+
pointName: string;
|
|
1728
|
+
pointNamePlural: string;
|
|
1729
|
+
/** 1 point = `pointValueRatio` currency units. */
|
|
1730
|
+
pointValueRatio: number;
|
|
1731
|
+
currency: string;
|
|
1732
|
+
minRedemptionPoints: number;
|
|
1733
|
+
maxRedemptionPercent: number;
|
|
1734
|
+
combineWithDiscounts: boolean;
|
|
1735
|
+
description: string | null;
|
|
1736
|
+
iconUrl: string | null;
|
|
1737
|
+
}
|
|
1738
|
+
interface LoyaltyBalance {
|
|
1739
|
+
currentPoints: number;
|
|
1740
|
+
/** `currentPoints` valued in the program currency. */
|
|
1741
|
+
currentPointsValue: number;
|
|
1742
|
+
lifetimePointsEarned: number;
|
|
1743
|
+
lifetimePointsRedeemed: number;
|
|
1744
|
+
lifetimeSpend: number;
|
|
1745
|
+
}
|
|
1746
|
+
interface LoyaltyTier {
|
|
1747
|
+
name: string;
|
|
1748
|
+
slug: string;
|
|
1749
|
+
color: string | null;
|
|
1750
|
+
earnMultiplier: number;
|
|
1751
|
+
/** Tier perks (human-readable perk lines), or null when the tier has none. */
|
|
1752
|
+
perks: LoyaltyTierPerks | null;
|
|
1753
|
+
}
|
|
1754
|
+
/** Perks attached to a loyalty tier. */
|
|
1755
|
+
interface LoyaltyTierPerks {
|
|
1756
|
+
/** Human-readable perk lines shown on the tier. */
|
|
1757
|
+
list: string[];
|
|
1758
|
+
}
|
|
1759
|
+
interface LoyaltyNextTier {
|
|
1760
|
+
name: string;
|
|
1761
|
+
slug: string;
|
|
1762
|
+
color: string | null;
|
|
1763
|
+
thresholdType: string;
|
|
1764
|
+
thresholdValue: number;
|
|
1765
|
+
currentValue: number;
|
|
1766
|
+
remaining: number;
|
|
1767
|
+
/** 0-100 progress toward this tier. */
|
|
1768
|
+
progressPercent: number;
|
|
1769
|
+
}
|
|
1770
|
+
interface LoyaltyTransaction {
|
|
1771
|
+
type: string;
|
|
1772
|
+
/** Positive = earned, negative = redeemed / expired. */
|
|
1773
|
+
points: number;
|
|
1774
|
+
balanceAfter: number;
|
|
1775
|
+
eventType: string | null;
|
|
1776
|
+
description: string | null;
|
|
1777
|
+
createdAt: number;
|
|
1778
|
+
}
|
|
1779
|
+
/**
|
|
1780
|
+
* Loyalty summary for the logged-in customer. `hasProgram` is false when the
|
|
1781
|
+
* eshop runs no program; `enrolled` is false when the customer has not yet
|
|
1782
|
+
* joined (then `program` still carries the public terms so you can render a
|
|
1783
|
+
* "join and earn" CTA).
|
|
1784
|
+
*/
|
|
1785
|
+
interface LoyaltySummary {
|
|
1786
|
+
hasProgram: boolean;
|
|
1787
|
+
enrolled: boolean;
|
|
1788
|
+
program: LoyaltyProgram | null;
|
|
1789
|
+
balance: LoyaltyBalance | null;
|
|
1790
|
+
currentTier: LoyaltyTier | null;
|
|
1791
|
+
nextTier: LoyaltyNextTier | null;
|
|
1792
|
+
referralCode: string | null;
|
|
1793
|
+
transactions: LoyaltyTransaction[];
|
|
1794
|
+
}
|
|
1795
|
+
interface CrossSellItem {
|
|
1796
|
+
productId: string;
|
|
1797
|
+
slug: string | null;
|
|
1798
|
+
/** Localized product name (resolved for the requested locale, falls back to
|
|
1799
|
+
* the eshop default language). */
|
|
1800
|
+
name: string;
|
|
1801
|
+
sku: string;
|
|
1802
|
+
/** Price in the requested currency (or eshop default), including any price
|
|
1803
|
+
* list override for the authenticated customer. `null` when hidden (B2B). */
|
|
1804
|
+
price: number | null;
|
|
1805
|
+
/** Original (crossed-out) price in the same currency, when on sale. */
|
|
1806
|
+
compareAtPrice: number | null;
|
|
1807
|
+
/** Currency code the `price` / `compareAtPrice` are expressed in. */
|
|
1808
|
+
currency: string;
|
|
1809
|
+
imageUrl: string | null;
|
|
1810
|
+
/** Cached stock quantity of the recommended product. */
|
|
1811
|
+
stockCached: number;
|
|
1812
|
+
/** Convenience flag: `stockCached > 0`. */
|
|
1813
|
+
inStock: boolean;
|
|
1814
|
+
/** Merchant-editable note ("proč se to hodí") resolved for the requested
|
|
1815
|
+
* locale (falls back to the eshop default language). `null` when unset. */
|
|
1816
|
+
note?: string | null;
|
|
1817
|
+
}
|
|
1818
|
+
interface ActivePromotion {
|
|
1819
|
+
id: string;
|
|
1820
|
+
name: string;
|
|
1821
|
+
slug: string;
|
|
1822
|
+
type: string;
|
|
1823
|
+
discountType: string;
|
|
1824
|
+
discountValue: number;
|
|
1825
|
+
startsAt: number;
|
|
1826
|
+
endsAt: number | null;
|
|
1827
|
+
badgeText: string | null;
|
|
1828
|
+
badgeColor: string | null;
|
|
1829
|
+
showCountdown: boolean;
|
|
1830
|
+
couponRequired: boolean;
|
|
1831
|
+
}
|
|
1832
|
+
interface GiftCardBalance {
|
|
1833
|
+
valid: boolean;
|
|
1834
|
+
balance: number;
|
|
1835
|
+
currency: string;
|
|
1836
|
+
}
|
|
1837
|
+
/** Customer gift card purchase (GAP-39): amount + recipient + optional payment method. */
|
|
1838
|
+
interface GiftCardPurchaseInput {
|
|
1839
|
+
/** Gift card value in whole units of the currency (50 to 50000). */
|
|
1840
|
+
amount: number;
|
|
1841
|
+
/** Must be supported by the shop; defaults to the shop default currency. */
|
|
1842
|
+
currency?: string;
|
|
1843
|
+
/** Buyer contact; owns the order and gets the order confirmation. */
|
|
1844
|
+
buyerEmail: string;
|
|
1845
|
+
/** Receives the gift card code once the order is paid. */
|
|
1846
|
+
recipientEmail: string;
|
|
1847
|
+
recipientName?: string;
|
|
1848
|
+
personalMessage?: string;
|
|
1849
|
+
/** Online payment method id (from listPaymentMethods) to start payment right away. */
|
|
1850
|
+
paymentMethodId?: string;
|
|
1851
|
+
locale?: string;
|
|
1852
|
+
}
|
|
1853
|
+
interface GiftCardPurchaseResult {
|
|
1854
|
+
orderId: string;
|
|
1855
|
+
orderNumber: string;
|
|
1856
|
+
grandTotal: number;
|
|
1857
|
+
currency: string;
|
|
1858
|
+
/**
|
|
1859
|
+
* Hosted gateway URL to pay the order, or null (offline method / no method /
|
|
1860
|
+
* gateway init failed). The gift card is generated and emailed to the
|
|
1861
|
+
* recipient only AFTER the order is paid.
|
|
1862
|
+
*/
|
|
1863
|
+
paymentRedirectUrl: string | null;
|
|
1864
|
+
}
|
|
1865
|
+
interface WishlistItem {
|
|
1866
|
+
id: string;
|
|
1867
|
+
productId: string;
|
|
1868
|
+
productName: string;
|
|
1869
|
+
productSku: string;
|
|
1870
|
+
productSlug: string | null;
|
|
1871
|
+
imageUrl: string | null;
|
|
1872
|
+
price: number | null;
|
|
1873
|
+
stockCached: number;
|
|
1874
|
+
createdAt: number;
|
|
1875
|
+
}
|
|
1876
|
+
type SubscriptionStatus = "ACTIVE" | "PAUSED" | "CANCELLED" | "EXPIRED" | "PAYMENT_FAILED";
|
|
1877
|
+
type SubscriptionFrequency = "WEEKLY" | "BIWEEKLY" | "MONTHLY" | "BIMONTHLY" | "QUARTERLY" | "EVERY_6_MONTHS" | "YEARLY" | "CUSTOM_DAYS";
|
|
1878
|
+
interface SubscriptionItem {
|
|
1879
|
+
id: string;
|
|
1880
|
+
productId: string;
|
|
1881
|
+
product: {
|
|
1882
|
+
id: string;
|
|
1883
|
+
slug: string | null;
|
|
1884
|
+
};
|
|
1885
|
+
quantity: number;
|
|
1886
|
+
unitPriceSnapshot: number;
|
|
1887
|
+
currency: string;
|
|
1888
|
+
}
|
|
1889
|
+
interface Subscription {
|
|
1890
|
+
id: string;
|
|
1891
|
+
status: SubscriptionStatus;
|
|
1892
|
+
frequency: SubscriptionFrequency;
|
|
1893
|
+
/** For CUSTOM_DAYS frequency: order every N days. */
|
|
1894
|
+
customDays: number | null;
|
|
1895
|
+
/** Unix ms of the next scheduled order. */
|
|
1896
|
+
nextOrderAt: number;
|
|
1897
|
+
/** Unix ms of the last generated order, if any. */
|
|
1898
|
+
lastOrderAt: number | null;
|
|
1899
|
+
totalOrders: number;
|
|
1900
|
+
/** Max number of orders before the subscription expires (null = unlimited). */
|
|
1901
|
+
maxOrders: number | null;
|
|
1902
|
+
/** Subscriber discount percent applied to each generated order. */
|
|
1903
|
+
discountPercent: number | null;
|
|
1904
|
+
items: SubscriptionItem[];
|
|
1905
|
+
orderCount: number;
|
|
1906
|
+
createdAt: number;
|
|
1907
|
+
updatedAt: number;
|
|
1908
|
+
}
|
|
1909
|
+
interface SubscriptionAction {
|
|
1910
|
+
id: string;
|
|
1911
|
+
status: SubscriptionStatus;
|
|
1912
|
+
/** Present after resume — the newly scheduled next order (Unix ms). */
|
|
1913
|
+
nextOrderAt?: number | null;
|
|
1914
|
+
updatedAt: number;
|
|
1915
|
+
}
|
|
1916
|
+
interface ProductReview {
|
|
1917
|
+
id: string;
|
|
1918
|
+
authorName: string;
|
|
1919
|
+
rating: number;
|
|
1920
|
+
title: string | null;
|
|
1921
|
+
content: string | null;
|
|
1922
|
+
imageUrls: string[];
|
|
1923
|
+
isVerifiedPurchase: boolean;
|
|
1924
|
+
helpfulCount: number;
|
|
1925
|
+
unhelpfulCount: number;
|
|
1926
|
+
replyContent: string | null;
|
|
1927
|
+
replyAt: number | null;
|
|
1928
|
+
createdAt: number;
|
|
1929
|
+
}
|
|
1930
|
+
interface ProductReviewsResponse {
|
|
1931
|
+
reviews: ProductReview[];
|
|
1932
|
+
total: number;
|
|
1933
|
+
page: number;
|
|
1934
|
+
limit: number;
|
|
1935
|
+
averageRating: number;
|
|
1936
|
+
reviewCount: number;
|
|
1937
|
+
}
|
|
1938
|
+
/** Returned by `catalog.notifyWhenAvailable()` — back-in-stock subscription. */
|
|
1939
|
+
interface BackInStockSubscription {
|
|
1940
|
+
id: string;
|
|
1941
|
+
eshopId: string;
|
|
1942
|
+
productId: string;
|
|
1943
|
+
email: string;
|
|
1944
|
+
createdAt: number;
|
|
1945
|
+
}
|
|
1946
|
+
interface SubmitReviewInput {
|
|
1947
|
+
productId: string;
|
|
1948
|
+
rating: number;
|
|
1949
|
+
title?: string;
|
|
1950
|
+
content?: string;
|
|
1951
|
+
authorName: string;
|
|
1952
|
+
authorEmail?: string;
|
|
1953
|
+
imageUrls?: string[];
|
|
1954
|
+
}
|
|
1955
|
+
interface ReturnableOrderItem {
|
|
1956
|
+
orderItemId: string;
|
|
1957
|
+
productName: string;
|
|
1958
|
+
/** Quantity ordered */
|
|
1959
|
+
quantity: number;
|
|
1960
|
+
/** Units still returnable (ordered minus active return claims) */
|
|
1961
|
+
returnableQuantity: number;
|
|
1962
|
+
}
|
|
1963
|
+
/**
|
|
1964
|
+
* Result of the guest order lookup used by the EU withdrawal form:
|
|
1965
|
+
* the customer enters their order number + email and gets back the
|
|
1966
|
+
* internal ids needed to submit a return. No account required.
|
|
1967
|
+
*/
|
|
1968
|
+
interface ReturnableOrder {
|
|
1969
|
+
orderId: string;
|
|
1970
|
+
orderNumber: string;
|
|
1971
|
+
status: string;
|
|
1972
|
+
items: ReturnableOrderItem[];
|
|
1973
|
+
createdAt: number;
|
|
1974
|
+
}
|
|
1975
|
+
interface ReturnRequestItem {
|
|
1976
|
+
id: string;
|
|
1977
|
+
orderItemId: string;
|
|
1978
|
+
productName: string;
|
|
1979
|
+
quantity: number;
|
|
1980
|
+
reason: string | null;
|
|
1981
|
+
imageUrls: string[];
|
|
1982
|
+
}
|
|
1983
|
+
/** Returned by `returns.submit()` — the acknowledged withdrawal request. */
|
|
1984
|
+
interface ReturnRequest {
|
|
1985
|
+
id: string;
|
|
1986
|
+
eshopId: string;
|
|
1987
|
+
orderId: string;
|
|
1988
|
+
/** REQUESTED | APPROVED | SHIPPED_BACK | RECEIVED | REFUNDED | REJECTED | CLOSED */
|
|
1989
|
+
status: string;
|
|
1990
|
+
reason: string;
|
|
1991
|
+
customerNote: string | null;
|
|
1992
|
+
items: ReturnRequestItem[];
|
|
1993
|
+
createdAt: number;
|
|
1994
|
+
}
|
|
1995
|
+
interface ReturnStatusItem {
|
|
1996
|
+
id: string;
|
|
1997
|
+
productName: string;
|
|
1998
|
+
quantity: number;
|
|
1999
|
+
reason: string | null;
|
|
2000
|
+
}
|
|
2001
|
+
/** Returned by `returns.getStatus()` — the full public view of a return. */
|
|
2002
|
+
interface ReturnStatus {
|
|
2003
|
+
id: string;
|
|
2004
|
+
orderNumber: string;
|
|
2005
|
+
/** REQUESTED | APPROVED | SHIPPED_BACK | RECEIVED | REFUNDED | REJECTED | CLOSED */
|
|
2006
|
+
status: string;
|
|
2007
|
+
reason: string;
|
|
2008
|
+
customerNote: string | null;
|
|
2009
|
+
refundMethod: string | null;
|
|
2010
|
+
refundAmount: number | null;
|
|
2011
|
+
refundedAt: number | null;
|
|
2012
|
+
returnTrackingNumber: string | null;
|
|
2013
|
+
items: ReturnStatusItem[];
|
|
2014
|
+
createdAt: number;
|
|
2015
|
+
updatedAt: number;
|
|
2016
|
+
}
|
|
2017
|
+
interface SubmitReturnInput {
|
|
2018
|
+
orderId: string;
|
|
2019
|
+
/**
|
|
2020
|
+
* Email used on the order. Required — it is the ownership gate for guest
|
|
2021
|
+
* withdrawals; the backend rejects submissions whose email doesn't match.
|
|
2022
|
+
*/
|
|
2023
|
+
email: string;
|
|
2024
|
+
reason: string;
|
|
2025
|
+
customerNote?: string;
|
|
2026
|
+
items: {
|
|
2027
|
+
orderItemId: string;
|
|
2028
|
+
productName: string;
|
|
2029
|
+
quantity: number;
|
|
2030
|
+
reason?: string;
|
|
2031
|
+
imageUrls?: string[];
|
|
2032
|
+
}[];
|
|
2033
|
+
}
|
|
2034
|
+
interface CookieConsent {
|
|
2035
|
+
necessary: boolean;
|
|
2036
|
+
analytics: boolean;
|
|
2037
|
+
marketing: boolean;
|
|
2038
|
+
preferences: boolean;
|
|
2039
|
+
consentedAt: number;
|
|
2040
|
+
}
|
|
2041
|
+
interface CookieConsentInput {
|
|
2042
|
+
visitorId: string;
|
|
2043
|
+
analytics: boolean;
|
|
2044
|
+
marketing: boolean;
|
|
2045
|
+
preferences: boolean;
|
|
2046
|
+
}
|
|
2047
|
+
interface QuoteItem {
|
|
2048
|
+
productId: string;
|
|
2049
|
+
quantity: number;
|
|
2050
|
+
requestedPrice: number | null;
|
|
2051
|
+
quotedPrice: number | null;
|
|
2052
|
+
}
|
|
2053
|
+
interface QuoteRequest {
|
|
2054
|
+
id: string;
|
|
2055
|
+
/** PENDING | QUOTED | ACCEPTED | REJECTED | EXPIRED */
|
|
2056
|
+
status: string;
|
|
2057
|
+
contactName: string;
|
|
2058
|
+
contactEmail: string;
|
|
2059
|
+
companyName: string | null;
|
|
2060
|
+
quotedTotal: number | null;
|
|
2061
|
+
quotedCurrency: string | null;
|
|
2062
|
+
quotedNote: string | null;
|
|
2063
|
+
expiresAt: number | null;
|
|
2064
|
+
items: QuoteItem[];
|
|
2065
|
+
createdAt: number;
|
|
2066
|
+
}
|
|
2067
|
+
interface SubmitQuoteInput {
|
|
2068
|
+
contactName: string;
|
|
2069
|
+
contactEmail: string;
|
|
2070
|
+
contactPhone?: string;
|
|
2071
|
+
companyName?: string;
|
|
2072
|
+
companyIco?: string;
|
|
2073
|
+
message?: string;
|
|
2074
|
+
items: {
|
|
2075
|
+
productId: string;
|
|
2076
|
+
quantity: number;
|
|
2077
|
+
requestedPrice?: number;
|
|
2078
|
+
}[];
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
declare class BehioStorefront {
|
|
2082
|
+
private baseUrl;
|
|
2083
|
+
private apiKey;
|
|
2084
|
+
/** Consent-gated persistent visitor id — set by the analytics tracker. */
|
|
2085
|
+
private analyticsVisitorId;
|
|
2086
|
+
private shopDomain?;
|
|
2087
|
+
private defaultLocale?;
|
|
2088
|
+
private defaultCurrency?;
|
|
2089
|
+
private fetchFn;
|
|
2090
|
+
private timeout;
|
|
2091
|
+
private retries;
|
|
2092
|
+
private retryDelay;
|
|
2093
|
+
private accessToken?;
|
|
2094
|
+
private refreshToken?;
|
|
2095
|
+
private isRefreshing;
|
|
2096
|
+
private refreshPromise;
|
|
2097
|
+
private cartSession?;
|
|
2098
|
+
private listeners;
|
|
2099
|
+
private requestInterceptors;
|
|
2100
|
+
private responseInterceptors;
|
|
2101
|
+
private rateLimitRemaining;
|
|
2102
|
+
private rateLimitReset;
|
|
2103
|
+
constructor(config: BehioStorefrontConfig);
|
|
2104
|
+
readonly catalog: CatalogModule;
|
|
2105
|
+
readonly auth: AuthModule;
|
|
2106
|
+
readonly cart: CartModule;
|
|
2107
|
+
readonly checkout: CheckoutModule;
|
|
2108
|
+
readonly orders: OrdersModule;
|
|
2109
|
+
readonly customer: CustomerModule;
|
|
2110
|
+
readonly pages: PagesModule;
|
|
2111
|
+
readonly wishlist: WishlistModule;
|
|
2112
|
+
readonly reviews: ReviewsModule;
|
|
2113
|
+
readonly returns: ReturnsModule;
|
|
2114
|
+
readonly consent: ConsentModule;
|
|
2115
|
+
readonly quotes: QuotesModule;
|
|
2116
|
+
readonly addresses: AddressModule;
|
|
2117
|
+
readonly shipping: ShippingModule;
|
|
2118
|
+
readonly newsletter: NewsletterModule;
|
|
2119
|
+
readonly subscriptions: SubscriptionsModule;
|
|
2120
|
+
readonly certificates: CourseCertificatesModule;
|
|
2121
|
+
/**
|
|
2122
|
+
* Called by the analytics tracker when the visitor grants (id) or revokes
|
|
2123
|
+
* (null) analytics consent. When set, requests carry the X-Behio-Vid header
|
|
2124
|
+
* so the backend can attribute orders to the visitor journey.
|
|
2125
|
+
*/
|
|
2126
|
+
setAnalyticsVisitorId(id: string | null): void;
|
|
2127
|
+
/** The consent-gated visitor id, if analytics consent was granted. */
|
|
2128
|
+
getAnalyticsVisitorId(): string | null;
|
|
2129
|
+
/**
|
|
2130
|
+
* Fire-and-forget Behio Analytics ingest. Uses a bare keepalive fetch (not
|
|
2131
|
+
* the interceptor pipeline) so flushes on pagehide still land, and swallows
|
|
2132
|
+
* every error — analytics must never break the shop. The client sends no
|
|
2133
|
+
* identity; the visitor hash is computed server-side from a daily salt.
|
|
2134
|
+
*/
|
|
2135
|
+
sendAnalyticsEvents(input: {
|
|
2136
|
+
sessionId?: string;
|
|
2137
|
+
/** Persistent consent-gated visitor id (behio_visitor_id). */
|
|
2138
|
+
visitorId?: string;
|
|
2139
|
+
events: Array<{
|
|
2140
|
+
type: "pageview" | "ecommerce" | "custom";
|
|
2141
|
+
name?: string;
|
|
2142
|
+
ts?: number;
|
|
2143
|
+
path?: string;
|
|
2144
|
+
referrer?: string;
|
|
2145
|
+
utmSource?: string;
|
|
2146
|
+
utmMedium?: string;
|
|
2147
|
+
utmCampaign?: string;
|
|
2148
|
+
utmTerm?: string;
|
|
2149
|
+
utmContent?: string;
|
|
2150
|
+
gclid?: string;
|
|
2151
|
+
fbclid?: string;
|
|
2152
|
+
dwellMs?: number;
|
|
2153
|
+
value?: number;
|
|
2154
|
+
currency?: string;
|
|
2155
|
+
props?: Record<string, unknown>;
|
|
2156
|
+
}>;
|
|
2157
|
+
}): Promise<void>;
|
|
2158
|
+
/**
|
|
2159
|
+
* Personal behavioral offers for this visitor (consent-gated id). Returns
|
|
2160
|
+
* only the visitor's own offers; requires the analytics visitor id.
|
|
2161
|
+
*/
|
|
2162
|
+
getPersonalOffers(visitorId: string): Promise<SdkResult<{
|
|
2163
|
+
items: Array<{
|
|
2164
|
+
id: string;
|
|
2165
|
+
productId: string;
|
|
2166
|
+
percent: number;
|
|
2167
|
+
status: string;
|
|
2168
|
+
code: string | null;
|
|
2169
|
+
expiresAt: number;
|
|
2170
|
+
}>;
|
|
2171
|
+
}>>;
|
|
2172
|
+
/** Email-gate completion: trade an e-mail for the personal discount code. */
|
|
2173
|
+
claimOfferByEmail(offerId: string, input: {
|
|
2174
|
+
visitorId: string;
|
|
2175
|
+
email: string;
|
|
2176
|
+
}): Promise<SdkResult<{
|
|
2177
|
+
code: string;
|
|
2178
|
+
percent: number;
|
|
2179
|
+
expiresAt: number;
|
|
2180
|
+
}>>;
|
|
2181
|
+
/** Get basic shop info */
|
|
2182
|
+
getShopInfo(): Promise<SdkResult<ShopInfo>>;
|
|
2183
|
+
/** Get SEO metadata for the shop homepage in the given locale (defaults to shop default). */
|
|
2184
|
+
getShopSeo(locale?: string): Promise<SdkResult<ShopSeo>>;
|
|
2185
|
+
/**
|
|
2186
|
+
* Get the merchant-defined scripts (analytics, pixels, verification, custom
|
|
2187
|
+
* head/body markup) to inject into the storefront. Returns only enabled
|
|
2188
|
+
* entries. Render typed entries into their snippet and RAW verbatim; gate
|
|
2189
|
+
* any entry with `consentRequired` behind the visitor's analytics consent.
|
|
2190
|
+
*/
|
|
2191
|
+
getShopScripts(): Promise<SdkResult<ShopScripts>>;
|
|
2192
|
+
/** Set auth tokens (e.g. from localStorage) */
|
|
2193
|
+
setTokens(tokens: {
|
|
2194
|
+
accessToken: string;
|
|
2195
|
+
refreshToken: string;
|
|
2196
|
+
}): void;
|
|
2197
|
+
/** Clear auth tokens */
|
|
2198
|
+
clearTokens(): void;
|
|
2199
|
+
/** Get current access token */
|
|
2200
|
+
getAccessToken(): string | undefined;
|
|
2201
|
+
/** Get current refresh token */
|
|
2202
|
+
getRefreshToken(): string | undefined;
|
|
2203
|
+
/** Set cart session token (e.g. from cookie) */
|
|
2204
|
+
setCartSession(token: string): void;
|
|
2205
|
+
/** Get cart session token */
|
|
2206
|
+
getCartSession(): string | undefined;
|
|
2207
|
+
/** Clear cart session */
|
|
2208
|
+
clearCartSession(): void;
|
|
2209
|
+
/**
|
|
2210
|
+
* Set the default currency sent on every catalog request (unless a per-call
|
|
2211
|
+
* `currency` overrides it). Read live at request time, so changing it takes
|
|
2212
|
+
* effect immediately without rebuilding the client. Pass undefined to clear
|
|
2213
|
+
* (falls back to the shop's default currency server-side).
|
|
2214
|
+
*/
|
|
2215
|
+
setCurrency(currency: string | undefined): void;
|
|
2216
|
+
/** Get the current default currency, if any. */
|
|
2217
|
+
getCurrency(): string | undefined;
|
|
2218
|
+
/** Set the default locale sent on every catalog request (per-call wins). */
|
|
2219
|
+
setLocale(locale: string | undefined): void;
|
|
2220
|
+
/** Get the current default locale, if any. */
|
|
2221
|
+
getLocale(): string | undefined;
|
|
2222
|
+
/** Subscribe to SDK events. Returns an unsubscribe function. */
|
|
2223
|
+
on(event: BehioEventType, handler: BehioEventHandler): () => void;
|
|
2224
|
+
/** @internal Emit an event (fire-and-forget, handler errors are swallowed) */
|
|
2225
|
+
emit(event: BehioEventType, data?: unknown): void;
|
|
2226
|
+
/** Add a request interceptor. Returns an unsubscribe function. */
|
|
2227
|
+
addRequestInterceptor(fn: RequestInterceptor): () => void;
|
|
2228
|
+
/** Add a response interceptor. Returns an unsubscribe function. */
|
|
2229
|
+
addResponseInterceptor(fn: ResponseInterceptor): () => void;
|
|
2230
|
+
/** Get current rate limit info from latest response headers */
|
|
2231
|
+
getRateLimitInfo(): {
|
|
2232
|
+
remaining: number | null;
|
|
2233
|
+
reset: number | null;
|
|
2234
|
+
};
|
|
2235
|
+
private handleTokenRefresh;
|
|
2236
|
+
/**
|
|
2237
|
+
* Every public module method funnels through here. Internally calls
|
|
2238
|
+
* `rawRequest` (which throws on failure) and maps thrown errors to
|
|
2239
|
+
* `SdkError` so the public surface can return `SdkResult<T>`.
|
|
2240
|
+
*
|
|
2241
|
+
* @internal — don't call from outside the SDK; use the typed module
|
|
2242
|
+
* methods (behio.catalog.*, behio.cart.*, …) instead.
|
|
2243
|
+
*/
|
|
2244
|
+
request<T>(method: string, path: string, options?: {
|
|
2245
|
+
body?: unknown;
|
|
2246
|
+
query?: Record<string, string | number | boolean | undefined | string[] | number[]>;
|
|
2247
|
+
auth?: boolean;
|
|
2248
|
+
signal?: AbortSignal;
|
|
2249
|
+
headers?: Record<string, string>;
|
|
2250
|
+
}): Promise<SdkResult<T>>;
|
|
2251
|
+
/**
|
|
2252
|
+
* Binary GET (PDF downloads). Same auth headers as `request()`, but the
|
|
2253
|
+
* response is returned as a Blob instead of parsed JSON.
|
|
2254
|
+
*
|
|
2255
|
+
* @internal — use the typed module methods (behio.certificates.downloadPdf).
|
|
2256
|
+
*/
|
|
2257
|
+
requestBlob(path: string): Promise<SdkResult<Blob>>;
|
|
2258
|
+
/**
|
|
2259
|
+
* Throws on failure (API error / network / timeout). Kept private so
|
|
2260
|
+
* internal auth refresh recursion keeps its existing control flow —
|
|
2261
|
+
* public callers must go through `request()` which returns Result.
|
|
2262
|
+
*/
|
|
2263
|
+
private rawRequest;
|
|
2264
|
+
}
|
|
2265
|
+
declare class CatalogModule {
|
|
2266
|
+
private client;
|
|
2267
|
+
constructor(client: BehioStorefront);
|
|
2268
|
+
/** List products with filtering, pagination, search */
|
|
2269
|
+
getProducts(query?: ProductsQuery): Promise<SdkResult<PaginatedResponse<ProductListItem>>>;
|
|
2270
|
+
/** Get product detail by slug */
|
|
2271
|
+
getProduct(slug: string, options?: {
|
|
2272
|
+
locale?: string;
|
|
2273
|
+
currency?: string;
|
|
2274
|
+
}): Promise<SdkResult<ProductDetail>>;
|
|
2275
|
+
/** Get category tree */
|
|
2276
|
+
getCategories(locale?: string): Promise<SdkResult<{
|
|
2277
|
+
categories: Category[];
|
|
2278
|
+
}>>;
|
|
2279
|
+
/** Get category detail by slug */
|
|
2280
|
+
getCategory(slug: string, locale?: string): Promise<SdkResult<CategoryDetail>>;
|
|
2281
|
+
/** Get products in a category */
|
|
2282
|
+
getCategoryProducts(slug: string, query?: ProductsQuery): Promise<SdkResult<PaginatedResponse<ProductListItem>>>;
|
|
2283
|
+
/**
|
|
2284
|
+
* Resolved navigation menu by handle (e.g. "main", "footer"), built in the
|
|
2285
|
+
* admin Navigace. Item labels resolve in `locale`; typed refs come back as
|
|
2286
|
+
* {type, slug} for link building. Returns an SdkResult error (404) when the
|
|
2287
|
+
* handle is unknown or inactive — callers fall back to their own source.
|
|
2288
|
+
*/
|
|
2289
|
+
getMenu(handle: string, options?: {
|
|
2290
|
+
locale?: string;
|
|
2291
|
+
}): Promise<SdkResult<Menu>>;
|
|
2292
|
+
/** Get all labels */
|
|
2293
|
+
getLabels(locale?: string): Promise<SdkResult<{
|
|
2294
|
+
labels: ProductLabel[];
|
|
2295
|
+
}>>;
|
|
2296
|
+
/** Get featured products */
|
|
2297
|
+
getFeatured(options?: {
|
|
2298
|
+
locale?: string;
|
|
2299
|
+
currency?: string;
|
|
2300
|
+
}): Promise<SdkResult<PaginatedResponse<ProductListItem>>>;
|
|
2301
|
+
/** Get available filter fields for dynamic filter UI */
|
|
2302
|
+
getFilters(): Promise<SdkResult<{
|
|
2303
|
+
filters: FilterField[];
|
|
2304
|
+
}>>;
|
|
2305
|
+
/**
|
|
2306
|
+
* Facet groups + selection-aware counts for the current filter set (custom
|
|
2307
|
+
* fields, labels, price, availability, rating, subcategories). Pass the SAME
|
|
2308
|
+
* query you pass to `getProducts` (category, search, price, inStock, ratingMin,
|
|
2309
|
+
* customFields, facets slugs, labels): counts for each facet are computed with
|
|
2310
|
+
* that facet excluded, and values that drop to 0 are still returned (render
|
|
2311
|
+
* them disabled). Use this to build an Alza-style filter sidebar.
|
|
2312
|
+
*/
|
|
2313
|
+
getFacets(query?: ProductsQuery): Promise<SdkResult<FacetsResponse>>;
|
|
2314
|
+
/** Search products */
|
|
2315
|
+
search(query: string, options?: {
|
|
2316
|
+
page?: number;
|
|
2317
|
+
limit?: number;
|
|
2318
|
+
}): Promise<SdkResult<PaginatedResponse<ProductListItem>>>;
|
|
2319
|
+
/** List all active bundles */
|
|
2320
|
+
getBundles(): Promise<SdkResult<{
|
|
2321
|
+
items: Bundle[];
|
|
2322
|
+
}>>;
|
|
2323
|
+
/** Get a single bundle by slug */
|
|
2324
|
+
getBundle(slug: string): Promise<SdkResult<Bundle>>;
|
|
2325
|
+
/**
|
|
2326
|
+
* One product group ("collection") by slug with its products as standard
|
|
2327
|
+
* list items. Groups are curated in the admin; use this to render curated
|
|
2328
|
+
* product bands. Returns an SdkResult error (404) when the group is
|
|
2329
|
+
* missing or inactive — callers should render nothing in that case.
|
|
2330
|
+
*/
|
|
2331
|
+
getProductGroup(slug: string, options?: {
|
|
2332
|
+
locale?: string;
|
|
2333
|
+
currency?: string;
|
|
2334
|
+
}): Promise<SdkResult<ProductGroup>>;
|
|
2335
|
+
/**
|
|
2336
|
+
* Cross-sell / related / upsell products for a product. Returns three
|
|
2337
|
+
* separate lists: `related` (podobné produkty), `upsell` (dražší
|
|
2338
|
+
* alternativy) and `crossSell` (doporučené k nákupu). Items are localized
|
|
2339
|
+
* and priced in the requested currency, ready to render with the same card
|
|
2340
|
+
* component as `getFeatured` / `getProductGroup`.
|
|
2341
|
+
*/
|
|
2342
|
+
getCrossSell(productSlug: string, options?: {
|
|
2343
|
+
locale?: string;
|
|
2344
|
+
currency?: string;
|
|
2345
|
+
}): Promise<SdkResult<{
|
|
2346
|
+
related: CrossSellItem[];
|
|
2347
|
+
upsell: CrossSellItem[];
|
|
2348
|
+
crossSell: CrossSellItem[];
|
|
2349
|
+
}>>;
|
|
2350
|
+
/** Active promotions applicable to a product (with countdown end time) */
|
|
2351
|
+
/** Back-in-stock notification subscription for a sold-out product. */
|
|
2352
|
+
notifyWhenAvailable(productId: string, email: string): Promise<SdkResult<BackInStockSubscription>>;
|
|
2353
|
+
getProductPromotions(productSlug: string): Promise<SdkResult<{
|
|
2354
|
+
items: ActivePromotion[];
|
|
2355
|
+
}>>;
|
|
2356
|
+
/** Check a gift card code — returns validity and remaining balance */
|
|
2357
|
+
checkGiftCard(code: string): Promise<SdkResult<GiftCardBalance>>;
|
|
2358
|
+
/**
|
|
2359
|
+
* Buy a gift card (GAP-39): creates a cart-independent order for the chosen
|
|
2360
|
+
* amount. Redirect the customer to `paymentRedirectUrl` when present; the
|
|
2361
|
+
* code is generated and emailed to the recipient once the order is paid.
|
|
2362
|
+
*/
|
|
2363
|
+
purchaseGiftCard(input: GiftCardPurchaseInput): Promise<SdkResult<GiftCardPurchaseResult>>;
|
|
2364
|
+
/** List configured payment methods (filtered by currency). */
|
|
2365
|
+
listPaymentMethods(opts?: {
|
|
2366
|
+
currency?: string;
|
|
2367
|
+
}): Promise<SdkResult<{
|
|
2368
|
+
items: CheckoutPaymentMethod[];
|
|
2369
|
+
}>>;
|
|
2370
|
+
}
|
|
2371
|
+
declare class AuthModule {
|
|
2372
|
+
private client;
|
|
2373
|
+
constructor(client: BehioStorefront);
|
|
2374
|
+
/** Register a new customer */
|
|
2375
|
+
register(input: RegisterInput): Promise<SdkResult<RegisterResult>>;
|
|
2376
|
+
/** Login with email and password */
|
|
2377
|
+
login(input: LoginInput): Promise<SdkResult<AuthTokens>>;
|
|
2378
|
+
/** Refresh access token using refresh token */
|
|
2379
|
+
refresh(refreshToken?: string): Promise<SdkResult<AuthTokens>>;
|
|
2380
|
+
/** Logout (invalidate refresh token) */
|
|
2381
|
+
logout(refreshToken?: string): Promise<SdkResult<MessageResponse>>;
|
|
2382
|
+
/** Request password reset email */
|
|
2383
|
+
forgotPassword(email: string): Promise<SdkResult<MessageResponse>>;
|
|
2384
|
+
/** Reset password with token */
|
|
2385
|
+
resetPassword(token: string, newPassword: string): Promise<SdkResult<MessageResponse>>;
|
|
2386
|
+
/** Verify email with token */
|
|
2387
|
+
verifyEmail(token: string): Promise<SdkResult<MessageResponse>>;
|
|
2388
|
+
/** Check if user is logged in (has access token) */
|
|
2389
|
+
isLoggedIn(): boolean;
|
|
2390
|
+
}
|
|
2391
|
+
declare class CartModule {
|
|
2392
|
+
private client;
|
|
2393
|
+
constructor(client: BehioStorefront);
|
|
2394
|
+
/** Get current cart */
|
|
2395
|
+
get(): Promise<SdkResult<Cart>>;
|
|
2396
|
+
/** Add item to cart */
|
|
2397
|
+
addItem(input: AddToCartInput): Promise<SdkResult<Cart & {
|
|
2398
|
+
newSessionToken?: string;
|
|
2399
|
+
}>>;
|
|
2400
|
+
/** Update item quantity */
|
|
2401
|
+
updateQuantity(itemId: string, quantity: number): Promise<SdkResult<Cart>>;
|
|
2402
|
+
/** Remove item from cart */
|
|
2403
|
+
removeItem(itemId: string): Promise<SdkResult<Cart>>;
|
|
2404
|
+
/** Clear entire cart */
|
|
2405
|
+
clear(): Promise<SdkResult<void>>;
|
|
2406
|
+
/** Apply a gift card code to the cart. Balance is deducted at checkout. */
|
|
2407
|
+
applyGiftCard(code: string): Promise<SdkResult<Cart>>;
|
|
2408
|
+
/** Remove a specific applied gift card from the cart by its code. */
|
|
2409
|
+
removeGiftCard(code: string): Promise<SdkResult<Cart>>;
|
|
2410
|
+
/**
|
|
2411
|
+
* Add a bundle to the cart. Price is snapshotted at the bundle's current
|
|
2412
|
+
* price. Pass either the bundle id or its slug — slug is more ergonomic
|
|
2413
|
+
* for static storefront wiring (`behio.cart.addBundle({slug: "morning-set"})`).
|
|
2414
|
+
*
|
|
2415
|
+
* Respects the bundle's `minQuantity`, `maxQuantity`, and `stockLimit`:
|
|
2416
|
+
* the request rejects with HTTP 400 if the resulting cart line would
|
|
2417
|
+
* violate any of them. The returned error includes the relevant field
|
|
2418
|
+
* (`minQuantity`, `maxQuantity`, or `remaining`) so the storefront can
|
|
2419
|
+
* surface a meaningful message.
|
|
2420
|
+
*
|
|
2421
|
+
* @param identifier Either `{id: bundleId}` or `{slug: bundleSlug}`. As a
|
|
2422
|
+
* convenience, passing a plain string is treated as the
|
|
2423
|
+
* bundle id for backwards compatibility.
|
|
2424
|
+
* @param quantity How many bundles to add (defaults to 1). Capped by
|
|
2425
|
+
* the bundle's `maxQuantity` if set.
|
|
2426
|
+
*/
|
|
2427
|
+
addBundle(identifier: string | {
|
|
2428
|
+
id: string;
|
|
2429
|
+
} | {
|
|
2430
|
+
slug: string;
|
|
2431
|
+
}, quantity?: number): Promise<SdkResult<Cart>>;
|
|
2432
|
+
/** Update quantity of a bundle already in the cart */
|
|
2433
|
+
updateBundleQuantity(bundleId: string, quantity: number): Promise<SdkResult<Cart>>;
|
|
2434
|
+
/** Remove a bundle from the cart */
|
|
2435
|
+
removeBundle(bundleId: string): Promise<SdkResult<Cart>>;
|
|
2436
|
+
/** Merge anonymous cart into authenticated customer cart */
|
|
2437
|
+
merge(): Promise<SdkResult<Cart>>;
|
|
2438
|
+
/** Apply discount code */
|
|
2439
|
+
applyDiscount(code: string): Promise<SdkResult<Cart>>;
|
|
2440
|
+
/** Remove discount code */
|
|
2441
|
+
removeDiscount(): Promise<SdkResult<Cart>>;
|
|
2442
|
+
}
|
|
2443
|
+
declare class CheckoutModule {
|
|
2444
|
+
private client;
|
|
2445
|
+
constructor(client: BehioStorefront);
|
|
2446
|
+
/** Create order from cart */
|
|
2447
|
+
createOrder(input: CheckoutInput): Promise<SdkResult<OrderDetail>>;
|
|
2448
|
+
}
|
|
2449
|
+
declare class OrdersModule {
|
|
2450
|
+
private client;
|
|
2451
|
+
constructor(client: BehioStorefront);
|
|
2452
|
+
/** List customer orders (requires auth) */
|
|
2453
|
+
list(options?: {
|
|
2454
|
+
page?: number;
|
|
2455
|
+
limit?: number;
|
|
2456
|
+
}): Promise<SdkResult<PaginatedResponse<OrderListItem>>>;
|
|
2457
|
+
/** Get order detail (requires auth) */
|
|
2458
|
+
get(orderNumber: string): Promise<SdkResult<OrderDetail>>;
|
|
2459
|
+
/** Cancel a PENDING order (requires auth) */
|
|
2460
|
+
cancel(orderNumber: string): Promise<SdkResult<OrderDetail>>;
|
|
2461
|
+
/**
|
|
2462
|
+
* Track an order by tracking token (no login, only API key). Returns a
|
|
2463
|
+
* PII-minimized view: order status + items + masked email + destination
|
|
2464
|
+
* city, never full address / phone / billing — the token travels in URLs
|
|
2465
|
+
* and e-mails so it must not expose full personal data.
|
|
2466
|
+
*/
|
|
2467
|
+
track(trackingToken: string): Promise<SdkResult<OrderTracking>>;
|
|
2468
|
+
/**
|
|
2469
|
+
* Step 1 of guest order-access: request a 6-digit code e-mailed to the
|
|
2470
|
+
* address on the order. The response is always generic (success) regardless
|
|
2471
|
+
* of whether the order number + e-mail match, so order numbers can't be
|
|
2472
|
+
* enumerated. No login, only API key.
|
|
2473
|
+
*/
|
|
2474
|
+
requestAccessCode(orderNumber: string, email: string): Promise<SdkResult<OrderAccessRequestResponse>>;
|
|
2475
|
+
/**
|
|
2476
|
+
* Step 2 of guest order-access: verify the e-mailed code. On success returns
|
|
2477
|
+
* the FULL order detail plus a short-lived `accessToken` you can pass to
|
|
2478
|
+
* {@link getByAccessToken} to re-fetch the detail without re-entering the
|
|
2479
|
+
* code. No login, only API key.
|
|
2480
|
+
*/
|
|
2481
|
+
verifyAccessCode(orderNumber: string, email: string, code: string): Promise<SdkResult<OrderAccessVerifyResponse>>;
|
|
2482
|
+
/**
|
|
2483
|
+
* Re-fetch a guest order's full detail using the `accessToken` returned by
|
|
2484
|
+
* {@link verifyAccessCode}. The token is scoped to that single order and
|
|
2485
|
+
* expires after 30 minutes.
|
|
2486
|
+
*/
|
|
2487
|
+
getByAccessToken(accessToken: string): Promise<SdkResult<OrderDetail>>;
|
|
2488
|
+
/**
|
|
2489
|
+
* Guest digital download (GAP-07): mint a short-lived signed URL for a
|
|
2490
|
+
* download grant on a guest-accessed order, using the order-access token from
|
|
2491
|
+
* {@link verifyAccessCode}. Scoped to that one order.
|
|
2492
|
+
*/
|
|
2493
|
+
getAccessDownloadUrl(accessToken: string, downloadId: string): Promise<SdkResult<DownloadUrl>>;
|
|
2494
|
+
}
|
|
2495
|
+
declare class CustomerModule {
|
|
2496
|
+
private client;
|
|
2497
|
+
constructor(client: BehioStorefront);
|
|
2498
|
+
/** Get customer profile */
|
|
2499
|
+
getProfile(): Promise<SdkResult<CustomerProfile>>;
|
|
2500
|
+
/** Update customer profile */
|
|
2501
|
+
updateProfile(data: Partial<Pick<CustomerProfile, "firstName" | "lastName" | "phone">>): Promise<SdkResult<CustomerProfile>>;
|
|
2502
|
+
/** Change password */
|
|
2503
|
+
changePassword(currentPassword: string, newPassword: string): Promise<SdkResult<MessageResponse>>;
|
|
2504
|
+
/** List addresses */
|
|
2505
|
+
getAddresses(): Promise<SdkResult<{
|
|
2506
|
+
items: CustomerAddress[];
|
|
2507
|
+
}>>;
|
|
2508
|
+
/** Create address */
|
|
2509
|
+
createAddress(address: Omit<CustomerAddress, "id">): Promise<SdkResult<CustomerAddress>>;
|
|
2510
|
+
/** Update address */
|
|
2511
|
+
updateAddress(addressId: string, data: Partial<CustomerAddress>): Promise<SdkResult<CustomerAddress>>;
|
|
2512
|
+
/** Delete address */
|
|
2513
|
+
deleteAddress(addressId: string): Promise<SdkResult<void>>;
|
|
2514
|
+
/**
|
|
2515
|
+
* Loyalty program summary for the logged-in customer (points balance +
|
|
2516
|
+
* value, current tier, next-tier progress, point ratio, referral code,
|
|
2517
|
+
* recent transactions). Requires an authenticated customer session.
|
|
2518
|
+
*/
|
|
2519
|
+
getLoyalty(): Promise<SdkResult<LoyaltySummary>>;
|
|
2520
|
+
/**
|
|
2521
|
+
* Digital product delivery (GAP-07): list the logged-in customer's download
|
|
2522
|
+
* grants across all their orders (file name, product, remaining downloads,
|
|
2523
|
+
* expiry). Requires an authenticated customer session.
|
|
2524
|
+
*/
|
|
2525
|
+
getDownloads(): Promise<SdkResult<{
|
|
2526
|
+
items: DigitalDownload[];
|
|
2527
|
+
}>>;
|
|
2528
|
+
/**
|
|
2529
|
+
* Mint a short-lived signed URL for one download grant. Counts against the
|
|
2530
|
+
* grant's download budget and enforces the max-download + expiry limits
|
|
2531
|
+
* server-side. Requires an authenticated customer session.
|
|
2532
|
+
*/
|
|
2533
|
+
getDownloadUrl(downloadId: string): Promise<SdkResult<DownloadUrl>>;
|
|
2534
|
+
/**
|
|
2535
|
+
* Online courses (LMS): list the logged-in customer's enrolled courses
|
|
2536
|
+
* with progress. Enrollment is created automatically when an order with a
|
|
2537
|
+
* course product is paid. Requires an authenticated customer session.
|
|
2538
|
+
*/
|
|
2539
|
+
getCourses(): Promise<SdkResult<{
|
|
2540
|
+
items: CourseListItem[];
|
|
2541
|
+
}>>;
|
|
2542
|
+
/**
|
|
2543
|
+
* Course player payload: modules and lessons in order, with per-lesson
|
|
2544
|
+
* drip-unlock state. Locked lessons never contain content — the server
|
|
2545
|
+
* withholds `videoUrl`/`content`/`attachments` until `unlockAt`.
|
|
2546
|
+
*/
|
|
2547
|
+
getCourse(courseId: string): Promise<SdkResult<CourseDetail>>;
|
|
2548
|
+
/** Mark an unlocked lesson as completed (idempotent). */
|
|
2549
|
+
completeLesson(courseId: string, lessonId: string): Promise<SdkResult<CourseProgress>>;
|
|
2550
|
+
/**
|
|
2551
|
+
* Quiz for an unlocked lesson. Correct answers are never included — scoring
|
|
2552
|
+
* happens server-side in `submitLessonQuiz`. Locked lessons return 403.
|
|
2553
|
+
*/
|
|
2554
|
+
getLessonQuiz(courseId: string, lessonId: string): Promise<SdkResult<LessonQuiz>>;
|
|
2555
|
+
/**
|
|
2556
|
+
* Submit quiz answers: returns the score, reveals correct answers and, when
|
|
2557
|
+
* the score reaches `passPercent` (70 %), marks the lesson completed
|
|
2558
|
+
* automatically.
|
|
2559
|
+
*/
|
|
2560
|
+
submitLessonQuiz(courseId: string, lessonId: string, answers: QuizAnswerInput[]): Promise<SdkResult<QuizResult>>;
|
|
2561
|
+
/**
|
|
2562
|
+
* Completion certificates of the logged-in customer. Each carries a public
|
|
2563
|
+
* verification code for sharing (LinkedIn, CV).
|
|
2564
|
+
*/
|
|
2565
|
+
getCourseCertificates(): Promise<SdkResult<{
|
|
2566
|
+
items: CourseCertificate[];
|
|
2567
|
+
}>>;
|
|
2568
|
+
/**
|
|
2569
|
+
* AI tutor "Ask about this lesson": the student's private thread for one
|
|
2570
|
+
* lesson (oldest first). `enabled: false` = the merchant turned the tutor
|
|
2571
|
+
* off — hide the widget. Locked lessons return 403.
|
|
2572
|
+
*/
|
|
2573
|
+
getLessonTutorThread(courseId: string, lessonId: string): Promise<SdkResult<CourseTutorThread>>;
|
|
2574
|
+
/**
|
|
2575
|
+
* Ask the AI tutor a question about the lesson. The answer sticks to the
|
|
2576
|
+
* lesson topic and comes back in the language of the question (Czech by
|
|
2577
|
+
* default). Rate limited (20/min); 403 on locked lessons or when the
|
|
2578
|
+
* merchant disabled the tutor.
|
|
2579
|
+
*/
|
|
2580
|
+
askLessonTutor(courseId: string, lessonId: string, question: string): Promise<SdkResult<CourseTutorMessage>>;
|
|
2581
|
+
/**
|
|
2582
|
+
* Lesson discussion: paginated top-level comments (newest first) with one
|
|
2583
|
+
* level of replies. Only enrolled customers with the lesson unlocked; 403
|
|
2584
|
+
* when the merchant disabled the discussion.
|
|
2585
|
+
*/
|
|
2586
|
+
getLessonComments(courseId: string, lessonId: string, page?: number): Promise<SdkResult<CourseCommentsList>>;
|
|
2587
|
+
/**
|
|
2588
|
+
* Post a comment under the lesson, or a reply when `parentId` points to a
|
|
2589
|
+
* top-level comment (replies go one level deep only). Max 5000 characters.
|
|
2590
|
+
*/
|
|
2591
|
+
postLessonComment(courseId: string, lessonId: string, body: string, parentId?: string): Promise<SdkResult<CoursePostedComment>>;
|
|
2592
|
+
/**
|
|
2593
|
+
* Delete the customer's OWN comment (including its replies). Someone
|
|
2594
|
+
* else's comment returns 404.
|
|
2595
|
+
*/
|
|
2596
|
+
deleteLessonComment(courseId: string, lessonId: string, commentId: string): Promise<SdkResult<void>>;
|
|
2597
|
+
/**
|
|
2598
|
+
* The student's private note for one lesson. `body` is an empty string
|
|
2599
|
+
* when no note exists yet. Visible only to the logged-in student.
|
|
2600
|
+
*/
|
|
2601
|
+
getLessonNote(courseId: string, lessonId: string): Promise<SdkResult<LessonNote>>;
|
|
2602
|
+
/**
|
|
2603
|
+
* Save (upsert) the student's private lesson note. Autosave-friendly; an
|
|
2604
|
+
* empty string clears the note. Max 20 000 characters.
|
|
2605
|
+
*/
|
|
2606
|
+
saveLessonNote(courseId: string, lessonId: string, body: string): Promise<SdkResult<LessonNote>>;
|
|
2607
|
+
}
|
|
2608
|
+
declare class CourseCertificatesModule {
|
|
2609
|
+
private client;
|
|
2610
|
+
constructor(client: BehioStorefront);
|
|
2611
|
+
/**
|
|
2612
|
+
* Publicly verify a certificate code (no customer login needed) — build a
|
|
2613
|
+
* `/certifikat/{code}` page with this. Unknown codes return a 404 error.
|
|
2614
|
+
*/
|
|
2615
|
+
verify(code: string): Promise<SdkResult<CertificateVerification>>;
|
|
2616
|
+
/**
|
|
2617
|
+
* Download the certificate as a branded PDF (A5 landscape). Returns a Blob;
|
|
2618
|
+
* trigger a browser download via `URL.createObjectURL(blob)`.
|
|
2619
|
+
*/
|
|
2620
|
+
downloadPdf(code: string): Promise<SdkResult<Blob>>;
|
|
2621
|
+
}
|
|
2622
|
+
declare class PagesModule {
|
|
2623
|
+
private client;
|
|
2624
|
+
constructor(client: BehioStorefront);
|
|
2625
|
+
/** List CMS pages */
|
|
2626
|
+
list(locale?: string): Promise<SdkResult<{
|
|
2627
|
+
pages: Page[];
|
|
2628
|
+
}>>;
|
|
2629
|
+
/** Get page by slug */
|
|
2630
|
+
get(slug: string, locale?: string): Promise<SdkResult<PageDetail>>;
|
|
2631
|
+
}
|
|
2632
|
+
declare class WishlistModule {
|
|
2633
|
+
private client;
|
|
2634
|
+
constructor(client: BehioStorefront);
|
|
2635
|
+
get(): Promise<SdkResult<{
|
|
2636
|
+
items: WishlistItem[];
|
|
2637
|
+
}>>;
|
|
2638
|
+
add(productId: string): Promise<SdkResult<{
|
|
2639
|
+
success: boolean;
|
|
2640
|
+
}>>;
|
|
2641
|
+
remove(productId: string): Promise<SdkResult<{
|
|
2642
|
+
success: boolean;
|
|
2643
|
+
}>>;
|
|
2644
|
+
isInWishlist(productId: string): Promise<SdkResult<{
|
|
2645
|
+
inWishlist: boolean;
|
|
2646
|
+
}>>;
|
|
2647
|
+
}
|
|
2648
|
+
declare class SubscriptionsModule {
|
|
2649
|
+
private client;
|
|
2650
|
+
constructor(client: BehioStorefront);
|
|
2651
|
+
/**
|
|
2652
|
+
* List the logged-in customer's recurring-order subscriptions (products,
|
|
2653
|
+
* cadence, next order date, status). Requires an authenticated customer
|
|
2654
|
+
* session. Subscriptions are created by the merchant in v1.
|
|
2655
|
+
*/
|
|
2656
|
+
list(): Promise<SdkResult<{
|
|
2657
|
+
items: Subscription[];
|
|
2658
|
+
}>>;
|
|
2659
|
+
/** Pause an active subscription (no orders are generated while paused). */
|
|
2660
|
+
pause(subscriptionId: string): Promise<SdkResult<SubscriptionAction>>;
|
|
2661
|
+
/** Resume a paused subscription (re-schedules the next order). */
|
|
2662
|
+
resume(subscriptionId: string): Promise<SdkResult<SubscriptionAction>>;
|
|
2663
|
+
/** Cancel a subscription permanently (no more orders). */
|
|
2664
|
+
cancel(subscriptionId: string): Promise<SdkResult<SubscriptionAction>>;
|
|
2665
|
+
}
|
|
2666
|
+
declare class ReviewsModule {
|
|
2667
|
+
private client;
|
|
2668
|
+
constructor(client: BehioStorefront);
|
|
2669
|
+
getProductReviews(productId: string, page?: number, limit?: number): Promise<SdkResult<ProductReviewsResponse>>;
|
|
2670
|
+
submit(input: SubmitReviewInput): Promise<SdkResult<{
|
|
2671
|
+
id: string;
|
|
2672
|
+
}>>;
|
|
2673
|
+
voteHelpful(reviewId: string, helpful: boolean): Promise<SdkResult<{
|
|
2674
|
+
success: boolean;
|
|
2675
|
+
}>>;
|
|
2676
|
+
}
|
|
2677
|
+
declare class ReturnsModule {
|
|
2678
|
+
private client;
|
|
2679
|
+
constructor(client: BehioStorefront);
|
|
2680
|
+
/**
|
|
2681
|
+
* Guest order lookup for the EU withdrawal form: order number + the email
|
|
2682
|
+
* used on the order resolve to the order id and per-item returnable
|
|
2683
|
+
* quantities. POST so the email never appears in a URL.
|
|
2684
|
+
*/
|
|
2685
|
+
lookupOrder(orderNumber: string, email: string): Promise<SdkResult<ReturnableOrder>>;
|
|
2686
|
+
submit(input: SubmitReturnInput): Promise<SdkResult<ReturnRequest>>;
|
|
2687
|
+
/** Email is the ownership gate; POST so it never lands in a URL / log. */
|
|
2688
|
+
getStatus(returnId: string, email: string): Promise<SdkResult<ReturnStatus>>;
|
|
2689
|
+
}
|
|
2690
|
+
declare class ConsentModule {
|
|
2691
|
+
private client;
|
|
2692
|
+
constructor(client: BehioStorefront);
|
|
2693
|
+
record(input: CookieConsentInput): Promise<SdkResult<CookieConsent>>;
|
|
2694
|
+
get(visitorId: string): Promise<SdkResult<CookieConsent | null>>;
|
|
2695
|
+
revoke(visitorId: string): Promise<SdkResult<{
|
|
2696
|
+
success: boolean;
|
|
2697
|
+
}>>;
|
|
2698
|
+
}
|
|
2699
|
+
declare class QuotesModule {
|
|
2700
|
+
private client;
|
|
2701
|
+
constructor(client: BehioStorefront);
|
|
2702
|
+
submit(input: SubmitQuoteInput): Promise<SdkResult<QuoteRequest>>;
|
|
2703
|
+
accept(quoteId: string, email: string): Promise<SdkResult<QuoteRequest>>;
|
|
2704
|
+
/** Email is the ownership gate — quotes carry contact PII and negotiated
|
|
2705
|
+
* prices, so the id alone is never enough. POST keeps it out of URLs. */
|
|
2706
|
+
getStatus(quoteId: string, email: string): Promise<SdkResult<QuoteRequest>>;
|
|
2707
|
+
/**
|
|
2708
|
+
* The logged-in customer's own quote requests ("Moje poptávky", GAP-18).
|
|
2709
|
+
* Requires an authenticated session; ownership is the auth token (customer id
|
|
2710
|
+
* + verified email), never a payload. Newest first.
|
|
2711
|
+
*/
|
|
2712
|
+
listMine(): Promise<SdkResult<{
|
|
2713
|
+
items: QuoteRequest[];
|
|
2714
|
+
}>>;
|
|
2715
|
+
}
|
|
2716
|
+
interface AddressSuggestion {
|
|
2717
|
+
placeId: string;
|
|
2718
|
+
description: string;
|
|
2719
|
+
street: string;
|
|
2720
|
+
city: string;
|
|
2721
|
+
zip: string;
|
|
2722
|
+
country: string;
|
|
2723
|
+
countryCode: string;
|
|
2724
|
+
}
|
|
2725
|
+
interface AddressDetail {
|
|
2726
|
+
street: string;
|
|
2727
|
+
streetNumber: string;
|
|
2728
|
+
city: string;
|
|
2729
|
+
zip: string;
|
|
2730
|
+
country: string;
|
|
2731
|
+
countryCode: string;
|
|
2732
|
+
formattedAddress: string;
|
|
2733
|
+
lat: number;
|
|
2734
|
+
lng: number;
|
|
2735
|
+
}
|
|
2736
|
+
declare class AddressModule {
|
|
2737
|
+
private client;
|
|
2738
|
+
constructor(client: BehioStorefront);
|
|
2739
|
+
/** Search for address suggestions (debounce on your side, or use the React hook) */
|
|
2740
|
+
autocomplete(query: string, country: string): Promise<SdkResult<{
|
|
2741
|
+
suggestions: AddressSuggestion[];
|
|
2742
|
+
}>>;
|
|
2743
|
+
/** Get full structured address from a suggestion's placeId */
|
|
2744
|
+
getDetail(placeId: string): Promise<SdkResult<AddressDetail>>;
|
|
2745
|
+
}
|
|
2746
|
+
/**
|
|
2747
|
+
* Storefront shipping module — list configured methods and fetch live
|
|
2748
|
+
* quotes for a destination + cart. Use `listMethods` for the always-on
|
|
2749
|
+
* picker (sidebar, info page) and `quote` once the customer enters a
|
|
2750
|
+
* destination address so live-quote providers (Zaslat etc.) can return
|
|
2751
|
+
* destination-specific prices.
|
|
2752
|
+
*/
|
|
2753
|
+
declare class ShippingModule {
|
|
2754
|
+
private client;
|
|
2755
|
+
constructor(client: BehioStorefront);
|
|
2756
|
+
/**
|
|
2757
|
+
* Return the configured shipping methods that pass the current
|
|
2758
|
+
* currency + country filter. Fixed-price methods come back with
|
|
2759
|
+
* their `pricing[]` row resolved; live-quote methods come back with
|
|
2760
|
+
* `price` 0 here — call `quote()` to get the real live price.
|
|
2761
|
+
*/
|
|
2762
|
+
listMethods(opts?: {
|
|
2763
|
+
currency?: string;
|
|
2764
|
+
country?: string;
|
|
2765
|
+
cartTotal?: number;
|
|
2766
|
+
cartWeightKg?: number;
|
|
2767
|
+
}): Promise<SdkResult<{
|
|
2768
|
+
items: ShippingMethodSummary[];
|
|
2769
|
+
}>>;
|
|
2770
|
+
/**
|
|
2771
|
+
* Quote shipping for a destination address + cart contents. Each
|
|
2772
|
+
* configured method is evaluated:
|
|
2773
|
+
* - `priceStrategy="fixed"` → resolved from the merchant's per-currency
|
|
2774
|
+
* `pricing[]` rows + free-shipping threshold check.
|
|
2775
|
+
* - `priceStrategy="live_quote"` → dispatched to the upstream
|
|
2776
|
+
* meta-provider (Zaslat, future Shippo / Sendcloud / …) and run
|
|
2777
|
+
* through the merchant's markup/rounding rules.
|
|
2778
|
+
*
|
|
2779
|
+
* Filter `available: true` for the checkout picker; `available: false`
|
|
2780
|
+
* rows carry a `reason` (`"no_rate_returned"`, `"live_quote_not_implemented"`,
|
|
2781
|
+
* …) you can log but should not display.
|
|
2782
|
+
*/
|
|
2783
|
+
quote(input: ShippingQuoteInput): Promise<SdkResult<{
|
|
2784
|
+
items: ShippingQuote[];
|
|
2785
|
+
}>>;
|
|
2786
|
+
/**
|
|
2787
|
+
* List pickup points (parcel shops / lockers) for a method that has
|
|
2788
|
+
* `supportsPickupPoints`. Filter with `query` (name / city / zip) for a
|
|
2789
|
+
* "find your branch" box. Send the chosen point's `externalId` back as
|
|
2790
|
+
* `checkout.pickupPointId`.
|
|
2791
|
+
*/
|
|
2792
|
+
getPickupPoints(input: PickupPointsInput): Promise<SdkResult<{
|
|
2793
|
+
items: PickupPoint[];
|
|
2794
|
+
}>>;
|
|
2795
|
+
}
|
|
2796
|
+
/**
|
|
2797
|
+
* First-party newsletter opt-in. Use for the footer signup block and the
|
|
2798
|
+
* checkout newsletter checkbox (render its default from
|
|
2799
|
+
* `ShopInfo.checkout.newsletterOptInDefault`). Subscribing is idempotent and
|
|
2800
|
+
* re-activates a previously unsubscribed email. Pass the hidden `website`
|
|
2801
|
+
* honeypot field straight through from your form: a filled value is silently
|
|
2802
|
+
* accepted but stored nowhere.
|
|
2803
|
+
*/
|
|
2804
|
+
declare class NewsletterModule {
|
|
2805
|
+
private client;
|
|
2806
|
+
constructor(client: BehioStorefront);
|
|
2807
|
+
subscribe(input: NewsletterSubscribeInput): Promise<SdkResult<NewsletterSubscribeResult>>;
|
|
2808
|
+
unsubscribe(email: string): Promise<SdkResult<NewsletterUnsubscribeResult>>;
|
|
2809
|
+
}
|
|
2810
|
+
|
|
60
2811
|
interface BehioContextValue {
|
|
61
2812
|
client: BehioStorefront;
|
|
62
2813
|
storage: StorageAdapter;
|
|
@@ -332,6 +3083,154 @@ declare function useLoyalty(options?: UseLoyaltyOptions): {
|
|
|
332
3083
|
refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<LoyaltySummary>, Error>>;
|
|
333
3084
|
};
|
|
334
3085
|
|
|
3086
|
+
interface UseCoursesOptions {
|
|
3087
|
+
enabled?: boolean;
|
|
3088
|
+
}
|
|
3089
|
+
/**
|
|
3090
|
+
* "My courses" list for the logged-in customer: enrolled courses with
|
|
3091
|
+
* progress. Enrollment happens automatically when an order containing a
|
|
3092
|
+
* course product is paid. Only runs when a customer is authenticated.
|
|
3093
|
+
*/
|
|
3094
|
+
declare function useCourses(options?: UseCoursesOptions): {
|
|
3095
|
+
courses: CourseListItem[];
|
|
3096
|
+
isLoading: boolean;
|
|
3097
|
+
error: Error | null;
|
|
3098
|
+
refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<{
|
|
3099
|
+
items: CourseListItem[];
|
|
3100
|
+
}>, Error>>;
|
|
3101
|
+
};
|
|
3102
|
+
interface UseCourseOptions {
|
|
3103
|
+
enabled?: boolean;
|
|
3104
|
+
}
|
|
3105
|
+
/**
|
|
3106
|
+
* Course player payload: modules and lessons in order with drip-unlock
|
|
3107
|
+
* state, plus a `completeLesson` mutation that records progress and
|
|
3108
|
+
* refreshes the course. Locked lessons carry no content — render the
|
|
3109
|
+
* title + `unlockAt` and let the server decide when content appears.
|
|
3110
|
+
*/
|
|
3111
|
+
declare function useCourse(courseId: string | null, options?: UseCourseOptions): {
|
|
3112
|
+
course: NoInfer<CourseDetail> | undefined;
|
|
3113
|
+
isLoading: boolean;
|
|
3114
|
+
error: Error | null;
|
|
3115
|
+
refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<CourseDetail>, Error>>;
|
|
3116
|
+
completeLesson: (lessonId: string) => Promise<CourseProgress>;
|
|
3117
|
+
isCompleting: boolean;
|
|
3118
|
+
};
|
|
3119
|
+
interface UseLessonQuizOptions {
|
|
3120
|
+
enabled?: boolean;
|
|
3121
|
+
}
|
|
3122
|
+
/**
|
|
3123
|
+
* Quiz for an unlocked lesson plus a `submit` mutation. The quiz payload never
|
|
3124
|
+
* contains correct answers; `submit` returns the score, reveals the correct
|
|
3125
|
+
* options and (at a passing score) marks the lesson completed, refreshing the
|
|
3126
|
+
* course queries.
|
|
3127
|
+
*/
|
|
3128
|
+
declare function useLessonQuiz(courseId: string | null, lessonId: string | null, options?: UseLessonQuizOptions): {
|
|
3129
|
+
quiz: NoInfer<LessonQuiz> | undefined;
|
|
3130
|
+
isLoading: boolean;
|
|
3131
|
+
error: Error | null;
|
|
3132
|
+
refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<LessonQuiz>, Error>>;
|
|
3133
|
+
submitQuiz: (answers: QuizAnswerInput[]) => Promise<QuizResult>;
|
|
3134
|
+
isSubmitting: boolean;
|
|
3135
|
+
result: QuizResult | null;
|
|
3136
|
+
};
|
|
3137
|
+
interface UseCourseCertificatesOptions {
|
|
3138
|
+
enabled?: boolean;
|
|
3139
|
+
}
|
|
3140
|
+
/**
|
|
3141
|
+
* Completion certificates of the logged-in customer. Each has a public
|
|
3142
|
+
* verification `code`; download the branded PDF via
|
|
3143
|
+
* `client.certificates.downloadPdf(code)`.
|
|
3144
|
+
*/
|
|
3145
|
+
declare function useCourseCertificates(options?: UseCourseCertificatesOptions): {
|
|
3146
|
+
certificates: CourseCertificate[];
|
|
3147
|
+
isLoading: boolean;
|
|
3148
|
+
error: Error | null;
|
|
3149
|
+
refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<{
|
|
3150
|
+
items: CourseCertificate[];
|
|
3151
|
+
}>, Error>>;
|
|
3152
|
+
};
|
|
3153
|
+
interface UseCertificateVerificationOptions {
|
|
3154
|
+
enabled?: boolean;
|
|
3155
|
+
}
|
|
3156
|
+
/**
|
|
3157
|
+
* Public certificate verification by code (no login needed) — for the
|
|
3158
|
+
* `/certifikat/{code}` page. Unknown codes surface as a NOT_FOUND error.
|
|
3159
|
+
*/
|
|
3160
|
+
declare function useCertificateVerification(code: string | null, options?: UseCertificateVerificationOptions): {
|
|
3161
|
+
verification: NoInfer<CertificateVerification> | null;
|
|
3162
|
+
isLoading: boolean;
|
|
3163
|
+
error: Error | null;
|
|
3164
|
+
refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<CertificateVerification>, Error>>;
|
|
3165
|
+
};
|
|
3166
|
+
|
|
3167
|
+
interface UseLessonTutorOptions {
|
|
3168
|
+
enabled?: boolean;
|
|
3169
|
+
}
|
|
3170
|
+
/**
|
|
3171
|
+
* AI tutor "Zeptejte se AI" under a lesson: the student's private thread plus
|
|
3172
|
+
* an `ask` mutation. Render the widget only when `enabled` is true (the
|
|
3173
|
+
* merchant can turn the tutor off). Locked lessons surface as a 403 error.
|
|
3174
|
+
*/
|
|
3175
|
+
declare function useLessonTutor(courseId: string | null, lessonId: string | null, options?: UseLessonTutorOptions): {
|
|
3176
|
+
messages: CourseTutorMessage[];
|
|
3177
|
+
/** False when the merchant disabled the AI tutor — hide the widget. */
|
|
3178
|
+
enabled: boolean;
|
|
3179
|
+
isLoading: boolean;
|
|
3180
|
+
error: Error | null;
|
|
3181
|
+
refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<CourseTutorThread>, Error>>;
|
|
3182
|
+
ask: (question: string) => Promise<CourseTutorMessage>;
|
|
3183
|
+
isAsking: boolean;
|
|
3184
|
+
askError: Error | null;
|
|
3185
|
+
};
|
|
3186
|
+
|
|
3187
|
+
interface UseLessonCommentsOptions {
|
|
3188
|
+
enabled?: boolean;
|
|
3189
|
+
/** 1-based page of top-level comments (newest first). Default 1. */
|
|
3190
|
+
page?: number;
|
|
3191
|
+
}
|
|
3192
|
+
/**
|
|
3193
|
+
* Lesson discussion: paginated top-level comments (newest first) with one
|
|
3194
|
+
* level of replies, plus `postComment` / `deleteComment` mutations. Render
|
|
3195
|
+
* the widget only when `enabled` is true (the merchant can turn the
|
|
3196
|
+
* discussion off). Only enrolled customers with the lesson unlocked.
|
|
3197
|
+
*/
|
|
3198
|
+
declare function useLessonComments(courseId: string | null, lessonId: string | null, options?: UseLessonCommentsOptions): {
|
|
3199
|
+
comments: CourseComment[];
|
|
3200
|
+
totalCount: number;
|
|
3201
|
+
page: number;
|
|
3202
|
+
pageSize: number;
|
|
3203
|
+
/** False when the merchant disabled the discussion — hide the widget. */
|
|
3204
|
+
enabled: boolean;
|
|
3205
|
+
isLoading: boolean;
|
|
3206
|
+
error: Error | null;
|
|
3207
|
+
refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<CourseCommentsList>, Error>>;
|
|
3208
|
+
postComment: (body: string, parentId?: string) => Promise<CoursePostedComment>;
|
|
3209
|
+
isPosting: boolean;
|
|
3210
|
+
deleteComment: (commentId: string) => Promise<void>;
|
|
3211
|
+
isDeleting: boolean;
|
|
3212
|
+
};
|
|
3213
|
+
|
|
3214
|
+
interface UseLessonNoteOptions {
|
|
3215
|
+
enabled?: boolean;
|
|
3216
|
+
}
|
|
3217
|
+
/**
|
|
3218
|
+
* The student's private note for one lesson (autosave textarea). `body` is
|
|
3219
|
+
* an empty string until the student writes something; `save` upserts and an
|
|
3220
|
+
* empty string clears the note. Visible only to the logged-in student.
|
|
3221
|
+
*/
|
|
3222
|
+
declare function useLessonNote(courseId: string | null, lessonId: string | null, options?: UseLessonNoteOptions): {
|
|
3223
|
+
note: NoInfer<LessonNote> | null;
|
|
3224
|
+
body: string;
|
|
3225
|
+
updatedAt: number | null;
|
|
3226
|
+
isLoading: boolean;
|
|
3227
|
+
error: Error | null;
|
|
3228
|
+
refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<NoInfer<LessonNote>, Error>>;
|
|
3229
|
+
save: (body: string) => Promise<LessonNote>;
|
|
3230
|
+
isSaving: boolean;
|
|
3231
|
+
saveError: Error | null;
|
|
3232
|
+
};
|
|
3233
|
+
|
|
335
3234
|
interface UseSubscriptionsOptions {
|
|
336
3235
|
enabled?: boolean;
|
|
337
3236
|
}
|
|
@@ -1293,4 +4192,127 @@ declare function useNotifyWhenAvailable(): _tanstack_react_query.UseMutationResu
|
|
|
1293
4192
|
*/
|
|
1294
4193
|
declare function useBehioClient(): BehioStorefront;
|
|
1295
4194
|
|
|
1296
|
-
|
|
4195
|
+
/**
|
|
4196
|
+
* Format a price amount with currency using Intl.NumberFormat.
|
|
4197
|
+
*
|
|
4198
|
+
* @param amount - The price amount (e.g. 1499, 24.99)
|
|
4199
|
+
* @param currency - ISO 4217 currency code (e.g. "CZK", "EUR", "USD")
|
|
4200
|
+
* @param locale - BCP 47 locale string (e.g. "cs", "en", "de"). Defaults to "cs".
|
|
4201
|
+
* @returns Formatted price string (e.g. "1 499 Kč", "24,99 €")
|
|
4202
|
+
*/
|
|
4203
|
+
declare function formatPrice(amount: number, currency: string, locale?: string): string;
|
|
4204
|
+
|
|
4205
|
+
/**
|
|
4206
|
+
* GA4 e-commerce event helper.
|
|
4207
|
+
*
|
|
4208
|
+
* Fires standard GA4 ecommerce/engagement events (view_item, add_to_cart,
|
|
4209
|
+
* begin_checkout, purchase, search, ...) into whatever analytics runtime the
|
|
4210
|
+
* shop has injected via `<StorefrontScripts/>`, and — crucially — into Behio
|
|
4211
|
+
* Analytics via the sink the tracker registers. One call, both systems.
|
|
4212
|
+
*
|
|
4213
|
+
* Sinks:
|
|
4214
|
+
* - Behio Analytics (`__behioEcommerceSink`) — always, when the tracker is
|
|
4215
|
+
* mounted. Records the ORIGINAL event name so Behio-exclusive signals
|
|
4216
|
+
* (variant_selected, newsletter_signup) stay distinct.
|
|
4217
|
+
* - direct GA4 (`gtag` present) -> `gtag("event", name, payload)`
|
|
4218
|
+
* - GTM (`dataLayer` array present) -> `dataLayer.push({event, ecommerce})`
|
|
4219
|
+
* (with the recommended `ecommerce: null` reset push first)
|
|
4220
|
+
* - neither present (no analytics configured, or consent not granted yet so
|
|
4221
|
+
* the consent-gated script never loaded) -> silent no-op for the GA path
|
|
4222
|
+
*
|
|
4223
|
+
* Behio-only signal names that have a GA4 recommended equivalent are remapped
|
|
4224
|
+
* for the GA path only (see `GA4_NAME_MAP`), so merchants keep clean GA4
|
|
4225
|
+
* reports while Behio keeps the richer signal.
|
|
4226
|
+
*
|
|
4227
|
+
* Consent stays the script layer's job: this helper never loads anything, it
|
|
4228
|
+
* only talks to runtimes that already exist on the page.
|
|
4229
|
+
*/
|
|
4230
|
+
type EcommerceEventName = "view_item" | "view_item_list" | "select_item" | "add_to_cart" | "remove_from_cart" | "view_cart" | "add_to_wishlist" | "view_promotion" | "select_promotion" | "begin_checkout" | "add_payment_info" | "add_shipping_info" | "search" | "generate_lead" | "purchase" | "variant_selected" | "newsletter_signup";
|
|
4231
|
+
type EcommerceItem = {
|
|
4232
|
+
item_id: string;
|
|
4233
|
+
item_name: string;
|
|
4234
|
+
price?: number;
|
|
4235
|
+
quantity?: number;
|
|
4236
|
+
item_variant?: string;
|
|
4237
|
+
item_category?: string;
|
|
4238
|
+
/** Position in the list (1-based) — for select_item rail/list attribution. */
|
|
4239
|
+
index?: number;
|
|
4240
|
+
};
|
|
4241
|
+
type EcommercePayload = {
|
|
4242
|
+
currency?: string;
|
|
4243
|
+
/** Order / cart total in `currency`. */
|
|
4244
|
+
value?: number;
|
|
4245
|
+
/** Required for `purchase` — the order number. */
|
|
4246
|
+
transaction_id?: string;
|
|
4247
|
+
shipping?: number;
|
|
4248
|
+
/** Optional for non-item events (search, add_shipping_info, newsletter). */
|
|
4249
|
+
items?: EcommerceItem[];
|
|
4250
|
+
/** search event: the query string. */
|
|
4251
|
+
search_term?: string;
|
|
4252
|
+
/** add_shipping_info: the selected shipping method label. */
|
|
4253
|
+
shipping_tier?: string;
|
|
4254
|
+
/** add_payment_info: the selected payment method type. */
|
|
4255
|
+
payment_type?: string;
|
|
4256
|
+
/** view_item_list / select_item: the list id (shop|category|search|rail:*). */
|
|
4257
|
+
item_list_id?: string;
|
|
4258
|
+
/** view_item_list / select_item: human-readable list name. */
|
|
4259
|
+
item_list_name?: string;
|
|
4260
|
+
/**
|
|
4261
|
+
* Behio-only extra props forwarded verbatim into the Behio event `props`
|
|
4262
|
+
* (ignored by GA4). Use for signals GA4 can't model: resultsCount,
|
|
4263
|
+
* zeroResults, variantId, listId, position, source, ...
|
|
4264
|
+
*/
|
|
4265
|
+
props?: Record<string, unknown>;
|
|
4266
|
+
};
|
|
4267
|
+
declare function trackEcommerceEvent(event: EcommerceEventName, payload: EcommercePayload): void;
|
|
4268
|
+
|
|
4269
|
+
/**
|
|
4270
|
+
* Consent-gated visitor identity helpers.
|
|
4271
|
+
*
|
|
4272
|
+
* Behio Analytics has three identity tiers (see BehioAnalyticsTracker):
|
|
4273
|
+
* anonymous (cookieless server hash), consented (persistent behio_visitor_id),
|
|
4274
|
+
* and customer-linked (server stitches at checkout/login). The persistent
|
|
4275
|
+
* `behio_visitor_id` is what unlocks returning-visitor metrics, the customer
|
|
4276
|
+
* journey and Smart Offers.
|
|
4277
|
+
*
|
|
4278
|
+
* Historically the SDK only READ that id and left generation/writing to each
|
|
4279
|
+
* shop's consent banner — so any storefront that forgot the write stayed 100%
|
|
4280
|
+
* anonymous. These helpers move the write into the SDK: the consent banner just
|
|
4281
|
+
* calls `grantAnalyticsConsent(client)` / `revokeAnalyticsConsent(client)` and
|
|
4282
|
+
* everything (id generation, storage, server record, tracker refresh) is
|
|
4283
|
+
* handled here, identically for every template and AI-generated shop.
|
|
4284
|
+
*/
|
|
4285
|
+
|
|
4286
|
+
/** Read the persistent visitor id (localStorage first, cookie fallback for SSR-set ids). */
|
|
4287
|
+
declare function getStoredVisitorId(): string | null;
|
|
4288
|
+
/**
|
|
4289
|
+
* Generate a fresh, URL-safe visitor id in the range the ingest DTO accepts
|
|
4290
|
+
* (8..64 chars, [A-Za-z0-9_-]). Uses crypto when available, falling back to
|
|
4291
|
+
* Math.random so it never throws in a locked-down runtime.
|
|
4292
|
+
*/
|
|
4293
|
+
declare function generateVisitorId(): string;
|
|
4294
|
+
/**
|
|
4295
|
+
* Grant analytics consent: ensure a persistent `behio_visitor_id` exists, store
|
|
4296
|
+
* it, record the consent server-side, wire the id into the client (so orders /
|
|
4297
|
+
* logins can be attributed) and notify the tracker to start sending it.
|
|
4298
|
+
*
|
|
4299
|
+
* Returns the visitor id (or an SdkResult error if the server record failed —
|
|
4300
|
+
* the id is still stored locally so tracking works and can retry later).
|
|
4301
|
+
*
|
|
4302
|
+
* @param categories optional marketing/preferences flags (default false); the
|
|
4303
|
+
* analytics flag is always true here.
|
|
4304
|
+
*/
|
|
4305
|
+
declare function grantAnalyticsConsent(client: BehioStorefront, categories?: {
|
|
4306
|
+
marketing?: boolean;
|
|
4307
|
+
preferences?: boolean;
|
|
4308
|
+
}): Promise<SdkResult<CookieConsent>>;
|
|
4309
|
+
/**
|
|
4310
|
+
* Revoke analytics consent: tell the server, stop sending the id and notify the
|
|
4311
|
+
* tracker. The stored id is kept (consent record now says analytics=false) so a
|
|
4312
|
+
* later re-grant reuses the same visitor rather than fragmenting the journey.
|
|
4313
|
+
*/
|
|
4314
|
+
declare function revokeAnalyticsConsent(client: BehioStorefront): Promise<SdkResult<{
|
|
4315
|
+
success: boolean;
|
|
4316
|
+
}>>;
|
|
4317
|
+
|
|
4318
|
+
export { type ActivePromotion, type AddToCartInput, type AnalyticsEventInput, type AuthTokens, BehioAnalyticsTracker, BehioApiError, BehioProvider, type BehioProviderProps, type Bundle, type BundleItem, type Cart, type CartDiscount, type CartItem, type Category, type CategoryDetail, type CheckoutAddress, type CheckoutInput, type CookieConsent, type CookieConsentInput, type CrossSellItem, CurrencySwitcher, type CurrencySwitcherProps, type CurrencySwitcherRenderProps, type CustomerAddress, type CustomerProfile, type EcommerceEventName, type EcommerceItem, type EcommercePayload, type FilterField, type FulfillmentStatus, type GiftCardBalance, type LoginInput, type MessageResponse, type OrderDetail, type OrderItem, type OrderListItem, type OrderStatus, type Page, type PageDetail, type PaginatedResponse, type PaymentStatus, type PersonalOffer, type ProductDetail, type ProductLabel, type ProductListItem, type ProductPrice, type ProductReview, type ProductReviewsResponse, type ProductVariant, type ProductsQuery, type QuoteRequest, type RegisterInput, type ReturnRequest, type ShopInfo, type ShopSeo, type StorageAdapter, StorefrontScripts, type StorefrontScriptsProps, type SubmitQuoteInput, type SubmitReturnInput, type SubmitReviewInput, type UseAddressAutocompleteOptions, type UseAddressAutocompleteReturn, type UseAddressesOptions, type UseCartCountOptions, type UseCartOptions, type UseCategoriesOptions, type UseCategoryOptions, type UseCertificateVerificationOptions, type UseCourseCertificatesOptions, type UseCourseOptions, type UseCoursesOptions, type UseCurrencyResult, type UseCustomerOptions, type UseFacetsOptions, type UseFeaturedOptions, type UseFiltersOptions, type UseLabelsOptions, type UseLessonCommentsOptions, type UseLessonNoteOptions, type UseLessonQuizOptions, type UseLessonTutorOptions, type UseLoyaltyOptions, type UseMenuOptions, type UseOrderOptions, type UseOrdersOptions, type UsePageOptions, type UsePagesOptions, type UsePaymentMethodsOptions, type UsePersonalOffersOptions, type UseProductOptions, type UseProductsOptions, type UseSearchOptions, type UseShippingMethodsOptions, type UseShippingQuoteOptions, type UseShopInfoOptions, type UseShopScriptsOptions, type UseShopSeoOptions, type UseSubscriptionsOptions, type WishlistItem, cookieStorage, createMemoryStorage, detectStorage, formatPrice, generateVisitorId, getStoredVisitorId, grantAnalyticsConsent, localStorageAdapter, memoryStorage, revokeAnalyticsConsent, trackEcommerceEvent, useAddressAutocomplete, useAddresses, useAnalyticsEvents, useAuth, useBehio, useBehioClient, useBundle, useBundles, useCart, useCartCount, useCategories, useCategory, useCertificateVerification, useCheckout, useCookieConsent, useCourse, useCourseCertificates, useCourses, useCrossSell, useCurrency, useCustomer, useFacets, useFeatured, useFilters, useGiftCardBalance, useIsInWishlist, useLabels, useLessonComments, useLessonNote, useLessonQuiz, useLessonTutor, useLookupReturnableOrder, useLoyalty, useMenu, useNewsletterSubscribe, useNewsletterUnsubscribe, useNotifyWhenAvailable, useOrder, useOrderAccess, useOrders, usePage, usePages, usePaymentMethods, usePersonalOffers, usePickupPoints, useProduct, useProductGroup, useProductPromotions, useProductReviews, useProducts, useQuoteStatus, useReturnStatus, useSearch, useShippingMethods, useShippingQuote, useShopInfo, useShopScripts, useShopSeo, useSubmitQuote, useSubmitReturn, useSubmitReview, useSubscriptions, useWishlist };
|