@estoreclub/api 0.0.0-stage → 0.1.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.
Files changed (58) hide show
  1. package/dist/bridgeClient.d.ts +10 -0
  2. package/dist/bridgeClient.js +10 -0
  3. package/dist/bridgeClient.js.map +7 -0
  4. package/dist/chunks/chunk-2554RPSS.js +45 -0
  5. package/dist/chunks/chunk-2554RPSS.js.map +7 -0
  6. package/dist/chunks/chunk-2BH4QPV2.js +27 -0
  7. package/dist/chunks/chunk-2BH4QPV2.js.map +7 -0
  8. package/dist/chunks/chunk-3KEEGSMP.js +86 -0
  9. package/dist/chunks/chunk-3KEEGSMP.js.map +7 -0
  10. package/dist/chunks/chunk-5DN7L6LX.js +861 -0
  11. package/dist/chunks/chunk-5DN7L6LX.js.map +7 -0
  12. package/dist/chunks/chunk-DUVULZ6N.js +111 -0
  13. package/dist/chunks/chunk-DUVULZ6N.js.map +7 -0
  14. package/dist/chunks/chunk-GJZ7EZEF.js +25 -0
  15. package/dist/chunks/chunk-GJZ7EZEF.js.map +7 -0
  16. package/dist/chunks/chunk-HFEQWXG6.js +24 -0
  17. package/dist/chunks/chunk-HFEQWXG6.js.map +7 -0
  18. package/dist/chunks/chunk-OFFTL6RC.js +24 -0
  19. package/dist/chunks/chunk-OFFTL6RC.js.map +7 -0
  20. package/dist/chunks/chunk-TSERNR4R.js +15 -0
  21. package/dist/chunks/chunk-TSERNR4R.js.map +7 -0
  22. package/dist/chunks/chunk-ZITPZDI7.js +280 -0
  23. package/dist/chunks/chunk-ZITPZDI7.js.map +7 -0
  24. package/dist/client.d.ts +407 -0
  25. package/dist/client.js +14 -0
  26. package/dist/client.js.map +7 -0
  27. package/dist/companyApiKey.d.ts +9 -0
  28. package/dist/companyApiKey.js +9 -0
  29. package/dist/companyApiKey.js.map +7 -0
  30. package/dist/customerToken.d.ts +18 -0
  31. package/dist/customerToken.js +11 -0
  32. package/dist/customerToken.js.map +7 -0
  33. package/dist/errors.d.ts +41 -0
  34. package/dist/errors.js +9 -0
  35. package/dist/errors.js.map +7 -0
  36. package/dist/index.d.ts +82 -0
  37. package/dist/index.js +166 -0
  38. package/dist/index.js.map +7 -0
  39. package/dist/language.d.ts +27 -0
  40. package/dist/language.js +11 -0
  41. package/dist/language.js.map +7 -0
  42. package/dist/params.d.ts +58 -0
  43. package/dist/params.js +27 -0
  44. package/dist/params.js.map +7 -0
  45. package/dist/requestCache.d.ts +46 -0
  46. package/dist/requestCache.js +9 -0
  47. package/dist/requestCache.js.map +7 -0
  48. package/dist/siteData.d.ts +237 -0
  49. package/dist/siteData.js +132 -0
  50. package/dist/siteData.js.map +7 -0
  51. package/dist/types.d.ts +2123 -0
  52. package/dist/types.js +1 -0
  53. package/dist/types.js.map +7 -0
  54. package/dist/visitorCountry.d.ts +25 -0
  55. package/dist/visitorCountry.js +15 -0
  56. package/dist/visitorCountry.js.map +7 -0
  57. package/package.json +64 -4
  58. package/README.md +0 -3
@@ -0,0 +1,2123 @@
1
+ /**
2
+ * What the public API answers with.
3
+ *
4
+ * These mirror the server's DTOs (`companyResponse.dto.ts`,
5
+ * `productCategoryWithTranslations.dto.ts`, `productWithTranslations.dto.ts`) and stop at the
6
+ * fields a site actually renders. Optional means the API marks it optional — a product with
7
+ * no price or no photo is ordinary, and the caller has to handle it.
8
+ */
9
+ /**
10
+ * Which dataset version a record belongs to, as the API reports it (`PublicCart.workspace`).
11
+ *
12
+ * The public API serves only `production`, what visitors see, so no client asks for one: there
13
+ * is no workspace parameter to send.
14
+ */
15
+ export type Workspace = "production" | "sandbox";
16
+ export interface PublicLanguage {
17
+ code: string;
18
+ codeLocal: string;
19
+ name: string;
20
+ }
21
+ /**
22
+ * The shop's terms and privacy policy, for a customer asked to accept them (`getTerms`).
23
+ */
24
+ export interface PublicTerms {
25
+ /**
26
+ * Whether customers must accept them (the shop's Terms & privacy rule). While true, a
27
+ * signed-in customer who has not accepted cannot order or book (`customer_terms_required`)
28
+ * until they do - `updateCustomerProfile({ acceptTerms: true })`.
29
+ */
30
+ required: boolean;
31
+ /**
32
+ * The text the shop wrote, Markdown, in the visitor's language - else the shop's default
33
+ * language's. Null: none written; link `termsUrl` / `privacyUrl` instead. Render it as
34
+ * Markdown WITHOUT raw HTML.
35
+ */
36
+ markdown: string | null;
37
+ /** The language `markdown` is in; null with it. */
38
+ language: string | null;
39
+ /** When the text last changed (ISO); null with it. */
40
+ updatedAt: string | null;
41
+ /** The shop's terms address; empty: the site's own `/terms` page, or `markdown` in place. */
42
+ termsUrl: string;
43
+ /** The shop's privacy policy address; empty: the site's `/privacy`, or `markdown` in place. */
44
+ privacyUrl: string;
45
+ }
46
+ /**
47
+ * One of the shop's physical locations — a restaurant, a pickup point — for a "find us" section
48
+ * or a map. The address is the one Google verified when the shop entered it, so `latitude` /
49
+ * `longitude` and `placeId` always describe the same place as `address`.
50
+ */
51
+ export interface PublicStoreLocation {
52
+ id: string;
53
+ /**
54
+ * The shop's own number for the location (`2`). Use it in your site's addresses
55
+ * (`/book?location=2`) - every `locationId` the API takes accepts it as well as `id`.
56
+ */
57
+ number: number;
58
+ name: string;
59
+ /** Free text the shop wrote: how to find the entrance, parking. Empty when none. */
60
+ description: string;
61
+ /** ISO 3166-1 alpha-2, e.g. `"NZ"`. Null on a location saved before countries were asked. */
62
+ countryCode: string | null;
63
+ /** The city, as Google names it — e.g. `"Auckland"`. */
64
+ city: string | null;
65
+ cityPlaceId: string | null;
66
+ /** Postcode, e.g. `"1011"`. Null when none was given. */
67
+ postalCode: string | null;
68
+ /** As the shop writes it, e.g. `"+64 9 123 4567"` — for a `tel:` link, strip the spaces. */
69
+ phone: string | null;
70
+ /** The location's own contact address — for a `mailto:` link. */
71
+ email: string | null;
72
+ /**
73
+ * When it is open, sorted by day: ISO weekday (1 = Monday … 7 = Sunday) and `HH:MM` times on
74
+ * the shop's clock; an `until` not after `from` runs past midnight. A weekday with no range is
75
+ * CLOSED. `null` means the shop gave no hours — print nothing rather than "closed".
76
+ */
77
+ workingHours: Array<{
78
+ day: number;
79
+ from: string;
80
+ until: string;
81
+ }> | null;
82
+ /**
83
+ * The street part only — "120 Ponsonby Road, Grey Lynn". The city and country are `city` and
84
+ * `countryCode`; print them after it for a full line.
85
+ */
86
+ address: string;
87
+ /** Google Place ID — for a "directions" link: `https://www.google.com/maps/place/?q=place_id:<placeId>`. */
88
+ placeId: string;
89
+ latitude: number;
90
+ longitude: number;
91
+ /** Its pictures, in the shop's order — the first is the one to show in a list. */
92
+ images: Array<{
93
+ mediaId: string;
94
+ url: string;
95
+ isExternal: boolean;
96
+ }>;
97
+ /**
98
+ * The days ahead (90) on which other hours hold than `workingHours` — Christmas closed, a late
99
+ * New Year's Eve — the location's own over the shop's, by date. `kind: "hours"` replaces that
100
+ * day's opening hours, `"delivery"` its delivery hours; `hours` empty is CLOSED. Orders,
101
+ * pickup, delivery and bookings already follow them: these are for the page to SHOW ("Closed
102
+ * on 25 December"), and for "open now" on such a day, read them before `workingHours`.
103
+ */
104
+ specialDays: Array<{
105
+ date: string;
106
+ kind: "hours" | "delivery";
107
+ hours: Array<{
108
+ from: string;
109
+ until: string;
110
+ }>;
111
+ note: string;
112
+ }>;
113
+ }
114
+ /**
115
+ * What the platform knows of a picture the site holds only as a URL — see `lookupImages`. The
116
+ * fields `Image` from `@estoreclub/client` draws a `srcset` from.
117
+ */
118
+ export interface PublicImage {
119
+ url: string;
120
+ width: number | null;
121
+ height: number | null;
122
+ /** Widths (px) of the resized WebP copies stored beside it, as `<name>@<width>.webp`. */
123
+ variants: number[];
124
+ }
125
+ export interface PublicMedia {
126
+ id: string;
127
+ url: string;
128
+ type: string;
129
+ description?: string;
130
+ /** The original's size in pixels. Set once the resized copies are made; absent until then. */
131
+ width?: number | null;
132
+ height?: number | null;
133
+ /**
134
+ * Widths (px) of the resized WebP copies stored beside the original as
135
+ * `<name>@<width>.webp`. Empty until they are made, and always for external or SVG media —
136
+ * render it with `Image` from `@estoreclub/client`, which falls back to `url`.
137
+ */
138
+ variants?: number[] | null;
139
+ }
140
+ /** A company, as `GET public/company` returns it. The API never includes its key. */
141
+ /** Which side of the amount a currency's symbol sits on. */
142
+ export type CurrencySymbolPosition = "prefix" | "suffix";
143
+ export interface PublicCompany {
144
+ name: string;
145
+ defaultLanguage: string;
146
+ /** ISO 4217 code every product of this company is priced in. */
147
+ defaultCurrency?: string;
148
+ /** ISO 3166-1 alpha-2 country the shop trades in, null until it is set. */
149
+ countryCode?: string | null;
150
+ /** "₽", "$", or the code itself where a currency has no distinct sign. */
151
+ currencySymbol?: string;
152
+ /** Where that symbol goes. See `PublicSiteInfo.currencySymbolPosition`. */
153
+ currencySymbolPosition?: CurrencySymbolPosition;
154
+ /** Sales tax rate in percent; 0 for none. */
155
+ taxRate?: number;
156
+ /** Whether product prices already include the tax. */
157
+ taxInclusive?: boolean;
158
+ /** What the tax is called where the shop trades — GST, VAT, Sales tax. */
159
+ taxName?: string;
160
+ /** Whether an order names its location: never asked, the customer's choice, or a must. */
161
+ orderLocation?: OrderLocationMode;
162
+ /** How customers may receive an order, in the order offered. */
163
+ orderTypes?: OrderType[];
164
+ /** How bookings run: `off` (none), a whole table, seats at a shared table, or a time only. */
165
+ reservationMode?: "off" | "table" | "seat" | "time";
166
+ /** What a guest may book, the main way first - see `SiteInfo.reservationKinds`. */
167
+ reservationKinds?: ReservationKind[];
168
+ /** The ways visitors may sign in - signing in is always offered. */
169
+ customerSignInMethods?: {
170
+ email: boolean;
171
+ google: boolean;
172
+ apple?: boolean;
173
+ };
174
+ /** Who sees the site: everybody, or signed-in customers only. */
175
+ customerAccess?: CustomerAccess;
176
+ /** Only a signed-in customer may book a table online. */
177
+ reservationRequiresSignIn?: boolean;
178
+ /** What a reservation may be booked for - see `PublicSiteInfo.reservationOrder`. */
179
+ reservationOrder?: "off" | "any" | "list";
180
+ /** How a booking may be paid when it is made - see `PublicSiteInfo.reservationPayment`. */
181
+ reservationPayment?: PublicReservationPayment;
182
+ /** Only a signed-in customer may order online. */
183
+ orderRequiresSignIn?: boolean;
184
+ /** A guest may track a delivered order by its tracking number and email. */
185
+ publicOrderTracking?: boolean;
186
+ /** Money off for paying one way — see `PublicSiteInfo`. */
187
+ paymentDiscounts?: PublicPaymentDiscounts;
188
+ /** The Google client id for the site's Google sign-in button. */
189
+ googleClientId?: string | null;
190
+ /** The platform's Google sign-in page, opened in a popup — see `PublicSiteInfo`. */
191
+ googleSignInUrl?: string | null;
192
+ /** The Apple Services ID for the site's Apple sign-in — see `PublicSiteInfo`. */
193
+ appleClientId?: string | null;
194
+ /** The platform's Apple sign-in page, opened in a popup — see `PublicSiteInfo`. */
195
+ appleSignInUrl?: string | null;
196
+ settings?: Record<string, string>;
197
+ languages: PublicLanguage[];
198
+ }
199
+ /** The company as a *site*: the shape a page asks for by `getSiteInfo()`. */
200
+ export interface PublicSiteInfo {
201
+ siteName: string;
202
+ defaultLanguage: string;
203
+ languages: PublicLanguage[];
204
+ /**
205
+ * ISO 4217, the code every price on this site is in.
206
+ *
207
+ * A product carries an amount and no currency — the company's is the currency — so a page
208
+ * showing a price without this one is guessing, and the guess is always "$".
209
+ */
210
+ currency?: string;
211
+ /**
212
+ * ISO 3166-1 alpha-2 country the shop trades in ("NZ"), null until it is set. A visitor from
213
+ * there reads the shop's own dollar as a bare "$"; anyone else is told whose dollar it is
214
+ * ("NZ$1.10"), and a dollar not the shop's always carries its code ("USD$1.10").
215
+ */
216
+ countryCode?: string | null;
217
+ /**
218
+ * The country the visitor reading this page is in ("NZ"), from their request - null when it
219
+ * is not known (a static build, a browser that names no region). With `countryCode`: a visitor
220
+ * at home reads the shop's dollar as "$1.10", anyone else "NZ$1.10".
221
+ */
222
+ visitorCountry?: string | null;
223
+ /** The sign to print beside an amount: "₽", "$", or the code where there is no sign. */
224
+ currencySymbol?: string;
225
+ /**
226
+ * Which side of the number that sign goes on, and it is a property of the CURRENCY rather
227
+ * than of the reader: the ruble trails ("1 000 ₽") and the dollar leads ("$1,000") whatever
228
+ * language the page is written in. `Intl` answers the other question — how an ENGLISH page
229
+ * writes a ruble — which is why this comes from the server instead.
230
+ *
231
+ * A trailing symbol is written with a space before it, a leading one without.
232
+ */
233
+ currencySymbolPosition?: CurrencySymbolPosition;
234
+ /**
235
+ * The sales tax rate in percent (0: none), and whether the prices on this site already
236
+ * include it — for "Prices include 15% GST" on a page, before anything is in a basket.
237
+ */
238
+ taxRate?: number;
239
+ taxInclusive?: boolean;
240
+ /** What the tax is called where the shop trades — GST, VAT, Sales tax. */
241
+ taxName?: string;
242
+ /**
243
+ * Whether to ask which location an order is for (`getLocations`): `never` - show no picker
244
+ * (a `locationId` sent anyway is not kept); `optional` - offer one; `required` - ask first:
245
+ * `createCheckout` without a `locationId` is refused.
246
+ */
247
+ orderLocation: OrderLocationMode;
248
+ /**
249
+ * How customers may receive an order, in the order the shop offers them: `pickup` (takeaway),
250
+ * `reservation` and/or `delivery`. The hosted payment page asks when there is more than one (and,
251
+ * for delivery, takes the address and adds the fee); a page may also ask in the cart and pass
252
+ * the choice as `createCheckout({ orderType })`.
253
+ */
254
+ orderTypes: OrderType[];
255
+ /**
256
+ * How guests book online (`getBookingSlots`, `createBooking`): `off` - no booking, hide any
257
+ * "Book" link; `table` a whole table; `seat` seats at a shared table; `time` a time only (no
258
+ * table, no plan).
259
+ */
260
+ reservationMode?: "off" | "table" | "seat" | "time";
261
+ /**
262
+ * What a guest may book - `table`, `list` (an entry of the shop's list: a specialist, a room),
263
+ * `time` alone - the shop's main way first, the one `reservationMode` describes. With more than
264
+ * one, let the guest pick and pass it as `kind` to `getBookingSlots`, `getBookingPlan` and
265
+ * `createBooking`. Empty while reservations are off.
266
+ */
267
+ reservationKinds: ReservationKind[];
268
+ /**
269
+ * @deprecated `reservationMode !== "off"` - worked out here for sites written before; the
270
+ * server no longer sends it.
271
+ */
272
+ tableReservations?: boolean;
273
+ /**
274
+ * @deprecated Always true: signing in is always offered (`customerSignInMethods` says how).
275
+ * Kept for sites written before; the server no longer sends it.
276
+ */
277
+ customerSignIn?: boolean;
278
+ /**
279
+ * Which ways to offer: `email` (`requestSignInCode` +
280
+ * `verifySignInCode`), `google` (`signInWithGoogle`) and `apple` (`signInWithApple`). A way
281
+ * that is off is refused.
282
+ */
283
+ customerSignInMethods: {
284
+ email: boolean;
285
+ google: boolean;
286
+ apple: boolean;
287
+ };
288
+ /**
289
+ * Who sees the site. `public`: everybody. `signed_in`: signed-in customers only - the
290
+ * catalogue, cart, checkout and bookings refuse a guest (`PublicApiError` 401, code
291
+ * `customer_sign_in_required`), so show the sign-in instead of the menu.
292
+ */
293
+ customerAccess: CustomerAccess;
294
+ /**
295
+ * Only a signed-in customer may book a table: `createBooking` rejects a guest (401). Ask them
296
+ * to sign in before the booking form.
297
+ */
298
+ reservationRequiresSignIn: boolean;
299
+ /**
300
+ * What a reservation may be booked for: `off` nothing; `any` any product; `list` only the
301
+ * products the booked entry allows (each entry `getBookingSlots` offers lists its
302
+ * `productIds`).
303
+ *
304
+ * The booking window, the per-customer limit, a payment due at booking and the cancellation
305
+ * notice are the server's to apply and are not published here: `getBookingSlots` marks times
306
+ * outside the window unavailable and says `cancelHours`; `createBooking` refuses what the
307
+ * rules refuse (and answers `pending` with `payment` when the booking is paid for up front);
308
+ * each of the customer's bookings says `cancellableUntil`.
309
+ */
310
+ reservationOrder?: "off" | "any" | "list";
311
+ /**
312
+ * How a booking's order may be paid when it is made: `order` - charged at once; `deferred` -
313
+ * the card held and charged when the shop accepts the booking. Both: let the guest choose and
314
+ * send it as `payment` to `createBooking`. Neither: paid at the visit.
315
+ */
316
+ reservationPayment: PublicReservationPayment;
317
+ /**
318
+ * Only a signed-in customer may order: `createCheckout` rejects a guest (401, "Sign in to place
319
+ * an order"). Sign them in when they go to pay, then check out.
320
+ */
321
+ orderRequiresSignIn: boolean;
322
+ /**
323
+ * A guest may follow a delivered order on the tracking page: `trackOrder({ code, email })` -
324
+ * the delivery's tracking number (`K7P-QX9-M2T`, in the order's emails) and the order's email.
325
+ * False: offer signing in instead (the account lists every order); `trackOrder` by number
326
+ * refuses.
327
+ */
328
+ publicOrderTracking: boolean;
329
+ /**
330
+ * Money off for paying one way — `online` by card at checkout, `inStore` at the counter — or
331
+ * null for none. For the basket to SAY ("Save 10% paying online"): the customer chooses how to
332
+ * pay on the checkout page, which takes it off then; the basket's own total is before it.
333
+ */
334
+ paymentDiscounts: PublicPaymentDiscounts;
335
+ /**
336
+ * The client id to render Google's sign-in button with (Google Identity Services). Null: Google
337
+ * sign-in is not configured on the platform — offer no Google button.
338
+ */
339
+ googleClientId: string | null;
340
+ /**
341
+ * The platform's Google sign-in page. A site opens it in a popup (`?origin=<site origin>`) and
342
+ * receives `{ type: "salespoint:google-credential", credential }` by `postMessage` — Google's
343
+ * button is drawn there, on the one origin registered with Google, not on every site's. Null:
344
+ * offer no Google button.
345
+ */
346
+ googleSignInUrl: string | null;
347
+ /**
348
+ * The Apple Services ID the platform's Apple sign-in page signs in with. Null: Apple sign-in is
349
+ * not configured on the platform — offer no Apple button.
350
+ */
351
+ appleClientId: string | null;
352
+ /**
353
+ * The platform's Apple sign-in page. A site opens it in a popup (`?origin=<site origin>`, and
354
+ * `client=<appleClientId>`) and receives `{ type: "salespoint:apple-credential", credential,
355
+ * name }` by `postMessage` — pass both to `signInWithApple`. `name` is "First Last" on the
356
+ * first sign-in only (Apple sends it once), else null. Null: offer no Apple button.
357
+ */
358
+ appleSignInUrl: string | null;
359
+ settings?: Record<string, string>;
360
+ }
361
+ /**
362
+ * A category. Only active ones are ever returned, so there is no `status`; the list comes
363
+ * back already in the author's order, so there is no `order` either.
364
+ *
365
+ * The optional parts are there only when asked for through `include` — which this client
366
+ * does by default, see `PublicCategoryInclude`.
367
+ */
368
+ export interface PublicCategory {
369
+ id: string;
370
+ name: string;
371
+ /**
372
+ * The name the shop gave it, untranslated - the same in every language (`name` is in the
373
+ * page's). For links and anchors that must not change with the language. Absent from an
374
+ * API older than it.
375
+ */
376
+ canonicalName?: string;
377
+ description?: string;
378
+ /** The parent category's id, or `null` for a root. A shop may have several roots. */
379
+ parentId: string | null;
380
+ createdAt?: string;
381
+ updatedAt?: string;
382
+ /** With `include: ["media"]`. */
383
+ media?: PublicMedia[];
384
+ /** With `include: ["count"]`: active products linked to this category. */
385
+ productCount?: number;
386
+ /** With `include: ["count"]`: active products here AND in every category beneath it. */
387
+ descendantProductCount?: number;
388
+ /** With `include: ["translations"]`: every enabled language, then field name. */
389
+ translations?: Record<string, Record<string, string>>;
390
+ }
391
+ /** One way a product is sold — see `PublicProduct.variants`. */
392
+ export interface PublicProductVariant {
393
+ id: string;
394
+ /** In the request language, falling back to the base name; `""` when the shop gave none. */
395
+ name: string;
396
+ /** What this variant costs: its own price, or the product's where it has none. A number, as
397
+ * `PublicProduct.price` is — this client converts it the same way. */
398
+ price?: number;
399
+ /** Whether it can be bought now. Show an unavailable one as sold out rather than hiding it. */
400
+ isAvailable: boolean;
401
+ order: number;
402
+ /** The variant's own first image, when it has one; otherwise use the product's. */
403
+ image?: string;
404
+ /** The variant-scoped settings, described like the product's: the variant's own value, or
405
+ * the product's where the variant has none. */
406
+ settings: Record<string, PublicProductSetting>;
407
+ }
408
+ /**
409
+ * The optional parts of a category. `count` is `productCount` + `descendantProductCount`.
410
+ *
411
+ * The API returns none of them unless asked. This client asks for ALL of them when a caller
412
+ * passes no `include`, so a page written before `include` existed renders as it did; pass a
413
+ * narrower list (or `[]`) to trim the response.
414
+ */
415
+ export type PublicCategoryInclude = "translations" | "media" | "count";
416
+ export interface PublicProductCategoryRef {
417
+ id: string;
418
+ name?: string;
419
+ }
420
+ /** What kind of value a product setting holds — and so, how a page renders it. */
421
+ export type PublicProductSettingType = "text" | "richtext" | "boolean" | "number" | "range"
422
+ /** A day, `"YYYY-MM-DD"`. */
423
+ | "date" | "dictionary" | "dictionary_multi";
424
+ /** A `range` value: where the product sits, and the scale it sits on. */
425
+ export interface PublicProductSettingRange {
426
+ value: number;
427
+ max: number;
428
+ }
429
+ /**
430
+ * One of a product's settings, described.
431
+ *
432
+ * The API used to answer a bare `{ KEY: value }` bag, which left a page guessing at all
433
+ * three things it needs: a `4` could be a count, a rating out of five or a number of
434
+ * minutes; a `"Large"` could be free text or one entry of a list the shop curates; and an
435
+ * absent key could mean "this shop does not use the field" or "nobody filled it in". None of
436
+ * those is answerable from a value, and a page cannot ask the catalogue — `getProductSettings`
437
+ * describes the SHOP, not this product.
438
+ */
439
+ export interface PublicProductSetting {
440
+ type: PublicProductSettingType;
441
+ /**
442
+ * What the product holds, or `""` when it holds nothing. The key is still there: a shop
443
+ * that shows a field nobody filled in renders differently from a shop without the field.
444
+ *
445
+ * `range` answers `{ value, max }`; `dictionary_multi` answers the entry NAMES, not ids.
446
+ */
447
+ value: string | number | boolean | string[] | PublicProductSettingRange | "";
448
+ /**
449
+ * `dictionary_multi` only: the entries of `value` the customer may not take off the product -
450
+ * an ingredient the dish is not made without. NAMES, as `value` holds them; absent when none.
451
+ * Show them kept and do not offer to leave them off: a line leaving one off is refused.
452
+ */
453
+ required?: string[];
454
+ /** The list the value is an entry of, as the shop writes it. Only on the two `dictionary`
455
+ * types — it is what tells one shop's "Size" (pizza sizes) from another's (bottle sizes).
456
+ * This is the one to PRINT; it is translated and reworded, so fetch with `listIdentifier`. */
457
+ listName?: string;
458
+ /**
459
+ * The same list by identifier — what to FETCH it with:
460
+ * `getDictionary({ identifier: setting.listIdentifier })`.
461
+ *
462
+ * The handle the shop gave the list. Unlike the name it does not move, so a page that reads
463
+ * a product's sizes or add-ons through it keeps working when the shop retitles the list or
464
+ * translates it. Absent on a list the shop has not given one, and on a list the shop keeps
465
+ * private (not "Visible on site") - there is nothing a page could fetch with it.
466
+ */
467
+ listIdentifier?: string;
468
+ }
469
+ /**
470
+ * One setting as the SHOP has it — the catalogue, not a product's value.
471
+ *
472
+ * `getProductSettings()` answers a list of these: what fields this shop keeps on its
473
+ * products, what kind of value each holds, and which of them it actually shows. A page uses
474
+ * it to lay out a form or a spec table before it has a product in hand; for one product's
475
+ * values, read `PublicProduct.settings`, which describes the same keys with values attached.
476
+ *
477
+ * Only the fields the shop has switched on AND lets websites read are listed. A disabled or
478
+ * private field (a SKU, a bar code, a cost) is not here, and its values never appear on a product.
479
+ */
480
+ export interface PublicProductSettingDefinition {
481
+ /** What the value is stored under — `IS_VEGETARIAN`, `SIZE`, `CUSTOM_ROAST`. */
482
+ key: string;
483
+ /** What to call it on the page — "Size", "Calories per serving (kcal)". */
484
+ label?: string;
485
+ type: PublicProductSettingType;
486
+ /** Section it is listed under, when the shop said. */
487
+ groupKey?: string;
488
+ /** Unit shown after the value, e.g. "g". Never on the list types. */
489
+ suffix?: string;
490
+ /** The list it draws from, on the two `dictionary` types. */
491
+ dictionaryId?: string;
492
+ /** What that list is called. Absent on a list nobody has named. */
493
+ listName?: string;
494
+ /** Top of the scale, on `range` only. */
495
+ rangeMax?: number;
496
+ }
497
+ export interface PublicProduct {
498
+ id: string;
499
+ /**
500
+ * The shop's own number for the product - link it as its key, `PR-12`
501
+ * (`/menu/PR-12`); `getProduct({ name: "PR-12" })` finds it by that key.
502
+ */
503
+ productNumber: number;
504
+ name: string;
505
+ description?: string;
506
+ story?: string;
507
+ /**
508
+ * Always a number here, and worth knowing why that is not free: the API answers with a
509
+ * STRING (`"13.00"`), because the column is a Postgres decimal. `@estoreclub/api` converts it
510
+ * so this type is true — anything reading the endpoint directly must do the same.
511
+ */
512
+ price?: number;
513
+ /** The product's type, or `null` for a flexible product. */
514
+ schemaId?: string | null;
515
+ /** A product or a service: chosen when the shop sells both, else the one kind it sells. */
516
+ kind?: "product" | "service";
517
+ createdAt?: string;
518
+ /** With `include: ["media"]`. */
519
+ media?: PublicMedia[];
520
+ /**
521
+ * True when the shop stops selling at zero (its sales rules) and this product has none left.
522
+ * Absent otherwise — including for a product nobody counts. Show it as sold out: adding it to
523
+ * a basket is refused.
524
+ */
525
+ soldOut?: boolean;
526
+ /**
527
+ * What customers' stars come to: the average (one decimal), how many rated, and the top of
528
+ * the scale. Only while the shop has customers vote with stars, and only once somebody has.
529
+ */
530
+ customerRating?: {
531
+ average: number;
532
+ count: number;
533
+ max: number;
534
+ };
535
+ /**
536
+ * What customers' likes come to: how many liked it and how many disliked it. Only while the
537
+ * shop has customers vote with likes (`dislikes` is 0 where it takes likes only), and only once
538
+ * somebody has.
539
+ */
540
+ customerLikes?: {
541
+ likes: number;
542
+ dislikes: number;
543
+ };
544
+ /**
545
+ * Where it stands among the shop's best sellers: 1 for the most units sold in paid,
546
+ * non-cancelled orders over the last 30 days, 2 for the next (ties share a rank) - the SALES
547
+ * rank; `sortBy: "popularity"` leads with ratings and only then follows it. A rank, never the
548
+ * units. Absent for a product that sold nothing in that time.
549
+ */
550
+ popularRank?: number;
551
+ /** With `include: ["categories"]`. Active categories only. */
552
+ categories?: PublicProductCategoryRef[];
553
+ /** With `include: ["settings"]`. Every setting the shop shows, described — see
554
+ * `PublicProductSetting`. Keys the company has switched off are absent, even where the
555
+ * product's type lists them; keys this product has not filled in carry an empty value. */
556
+ settings?: Record<string, PublicProductSetting>;
557
+ /** With `include: ["translations"]`: every enabled language, then field name. */
558
+ translations?: Record<string, Record<string, string>>;
559
+ /**
560
+ * The product's variants — its sizes, crusts, volumes — in the shop's order. Present with
561
+ * `include: ["settings"]`, and only on a product that has any.
562
+ *
563
+ * A product WITH variants is bought as one of them: `addCartItem` needs the variant's `id`
564
+ * as `variantId`, and the cart and checkout then charge that variant's price and discount.
565
+ */
566
+ variants?: PublicProductVariant[];
567
+ }
568
+ /**
569
+ * The optional parts of a product in a LISTING. Only active products are returned, so there
570
+ * is no `status`.
571
+ *
572
+ * As with categories, the API returns none unless asked and this client asks for all of them
573
+ * when a caller passes no `include`. `settings` is by far the largest part — a page that only
574
+ * shows names and prices should leave it out.
575
+ *
576
+ * One product read by id or name (`getProduct`) always carries everything.
577
+ */
578
+ export type PublicProductInclude = "translations" | "media" | "categories" | "settings";
579
+ /** One field every entry of a list carries, so a page knows how to read the values. */
580
+ /** What a list column holds. `entry` is the id of an entry of another list. */
581
+ export type PublicDictionaryColumnType = "text" | "number" | "money" | "date" | "translated_text" | "product" | "category" | "image" | "boolean" | "entry";
582
+ export interface PublicDictionaryColumn {
583
+ key: string;
584
+ label?: string;
585
+ type: PublicDictionaryColumnType;
586
+ /** For `entry`: the list the ids belong to - `getDictionary({ id })` names them. */
587
+ referenceDictionaryId?: string;
588
+ /**
589
+ * Several values of the type: the value is an array (several numbers, images, entry ids).
590
+ * Never for `boolean` or `translated_text`.
591
+ */
592
+ multiple?: boolean;
593
+ }
594
+ export interface PublicDictionaryEntry {
595
+ id: string;
596
+ /** Resolved to the language the site is read in. */
597
+ name: string;
598
+ /**
599
+ * Column values by key. A `money` column is a signed number of the shop's currency; a
600
+ * `multiple` column's value is an array of its type's values.
601
+ */
602
+ values: Record<string, string | number | boolean | string[] | number[]>;
603
+ }
604
+ /**
605
+ * A list the shop keeps — its sizes, its add-ons, what its kitchen cooks with.
606
+ *
607
+ * The other half of `product.settings`: a product says WHICH size it is and which add-ons it
608
+ * offers, this says what the shop's sizes and add-ons ARE — every entry, and the columns they
609
+ * carry. An add-on's surcharge lives on the entry, so a page pricing "large with extra
610
+ * mozzarella" needs both halves and only one of them rides on a product.
611
+ */
612
+ export interface PublicDictionary {
613
+ id: string;
614
+ /**
615
+ * The shop's own machine name for the list — `add_ons`, `pizza_sizes`. Set once and never
616
+ * changed, which is why a page should read by it rather than by the label.
617
+ */
618
+ identifier?: string;
619
+ /** What the shop calls it, in the language asked for. */
620
+ label: string;
621
+ description?: string;
622
+ columns: PublicDictionaryColumn[];
623
+ entries: PublicDictionaryEntry[];
624
+ }
625
+ /**
626
+ * A list without its entries — what `listDictionaries()` answers. Only the lists the shop
627
+ * marked "Visible on site", and only their public columns.
628
+ */
629
+ export type PublicDictionarySummary = Omit<PublicDictionary, "entries">;
630
+ /**
631
+ * How a single read names its row: by `id`, or by what it is called. Exactly one — the
632
+ * client refuses both or neither before anything leaves the process.
633
+ */
634
+ export type ByIdOrName = {
635
+ /** The row's id (a UUID), e.g. from a listing. */
636
+ id: string;
637
+ name?: never;
638
+ } | {
639
+ /**
640
+ * What it is called. Matched case-insensitively on the trimmed text, so a page need
641
+ * not reproduce the shop's capitalisation.
642
+ */
643
+ name: string;
644
+ id?: never;
645
+ };
646
+ /**
647
+ * A list by IDENTIFIER, by id, or by its label. Exactly one.
648
+ *
649
+ * `identifier` is the one to write a page against: the shop sets it once and it never changes.
650
+ * The label — `"Add-ons"`, `"Pizza sizes"` — still works and survives a retitling in another
651
+ * case, but it is translated and reworded, and a page reading by it breaks the day the shop
652
+ * tidies it up.
653
+ */
654
+ export type GetDictionaryParams = {
655
+ /** The shop's machine name for the list, e.g. `"add_ons"`. */
656
+ identifier: string;
657
+ id?: never;
658
+ name?: never;
659
+ } | (ByIdOrName & {
660
+ identifier?: never;
661
+ });
662
+ /** Products are paginated; categories are not. The asymmetry is the API's, not ours. */
663
+ export interface PaginationMetadata {
664
+ page: number;
665
+ limit: number;
666
+ hasNext: boolean;
667
+ }
668
+ export interface Paginated<T> {
669
+ data: T[];
670
+ pagination: PaginationMetadata;
671
+ }
672
+ export interface ListCategoriesParams {
673
+ search?: string;
674
+ /** Optional parts to include. Omitted → all of them; `[]` → none. */
675
+ include?: PublicCategoryInclude[];
676
+ /**
677
+ * At most this many.
678
+ *
679
+ * Applied HERE, not by the server: the categories route takes no paging, while the
680
+ * products one does. Callers write the two calls side by side and reasonably expect the
681
+ * same parameter to mean something in both, so it is honoured rather than ignored — a
682
+ * category list is tens of rows, so trimming the answer costs nothing.
683
+ */
684
+ limit?: number;
685
+ }
686
+ /**
687
+ * One category by `id`, or by what it is called — `"Wood-fired"`.
688
+ *
689
+ * A name is matched case-insensitively on the trimmed text, against the category's own name
690
+ * and its translations, so a page read in German may ask for the German heading. Names are
691
+ * not unique: where several match, the oldest is returned.
692
+ */
693
+ export type GetCategoryParams = ByIdOrName & {
694
+ /** Optional parts to include. Omitted → all of them; `[]` → none. */
695
+ include?: PublicCategoryInclude[];
696
+ };
697
+ /** One product by `id`, or by what it is called — matched the way a category's name is. */
698
+ export type GetProductParams = ByIdOrName;
699
+ export interface ListProductsParams {
700
+ /** A category UUID. Mutually exclusive with `categoryName`. */
701
+ categoryId?: string;
702
+ /** A category slug. The API's own spelling for what a page may call `categoryUniqueName`. */
703
+ categoryName?: string;
704
+ /** Only products filed under no category at all. */
705
+ categoryEmpty?: boolean;
706
+ search?: string;
707
+ /** 1-indexed, as the API counts. */
708
+ page?: number;
709
+ limit?: number;
710
+ tags?: string;
711
+ /**
712
+ * How the list is ordered. `custom` — the shop's own arrangement — is the default.
713
+ *
714
+ * `popularity` puts RATED products first, best rated first: by the customers' votes while the
715
+ * shop takes them (stars as the average over the scale, likes as the share of likes; with `up`
716
+ * voting, liked products first), else by the shop's own RATING setting over its scale. Equal
717
+ * ratings and unrated products then follow by units sold in paid, non-cancelled orders over the
718
+ * last `popularityDays`.
719
+ *
720
+ * `discount` puts the biggest discount on RIGHT NOW first: what comes off one unit of the
721
+ * product's own price - its DISCOUNT_RULE while that rule applies, else its DISCOUNT setting -
722
+ * the biggest percentage first, then the most saved. Products with no discount come last.
723
+ *
724
+ * Every order breaks ties by the shop's arrangement, so a shop with no ratings, sales or deals
725
+ * yet gets its own order back.
726
+ */
727
+ sortBy?: ProductSort;
728
+ /**
729
+ * Defaults to `DESC` for `popularity` and `discount` (the most of it first) and `ASC` for
730
+ * everything else. Unrated (popularity) and undiscounted (discount) products stay last either
731
+ * way.
732
+ */
733
+ sortOrder?: "ASC" | "DESC";
734
+ /** How many days back `popularity` counts sales over: 1–365, 30 when omitted. */
735
+ popularityDays?: number;
736
+ /** Optional parts to include. Omitted → all of them; `[]` → none. */
737
+ include?: PublicProductInclude[];
738
+ }
739
+ /**
740
+ * When a deal is on, on the shop's clock. A deal with no schedule is on at every hour of the
741
+ * days it is valid.
742
+ */
743
+ export interface PublicDealSchedule {
744
+ /** IANA zone the windows are read in, e.g. `"Pacific/Auckland"`. */
745
+ timeZone: string;
746
+ windows: Array<{
747
+ /** ISO weekdays, 1 = Monday … 7 = Sunday. */
748
+ days: number[];
749
+ /** `HH:MM`, inclusive. */
750
+ from: string;
751
+ /** `HH:MM`, exclusive. Not after `from`: runs past midnight. */
752
+ until: string;
753
+ }>;
754
+ }
755
+ /**
756
+ * How a combo's `price` is read:
757
+ *
758
+ * - `fixed_price`: the combo costs `price`, plus each pick's `surcharge`.
759
+ * - `percent_off`: the picks at their own prices, `price`% off.
760
+ * - `amount_off`: the picks at their own prices, `price` off — never below zero.
761
+ */
762
+ export type ComboPriceKind = "fixed_price" | "percent_off" | "amount_off";
763
+ /** A product variant a combo option may be filled with — when the option leaves it open. */
764
+ export interface PublicComboVariant {
765
+ id: string;
766
+ name: string;
767
+ /** False for a variant not on sale now: show it, but do not let it be picked. */
768
+ isAvailable: boolean;
769
+ }
770
+ /** One product that may fill a slot. */
771
+ export interface PublicComboSlotOption {
772
+ productId: string;
773
+ name: string;
774
+ /** The one variant this option offers, or null for "any of the product's variants". */
775
+ variantId: string | null;
776
+ variantName: string | null;
777
+ /** When `variantId` is null and the product has variants: the ones to choose from. */
778
+ variants?: PublicComboVariant[];
779
+ /** Added to a `fixed_price` combo for this pick, in major units. */
780
+ surcharge: number;
781
+ }
782
+ /** A place in the combo — "a pizza", "two drinks" — and what may fill it. */
783
+ export interface PublicComboSlot {
784
+ id: string;
785
+ name: string;
786
+ /** How many picks the slot takes. */
787
+ quantity: number;
788
+ options: PublicComboSlotOption[];
789
+ }
790
+ /**
791
+ * A combo on sale now: slots the shopper fills from a list of products, at a price.
792
+ *
793
+ * Only combos that are active, inside their dates and inside a weekly window AT THE MOMENT OF
794
+ * THE REQUEST are listed, and one with a slot no product on sale can fill is left out — so a
795
+ * page can show everything it is given. Add one to the cart with `addCartItem({ comboId,
796
+ * picks })`.
797
+ */
798
+ export interface PublicCombo {
799
+ id: string;
800
+ name: string;
801
+ description?: string;
802
+ priceKind: ComboPriceKind;
803
+ /** Read by `priceKind`: the price before surcharges, the percentage off, or the amount off. */
804
+ price: number;
805
+ /** The cheapest way to fill it, in major units — for "from 9.90" on a menu. */
806
+ fromPrice: number;
807
+ /** ISO timestamp it stops being sold, or null when open-ended. */
808
+ validUntil: string | null;
809
+ schedule: PublicDealSchedule | null;
810
+ /** The categories the shop displays it in — e.g. a lunch combo among the pizzas. */
811
+ categoryIds: string[];
812
+ /**
813
+ * The combo's own pictures, cover first — the deal photographed as a set. Empty when the shop
814
+ * has none: show the combo by its picks' photos instead.
815
+ */
816
+ images: {
817
+ url: string;
818
+ }[];
819
+ slots: PublicComboSlot[];
820
+ }
821
+ export interface ListCombosParams {
822
+ /** Only the combos the shop displays in this category. */
823
+ categoryId?: string;
824
+ }
825
+ /**
826
+ * The ways a discount rule prices the units it applies to:
827
+ *
828
+ * - `percent_off`: every unit costs `value`% less.
829
+ * - `amount_off`: every unit costs `value` less, never below zero.
830
+ * - `fixed_price`: every unit costs `value`, when that is less than its price.
831
+ * - `buy_x_get_y`: for every `buyQuantity` bought, the next `getQuantity` cost `value` each
832
+ * (`0` is free). The cheapest units of each group are the ones discounted.
833
+ * - `bundle_price`: every `buyQuantity` units together cost `value`.
834
+ */
835
+ export type DiscountRuleKind = "percent_off" | "amount_off" | "fixed_price" | "buy_x_get_y" | "bundle_price";
836
+ /**
837
+ * A discount rule on now — for a page to badge the products it targets ("2 for 1", "-20%").
838
+ *
839
+ * For DISPLAY: which rule a cart unit actually takes is decided when the cart is priced, and
840
+ * the cart's `discounts` say what was taken off.
841
+ */
842
+ export interface PublicDiscountRule {
843
+ id: string;
844
+ name: string;
845
+ description?: string;
846
+ kind: DiscountRuleKind;
847
+ /** A percentage for `percent_off`; money in major units for every other kind. */
848
+ value: number;
849
+ buyQuantity: number | null;
850
+ getQuantity: number | null;
851
+ validUntil: string | null;
852
+ schedule: PublicDealSchedule | null;
853
+ /** What it applies to: these products, and every product in these categories. */
854
+ productIds: string[];
855
+ categoryIds: string[];
856
+ }
857
+ /** The orders `getProducts` can list in. */
858
+ export type ProductSort = "custom" | "name" | "price" | "popularity" | "discount";
859
+ /**
860
+ * A basket, held by the server.
861
+ *
862
+ * `cartId` is the CREDENTIAL as well as the identifier — there is no visitor account, so
863
+ * whoever holds it holds the cart. Keep it out of anything a page renders, and out of a URL a
864
+ * visitor might share.
865
+ */
866
+ export interface PublicCart {
867
+ cartId: string;
868
+ workspace: Workspace;
869
+ items: PublicCartItem[];
870
+ /** Units across every line, for a badge. */
871
+ count: number;
872
+ /**
873
+ * Sum of price x quantity at CURRENT prices — each line's variant price where it has one —
874
+ * before any discount.
875
+ *
876
+ * The server does not know what a site charges for a size or a topping — that lives in
877
+ * `variant`, which it stores and never reads — so a site with its own options has to total
878
+ * the lines itself. This is the floor, not the bill.
879
+ */
880
+ subtotal: number;
881
+ /** Everything the shop's deals took off, in major units. */
882
+ discount: number;
883
+ /** `subtotal` less `discount`, plus tax when it is added on top — what the server will charge. */
884
+ total: number;
885
+ /**
886
+ * The sales tax in it, in major units: inside `total` when `taxInclusive` (show "incl. 15%
887
+ * tax"), added to it otherwise. 0 when the shop charges none.
888
+ */
889
+ tax: number;
890
+ /** The shop's tax rate, in percent. 0: no tax. */
891
+ taxRate: number;
892
+ /** True: prices include the tax. False: it is added on top of them. */
893
+ taxInclusive: boolean;
894
+ /** What the tax is called where the shop trades — GST, VAT, Sales tax. Label the tax line with it. */
895
+ taxName: string;
896
+ /** The rules that took money off the cart as a whole, and how much each. */
897
+ discounts: PublicCartDiscount[];
898
+ /**
899
+ * The table booking this basket is ordered for (`setCartBooking`), with what its booking fee
900
+ * adds to paying it; null for an ordinary basket.
901
+ */
902
+ booking: PublicCartBooking | null;
903
+ }
904
+ /** The booking a basket is ordered for, and its fee - see `PublicCart.booking`. */
905
+ export interface PublicCartBooking {
906
+ bookingId: string;
907
+ /** The shop's booking fee for this party, in major units; 0 when none is paid with an order. */
908
+ fee: number;
909
+ /**
910
+ * The fee counts towards the order: it is a minimum spend - an order of at least `fee` pays
911
+ * no fee, a smaller one pays the difference.
912
+ */
913
+ feeIsDeposit: boolean;
914
+ /**
915
+ * What paying THIS basket adds for the booking, in major units, on top of `total`: the whole
916
+ * fee for an empty basket, the shortfall or 0 for a deposit, 0 once the fee is paid.
917
+ */
918
+ charged: number;
919
+ /**
920
+ * Of a deposit, the part the basket covers, in major units - shown as the fee and taken off,
921
+ * so the fee is seen charged and removed. `charged` + `included` is the whole fee. Absent from
922
+ * servers before it.
923
+ */
924
+ included?: number;
925
+ }
926
+ /** One deal, and what it took off a line or the cart. */
927
+ export interface PublicCartDiscount {
928
+ ruleId: string;
929
+ name: string;
930
+ /** In major units. */
931
+ amount: number;
932
+ }
933
+ /** One product picked into a combo line. */
934
+ export interface PublicCartComboPick {
935
+ slotId: string;
936
+ slotName: string;
937
+ productId: string;
938
+ name: string;
939
+ variantId: string | null;
940
+ variantName: string | null;
941
+ /** Added to the combo's price for this pick, in major units. */
942
+ surcharge: number;
943
+ /** The site's own configuration for the pick, as on a product line. */
944
+ variant?: string;
945
+ }
946
+ /** What makes a line a combo: which one, and what fills it. The line's `name` is the combo's. */
947
+ export interface PublicCartCombo {
948
+ comboId: string;
949
+ picks: PublicCartComboPick[];
950
+ }
951
+ export interface PublicCartItem {
952
+ /** Identifies the LINE, which is what quantity changes and removals address. */
953
+ cartItemId: string;
954
+ /** The product on a product line. Absent on a combo line — read `combo` there. */
955
+ productId?: string;
956
+ /** Present on a combo line: the combo and every pick in it. */
957
+ combo?: PublicCartCombo;
958
+ /** What deals took off this line, in major units, and which ones. */
959
+ discount: number;
960
+ discounts: PublicCartDiscount[];
961
+ /** (Price + `addOns`) × quantity less `discount`. */
962
+ total: number;
963
+ /** Why the line can no longer be bought (sold out, deal ended) — absent when it can. */
964
+ unavailable?: string;
965
+ name: string;
966
+ /** As it stands now, not as it stood when the line was added. Without the extras. */
967
+ price?: number;
968
+ /**
969
+ * What the chosen extras add to one unit, at the prices in the shop's lists - charged at
970
+ * checkout, not discounted. Absent when nothing extra was chosen.
971
+ */
972
+ addOns?: number;
973
+ image?: string;
974
+ quantity: number;
975
+ /** The product variant this line is, when the product has variants. */
976
+ variantId: string | null;
977
+ /** That variant's name in the request language, for the basket row. */
978
+ variantName: string | null;
979
+ /** Whatever the site put there. Opaque to the server; parse it back yourself. */
980
+ variant: string;
981
+ }
982
+ /**
983
+ * Every cart call carries the id explicitly.
984
+ *
985
+ * The server would accept the cookie it set instead, and a browser on the same site would be
986
+ * fine. A SERVER component would not: it has no cookie jar, and would silently read whichever
987
+ * cart the process last touched. Passing the id makes the call mean the same thing wherever it
988
+ * runs.
989
+ */
990
+ export interface GetCartParams {
991
+ cartId: string;
992
+ }
993
+ /**
994
+ * Add a product — or a combo, with what fills it. Exactly one of `productId` and `comboId`.
995
+ */
996
+ export interface AddCartItemParams extends GetCartParams {
997
+ productId?: string;
998
+ /** A combo from `getCombos`; `picks` then fill every one of its slots. */
999
+ comboId?: string;
1000
+ /** One per unit a slot takes: a slot of `quantity: 2` takes two picks. */
1001
+ picks?: ComboPick[];
1002
+ /** Defaults to 1. Clamped, floored, and rejected if it is not a number. */
1003
+ quantity?: number;
1004
+ /**
1005
+ * Which of the product's variants — `PublicProduct.variants[].id`. Required for a product
1006
+ * that has variants, refused for one that has none. The line is then priced as that variant:
1007
+ * its price, its discount rule.
1008
+ */
1009
+ variantId?: string;
1010
+ /**
1011
+ * The site's own configuration for this line — a size, toppings, whatever it sells.
1012
+ *
1013
+ * Stored verbatim and never parsed by the server, which uses it only to tell two lines of
1014
+ * the same product apart. Send the SAME string for the same configuration or a second Large
1015
+ * opens a second line: serialize it in a stable order, or the key stops matching itself.
1016
+ */
1017
+ variant?: string;
1018
+ }
1019
+ /** One product filling one place in a combo. */
1020
+ export interface ComboPick {
1021
+ /** `PublicComboSlot.id`. */
1022
+ slotId: string;
1023
+ /** One of that slot's `options[].productId`. */
1024
+ productId: string;
1025
+ /**
1026
+ * Which variant: required when the option leaves it open (`variantId: null`) and the
1027
+ * product has variants — one of the option's `variants[].id`.
1028
+ */
1029
+ variantId?: string;
1030
+ /** The site's own configuration for the pick, as on a product line. */
1031
+ variant?: string;
1032
+ }
1033
+ export interface SetCartItemQuantityParams extends GetCartParams {
1034
+ cartItemId: string;
1035
+ /** Zero removes the line. */
1036
+ quantity: number;
1037
+ }
1038
+ export interface RemoveCartItemParams extends GetCartParams {
1039
+ cartItemId: string;
1040
+ }
1041
+ export interface SetCartBookingParams extends GetCartParams {
1042
+ /** The booking (createBooking's id) the basket is ordered for; null lets it go. */
1043
+ bookingId: string | null;
1044
+ }
1045
+ /**
1046
+ * Start paying for a basket.
1047
+ *
1048
+ * The server builds the order from the cart it holds — every line, at the quantity the
1049
+ * shopper chose, priced from the catalogue now — so a page cannot charge for something that
1050
+ * was never in the basket.
1051
+ */
1052
+ /**
1053
+ * How an order reaches the customer. `delivery`: the hosted payment page asks for the address
1054
+ * and prices it by the shop's delivery zones.
1055
+ */
1056
+ /** Whether an order names the location it is for - see `SiteInfo.orderLocation`. */
1057
+ /** Who sees the site - `getSiteInfo().customerAccess`. */
1058
+ export type CustomerAccess = "public" | "signed_in";
1059
+ export type OrderLocationMode = "never" | "optional" | "required";
1060
+ export type OrderType = "pickup" | "reservation" | "delivery" | "dine_in";
1061
+ /** A table a guest is ordering from, by the id on its QR code. */
1062
+ export interface PublicDiningTable {
1063
+ tableId: string;
1064
+ label: string;
1065
+ /** How to name it to the guest, in their language: "Table 5". */
1066
+ title: string;
1067
+ /** The restaurant it stands in - null for a shop whose plan names none. */
1068
+ locationId: string | null;
1069
+ /** The way out, in their language, for a code scanned by mistake: "Not at this table?". */
1070
+ leaveLabel: string;
1071
+ /** What to call the table code, in the page's language. */
1072
+ codeLabel: string;
1073
+ /** What to say once the code is accepted. */
1074
+ codeAcceptedLabel: string;
1075
+ /** Whether the shop takes orders from tables. */
1076
+ isOpen: boolean;
1077
+ /** What to tell the guest, in their language: to ask the staff for the table's code. */
1078
+ notice: string | null;
1079
+ }
1080
+ export interface CreateCheckoutParams extends GetCartParams {
1081
+ /**
1082
+ * Where the receipt goes, and who the shopper is to Stripe for saved cards. Optional: left
1083
+ * out, the checkout page asks for it before taking the payment — so a site needs no form.
1084
+ */
1085
+ customerEmail?: string;
1086
+ /**
1087
+ * A phone to reach the customer about the order. Required for a delivery before it is paid:
1088
+ * left out, the checkout page asks for it. A signed-in customer's own phone is used otherwise.
1089
+ */
1090
+ customerPhone?: string;
1091
+ /** The customer's note for the kitchen or the driver - "no onions", "ring the bell". */
1092
+ notes?: string;
1093
+ /**
1094
+ * Where the checkout page sends the shopper after paying. `{CHECKOUT_ID}` is replaced with
1095
+ * the checkout's id, so a confirmation page can look it up.
1096
+ */
1097
+ successUrl?: string;
1098
+ /** Where the checkout page sends a shopper who backs out — usually the basket. */
1099
+ cancelUrl?: string;
1100
+ /**
1101
+ * The language the shopper is reading the shop in, as an ISO code.
1102
+ *
1103
+ * The payment page is written in it and the product names on the checkout are snapshotted in
1104
+ * it, so a shopper who ordered in Russian pays in Russian. Left out, the language this client
1105
+ * is already reading in is sent — the same one that goes out as `x-language` — which is the
1106
+ * right answer for every site that has a language at all. Pass it only to say something
1107
+ * different from what the page is rendered in.
1108
+ */
1109
+ language?: string;
1110
+ /**
1111
+ * Where the order is picked up or served: one of the shop's active locations, from
1112
+ * `getLocations` - its `number` (`2`, preferred in addresses) or its `id`. Required when the site info says `orderLocation: "required"`; refused when it
1113
+ * names a location that is not the shop's or not on its site.
1114
+ */
1115
+ locationId?: string | number;
1116
+ /**
1117
+ * How the order reaches the customer — one of `getSiteInfo().orderTypes`. Left out: the first
1118
+ * the shop offers, which the hosted payment page lets the shopper change. Refused when the
1119
+ * shop does not offer it.
1120
+ */
1121
+ orderType?: OrderType;
1122
+ /**
1123
+ * When the order should be ready: a time's `at` from `getOrderTimes`. Left out, as soon as
1124
+ * possible. Refused when the shop does not let customers choose a time, or it is not one
1125
+ * offered.
1126
+ */
1127
+ scheduledFor?: string;
1128
+ /**
1129
+ * The table booking this order is for — a guest ordering ahead for the table they booked: the
1130
+ * `id` `createBooking` returned, or a `bookingId` from `getCustomerBookings`. The order becomes
1131
+ * `reservation` at the booking's location unless `orderType` / `locationId` say otherwise, and the
1132
+ * shop sees it on the booking. Refused when the booking is over (finished, cancelled, no-show)
1133
+ * or belongs to another signed-in customer.
1134
+ */
1135
+ bookingId?: string | number;
1136
+ /**
1137
+ * The table a guest is ordering from, by the id on its QR code. The order is then dine-in at
1138
+ * that table, and nothing about it can be changed; the payment page asks for the table's code.
1139
+ */
1140
+ tableId?: string;
1141
+ /** That table's code, if the guest gave it already: the payment page then does not ask. */
1142
+ tableCode?: string;
1143
+ /**
1144
+ * False: the payment page offers no choice of when - `scheduledFor` stands, or as soon as
1145
+ * possible. These go in the checkout, not its address, so a guest cannot change them.
1146
+ */
1147
+ allowTimeChoice?: boolean;
1148
+ /** False: no choice of how the order is received. Needs `orderType`. */
1149
+ allowOrderTypeChoice?: boolean;
1150
+ /** False: no choice of how it is paid. Needs `paymentMethod`. */
1151
+ allowPaymentMethodChoice?: boolean;
1152
+ /** How it is paid: `card` online, or `in_store`. */
1153
+ paymentMethod?: "card" | "in_store";
1154
+ /**
1155
+ * A promo code the customer typed, any case - money off the order after its deals, or free
1156
+ * delivery. Refused with the reason (`code`: `promo_code_unknown`, `promo_code_expired`,
1157
+ * `promo_code_used_up`, `promo_code_minimum`, ...) when it cannot go on this order. The hosted
1158
+ * payment page offers a code field of its own, so a site need not ask.
1159
+ */
1160
+ promoCode?: string;
1161
+ /**
1162
+ * The signed-in customer's token, from `verifySignInCode`, `signInWithGoogle` or `signInWithApple`. The checkout
1163
+ * — and the order it becomes — is then theirs, and their email is used when `customerEmail`
1164
+ * is left out. Left out: a guest checkout, belonging to whoever the email is.
1165
+ */
1166
+ customerToken?: string;
1167
+ }
1168
+ export type CheckoutStatus = "pending" | "paid" | "failed" | "cancelled";
1169
+ /** Which checkout to read, by the id `createCheckout` answered with. */
1170
+ export interface GetCheckoutParams {
1171
+ checkoutId: string;
1172
+ }
1173
+ /** Who is paying, given on the site's own payment page. */
1174
+ export interface SetCheckoutEmailParams extends GetCheckoutParams {
1175
+ email: string;
1176
+ }
1177
+ /**
1178
+ * What Stripe.js needs to take the card IN THE PAGE, rather than on the hosted page.
1179
+ *
1180
+ * Present only while the checkout can still be paid. None of it is a secret a shopper must be
1181
+ * kept from: the publishable key is public by design, and a PaymentIntent's client secret
1182
+ * authorises paying THIS order and nothing else — which is why Stripe's own Elements take it
1183
+ * in the browser. Pass it to a `"use client"` component as props; the card itself is typed
1184
+ * into Stripe's iframe and never touches page code.
1185
+ */
1186
+ export interface PublicCheckoutPayment {
1187
+ /** The PLATFORM's publishable key. Public, and safe in a bundle. */
1188
+ publishableKey: string;
1189
+ /**
1190
+ * The shop's own Stripe account, when the charge is made on it.
1191
+ *
1192
+ * Stripe.js has to be loaded with it (`loadStripe(key, { stripeAccount })`) or it looks for
1193
+ * the PaymentIntent on the platform's account, does not find it, and the element never
1194
+ * mounts.
1195
+ */
1196
+ connectedAccountId?: string;
1197
+ /** The PaymentIntent to confirm. */
1198
+ clientSecret: string;
1199
+ /**
1200
+ * Offers the cards this shopper saved at this shop, and offers to save this one.
1201
+ *
1202
+ * Only when the checkout knows who is paying — pass `customerEmail` to `createCheckout`.
1203
+ * Without it the payment is a one-off, which still works.
1204
+ */
1205
+ customerSessionClientSecret?: string;
1206
+ /**
1207
+ * The card is kept for later whatever the shopper says - a booking that needs it, or a shop
1208
+ * that keeps every card (Sales rules → Payment methods → Online payment details). Stripe's
1209
+ * element then shows no "save" box: say on the page that the card is saved. Absent from an
1210
+ * older server: not kept.
1211
+ */
1212
+ storesCard?: boolean;
1213
+ }
1214
+ /**
1215
+ * A checkout as the page TAKING the payment sees it: the order, and the secrets to charge it.
1216
+ *
1217
+ * Read with `getCheckout`. The shape differs from `createCheckout`'s answer because it answers
1218
+ * a different question — not "where do I send the shopper" but "what am I charging, and with
1219
+ * what" — so it carries the shop's name, the currency and `payment`, and no hosted URL.
1220
+ */
1221
+ export interface PublicCheckoutSession {
1222
+ checkoutId: string;
1223
+ status: CheckoutStatus;
1224
+ /** The shop being paid, for the page to name in its own words. */
1225
+ shopName: string;
1226
+ /** Stripe test keys: a test card works and nothing real is charged. */
1227
+ testMode: boolean;
1228
+ /** Null until the shopper is known — no email was given at creation. */
1229
+ customerEmail: string | null;
1230
+ /** Priced by the server from the cart, so a page cannot charge its own totals. */
1231
+ items: {
1232
+ name: string;
1233
+ /** The variant sold, when the product has variants. */
1234
+ variantName?: string;
1235
+ quantity: number;
1236
+ unitPriceCents: number;
1237
+ }[];
1238
+ subtotalCents: number;
1239
+ totalCents: number;
1240
+ /** ISO 4217, lowercase. */
1241
+ currency: string;
1242
+ /** Decimal digits of every `…Cents` amount (ISO 4217): read `totalCents / 10 ** currencyMinorUnit`. */
1243
+ currencyMinorUnit?: number;
1244
+ successUrl?: string;
1245
+ cancelUrl?: string;
1246
+ /**
1247
+ * True: the shop takes orders from signed-in customers only and a guest made this checkout
1248
+ * (before the rule was on) - there is no `payment`; send them back to sign in and check out again.
1249
+ */
1250
+ signInRequired?: boolean;
1251
+ /** Absent once the checkout is paid, cancelled, or otherwise no longer payable. */
1252
+ payment?: PublicCheckoutPayment;
1253
+ }
1254
+ export interface PublicCheckout {
1255
+ checkoutId: string;
1256
+ /**
1257
+ * The hosted checkout page. Send the shopper's BROWSER here — a redirect from a server
1258
+ * action — and the page takes the payment and returns them to `successUrl`.
1259
+ */
1260
+ checkoutUrl: string;
1261
+ status: CheckoutStatus;
1262
+ /** Null until known — when the site left it to the checkout page, and the shopper has not got there. */
1263
+ customerEmail: string | null;
1264
+ /** In the smallest currency unit. */
1265
+ subtotalCents: number;
1266
+ totalCents: number;
1267
+ /** The sales tax, in the smallest unit — inside `totalCents` when `taxInclusive`. */
1268
+ taxCents: number;
1269
+ taxRate: number;
1270
+ taxInclusive: boolean;
1271
+ /** What the tax is called where the shop trades — GST, VAT, Sales tax. Label the tax line with it. */
1272
+ taxName: string;
1273
+ items: {
1274
+ productId?: string;
1275
+ productNameSnapshot: string;
1276
+ /** The variant sold, when the product has variants. */
1277
+ variantId?: string | null;
1278
+ /** What that variant was called, in the checkout's language. */
1279
+ variantName?: string | null;
1280
+ quantity: number;
1281
+ unitPriceCents: number;
1282
+ }[];
1283
+ createdAt: string;
1284
+ }
1285
+ /** A time a party can book, on the location's clock. */
1286
+ export interface PublicBookingSlot {
1287
+ /** `HH:mm` at the location. */
1288
+ time: string;
1289
+ /** The instant — what `createBooking` takes. */
1290
+ startsAt: string;
1291
+ /** Whether a table that seats the party is free for the whole visit. */
1292
+ available: boolean;
1293
+ }
1294
+ /** One later time an order can be for: the location's wall clock, and the instant. */
1295
+ export interface PublicOrderTime {
1296
+ /** `HH:mm` at the location. */
1297
+ time: string;
1298
+ /** The instant — what `createCheckout` takes as `scheduledFor`. */
1299
+ at: string;
1300
+ }
1301
+ /**
1302
+ * When an order can be for, on the location's own clock — the same times the hosted payment
1303
+ * page offers and the server accepts.
1304
+ */
1305
+ export interface PublicOrderTimes {
1306
+ /** The location's zone; null when it has none — then `days` is empty. */
1307
+ timeZone: string | null;
1308
+ /** Whether "as soon as possible" can be ordered now: the location is open. */
1309
+ asap: boolean;
1310
+ /** The earliest an order can be ready (now plus the takeaway time), ISO 8601. */
1311
+ earliest: string;
1312
+ /**
1313
+ * Later times by day (`date` is `YYYY-MM-DD` at the location) — today only unless the shop
1314
+ * lets customers choose a day. Empty when the shop does not let customers choose a time.
1315
+ */
1316
+ days: {
1317
+ date: string;
1318
+ times: PublicOrderTime[];
1319
+ }[];
1320
+ }
1321
+ export interface GetOrderTimesParams {
1322
+ /** The order's location, from `getLocations` - its `number` (`2`, preferred in addresses) or its `id`; left out, the shop's only active one. */
1323
+ locationId?: string | number;
1324
+ }
1325
+ /** The day's times for a party at one location. */
1326
+ export interface PublicBookingSlots {
1327
+ locationId: string;
1328
+ date: string;
1329
+ /** The clock the times are on. */
1330
+ timeZone: string;
1331
+ /** How long a booking holds its table — the length asked for, or the shop's default. */
1332
+ durationMinutes: number;
1333
+ /** The shortest reservation the shop takes, in minutes — what a guest may choose from. */
1334
+ minDurationMinutes?: number;
1335
+ /** The longest, in minutes. */
1336
+ maxDurationMinutes?: number;
1337
+ /**
1338
+ * The cancellation notice the guest books under: they may cancel it themselves
1339
+ * (`cancelBooking`) up to this many hours before it starts; 0: up to the start. Say it beside
1340
+ * the booking - "Free cancellation up to 2 hours before".
1341
+ */
1342
+ cancelHours?: number;
1343
+ /**
1344
+ * False: the shop allows no free cancellation - say none; `cancelHours` promises nothing, and
1345
+ * cancelling costs its fee (each booking's `cancelFee`).
1346
+ */
1347
+ freeCancellation?: boolean;
1348
+ /** What booking costs, in minor units of the shop's currency; 0: nothing. Paid online. */
1349
+ bookingFeeCents?: number;
1350
+ /** When it is paid: with the booking, or only for a late cancellation or a no-show. */
1351
+ bookingFeeCharge?: "checkout" | "on_cancel";
1352
+ /** Per booking, or per guest (times the party). */
1353
+ bookingFeePer?: "booking" | "guest";
1354
+ /** From how many guests the fee is asked; a smaller party pays none. */
1355
+ bookingFeeFromParty?: number;
1356
+ /**
1357
+ * The fee counts towards the order (a deposit): with dishes ordered for the booking it is part
1358
+ * of the order's price, not paid on top - say the fee only for a booking with no order.
1359
+ */
1360
+ bookingFeeDeposit?: boolean;
1361
+ /** The smallest and largest party the shop takes online - a bigger one should call. */
1362
+ minPartySize?: number;
1363
+ maxPartySize?: number;
1364
+ /** A whole table, seats at a shared table, or a time only (no table, no plan to show). */
1365
+ mode: "table" | "seat" | "time";
1366
+ /**
1367
+ * What the shop reserves: `specialist` and `custom` book one of `entries`; `table` and `seat`
1368
+ * a table; `time` a time only.
1369
+ */
1370
+ reservationType?: "off" | "table" | "seat" | "specialist" | "time" | "custom";
1371
+ /**
1372
+ * For a `specialist` or `custom` shop, what a guest may pick, in the shop's order - pass one
1373
+ * as `entryId` to see its times and to book it. Empty otherwise.
1374
+ */
1375
+ entries?: PublicBookingEntry[];
1376
+ /** Rooms with bookable tables — what `seating` may name. Empty for time-only. */
1377
+ rooms: string[];
1378
+ /** Every half hour while open; empty when closed that day. */
1379
+ slots: PublicBookingSlot[];
1380
+ }
1381
+ /** Something a guest books by name - a specialist. */
1382
+ export interface PublicBookingEntry {
1383
+ id: string;
1384
+ name: string;
1385
+ /** Its picture, as a URL - a specialist's photo; null when it has none. */
1386
+ image: string | null;
1387
+ /**
1388
+ * The products it can be booked for - a dentist's treatments - while the shop books from an
1389
+ * allowed list (`reservationOrder: "list"`); null: anything the rules allow.
1390
+ */
1391
+ productIds?: string[] | null;
1392
+ }
1393
+ /** What a guest books: a table, an entry of the shop's list, or a time alone. */
1394
+ export type ReservationKind = "table" | "list" | "time";
1395
+ export interface GetBookingSlotsParams {
1396
+ /** The location - its `number` (`2`, preferred in addresses) or its `id`. */
1397
+ locationId: string | number;
1398
+ /** `YYYY-MM-DD`. */
1399
+ date: string;
1400
+ partySize: number;
1401
+ /** A room from `rooms`; any when left out. */
1402
+ seating?: string;
1403
+ /** The visitor's IANA zone, for a location that keeps none. */
1404
+ timeZone?: string;
1405
+ /**
1406
+ * One table of the location: each time then says whether THAT table is free and seats the
1407
+ * party — the day of the table the guest picked. Ignored when the shop books a time only.
1408
+ */
1409
+ tableId?: string;
1410
+ /** How long the visit is, in minutes — within the shop's range; its default when left out. */
1411
+ durationMinutes?: number;
1412
+ /** For a `specialist` or `custom` shop: one of `entries` - the times THAT one is free. */
1413
+ entryId?: string;
1414
+ /** Several of `entries` - the times ANY of them is free. Ignored with `entryId`. */
1415
+ entryIds?: string[];
1416
+ /**
1417
+ * What the visit is for - a product (a treatment). With an allowed list only the entries that
1418
+ * offer it count: each time says whether any of them is free.
1419
+ */
1420
+ productId?: string;
1421
+ /** Several services: the times an entry that offers ALL of them is free. */
1422
+ productIds?: string[];
1423
+ /**
1424
+ * What is booked, of the shop's `reservationKinds` (`getSiteInfo`) - `table`, `list` (an entry
1425
+ * of its list: a specialist, a room), `time` alone; the shop's main way when left out.
1426
+ */
1427
+ kind?: ReservationKind;
1428
+ }
1429
+ /** One thing drawn on the floor plan, in grid units (about a metre each). */
1430
+ export interface PublicPlanItem {
1431
+ id: string;
1432
+ kind: "table" | "room" | "wall" | "bar" | "door" | "window" | "plant" | "zone" | "column";
1433
+ label: string;
1434
+ shape: "round" | "rect" | null;
1435
+ seats: number | null;
1436
+ /** Chairs per side of a rectangular table. */
1437
+ chairs: {
1438
+ top: number;
1439
+ right: number;
1440
+ bottom: number;
1441
+ left: number;
1442
+ } | null;
1443
+ x: number;
1444
+ y: number;
1445
+ width: number;
1446
+ height: number;
1447
+ rotation: number;
1448
+ }
1449
+ /** A table's state at the asked time. */
1450
+ export interface PublicPlanTable {
1451
+ id: string;
1452
+ label: string;
1453
+ seats: number;
1454
+ /** The room it stands in. */
1455
+ room: string | null;
1456
+ /** Free at that time, for any party. */
1457
+ available: boolean;
1458
+ /** Free AND seats this party in the wanted room. */
1459
+ fits: boolean;
1460
+ }
1461
+ /** The location's floor plan at a time, with the best free table for the party. */
1462
+ export interface PublicBookingPlan {
1463
+ width: number;
1464
+ height: number;
1465
+ /** Everything to draw, rooms first. */
1466
+ items: PublicPlanItem[];
1467
+ tables: PublicPlanTable[];
1468
+ /** Null when none fits — and always in `time` mode, where no table is chosen. */
1469
+ suggestedTableId: string | null;
1470
+ /**
1471
+ * How the shop takes bookings. `time`: the plan is for looking at — no table fits, none is
1472
+ * suggested, and a booking that names a table or seating is refused.
1473
+ */
1474
+ mode?: "table" | "seat" | "time";
1475
+ }
1476
+ export interface GetBookingPlanParams {
1477
+ /** The location - its `number` (`2`, preferred in addresses) or its `id`. */
1478
+ locationId: string | number;
1479
+ /** A slot's `startsAt`. */
1480
+ startsAt: string;
1481
+ partySize: number;
1482
+ seating?: string;
1483
+ /** How long the visit is, in minutes; the shop's default when left out. */
1484
+ durationMinutes?: number;
1485
+ /**
1486
+ * What is booked, of the shop's `reservationKinds` (`getSiteInfo`) - `table`, `list` (an entry
1487
+ * of its list: a specialist, a room), `time` alone; the shop's main way when left out.
1488
+ */
1489
+ kind?: ReservationKind;
1490
+ }
1491
+ export interface CreateBookingParams {
1492
+ /** The location - its `number` (`2`, preferred in addresses) or its `id`. */
1493
+ locationId: string | number;
1494
+ /** A slot's `startsAt`. */
1495
+ startsAt: string;
1496
+ partySize: number;
1497
+ /**
1498
+ * What is booked, of the shop's `reservationKinds` (`getSiteInfo`) - `table`, `list` (an entry
1499
+ * of its list: a specialist, a room), `time` alone; the shop's main way when left out.
1500
+ */
1501
+ kind?: ReservationKind;
1502
+ /**
1503
+ * Who is coming — required for a guest. With a signed-in customer (`customerToken`, or the
1504
+ * cookie through `@estoreclub/client`) each one left out is taken from their account.
1505
+ */
1506
+ guestName?: string;
1507
+ guestPhone?: string;
1508
+ guestEmail?: string;
1509
+ /** Birthday, high chair, allergies… */
1510
+ notes?: string;
1511
+ /** The table the guest picked; the best fit when left out or taken. */
1512
+ tableId?: string;
1513
+ seating?: string;
1514
+ /** How long to hold the table, in minutes — within the shop's range; its default when left out. */
1515
+ durationMinutes?: number;
1516
+ /** The guest asked for a text reminder. */
1517
+ remind?: boolean;
1518
+ timeZone?: string;
1519
+ /** The signed-in customer's token: the booking is then theirs. */
1520
+ customerToken?: string;
1521
+ /** For a `specialist` or `custom` shop: the one to book; the first free when left out. */
1522
+ entryId?: string;
1523
+ /** Without `entryId`: the first free of these is booked. */
1524
+ entryIds?: string[];
1525
+ /**
1526
+ * What the visit is for - one of the shop's products, when its rules let a reservation carry
1527
+ * one (`reservationOrder`). With an allowed list, only an entry that offers it is booked.
1528
+ */
1529
+ productId?: string;
1530
+ /**
1531
+ * The visit's services - the shop's products. Booked with a draft order holding them; with an
1532
+ * allowed list only an entry that offers ALL of them is booked.
1533
+ */
1534
+ productIds?: string[];
1535
+ /** Where the payment page sends the guest back, when the shop requires payment to reserve. */
1536
+ successUrl?: string;
1537
+ cancelUrl?: string;
1538
+ /**
1539
+ * How the guest pays, where the shop offers both (`reservationPayment`): `now`, or `on_accept`
1540
+ * - the card held, charged when the shop accepts. Left out: the shop's way.
1541
+ */
1542
+ payment?: ReservationPaymentTiming;
1543
+ }
1544
+ /** The ways a booking may be paid when it is made. */
1545
+ export interface PublicReservationPayment {
1546
+ /** Paid now - charged at once. */
1547
+ order: boolean;
1548
+ /** The card held now, charged when the shop accepts the booking. */
1549
+ deferred: boolean;
1550
+ }
1551
+ /** One booking's way of paying: charged now, or held until the shop accepts it. */
1552
+ export type ReservationPaymentTiming = "now" | "on_accept";
1553
+ /** A booking made from the site — confirmed at once. */
1554
+ export interface PublicBooking {
1555
+ id: string;
1556
+ /** The shop's own number for the booking (`12`) - what your links name it by; taken wherever a `bookingId` is. */
1557
+ bookingNumber: number | null;
1558
+ locationId: string;
1559
+ startsAt: string;
1560
+ partySize: number;
1561
+ durationMinutes: number;
1562
+ /** The table held for the party; null for a time-only booking. */
1563
+ tableLabel: string | null;
1564
+ room: string | null;
1565
+ /** The entry booked - a specialist - its name and picture; null otherwise. */
1566
+ entryId?: string | null;
1567
+ entryName?: string | null;
1568
+ entryImage?: string | null;
1569
+ /** What the visit is for - the services booked, in the order asked. */
1570
+ services?: {
1571
+ id: string;
1572
+ name: string;
1573
+ }[];
1574
+ /**
1575
+ * The draft order holding the services, paid later - at the visit, or now when the shop
1576
+ * requires payment to reserve (`payment`). Null when nothing was booked for.
1577
+ */
1578
+ orderId?: string | null;
1579
+ orderNumber?: number | null;
1580
+ /** What it comes to, in major units. */
1581
+ orderTotal?: number | null;
1582
+ /**
1583
+ * For a `pending` booking (the shop requires payment to reserve): where the guest pays - a PATH
1584
+ * on the shop's own site; send them there. The time is held meanwhile and lapses unpaid.
1585
+ */
1586
+ payment?: {
1587
+ checkoutId: string;
1588
+ checkoutUrl: string;
1589
+ /** `now`: charged on the payment page; `on_accept`: only held there. */
1590
+ timing?: ReservationPaymentTiming;
1591
+ } | null;
1592
+ /**
1593
+ * `confirmed`; `pending` while its payment is made; or `requested` - waiting for the shop to
1594
+ * accept it (its time held meanwhile). The guest is emailed the shop's answer.
1595
+ */
1596
+ status: "confirmed" | "pending" | "requested";
1597
+ }
1598
+ /** A customer of the shop, as the site sees them. */
1599
+ export interface PublicCustomer {
1600
+ customerId: string;
1601
+ email: string;
1602
+ name: string | null;
1603
+ phone: string | null;
1604
+ /** `YYYY-MM-DD`. */
1605
+ dateOfBirth: string | null;
1606
+ /**
1607
+ * Their picture, as a URL — Google's profile photo, refreshed on each Google sign-in. Null:
1608
+ * none; draw initials. Load it with `referrerPolicy="no-referrer"`.
1609
+ */
1610
+ avatarUrl: string | null;
1611
+ /**
1612
+ * The language they chose to read the shop in (ISO code), on any of its sites or apps - read
1613
+ * in it once they sign in. Null: never chosen.
1614
+ */
1615
+ language?: string | null;
1616
+ /** When they first signed in. */
1617
+ signedUpAt: string | null;
1618
+ /**
1619
+ * Signed in and holding every detail the shop requires. False: ask for `missingFields`
1620
+ * (with `updateCustomerProfile`) before going on.
1621
+ */
1622
+ onboarded: boolean;
1623
+ /** The required details still missing; empty once onboarded. */
1624
+ /**
1625
+ * The details still to give, then the consents the shop requires and they have not given:
1626
+ * `terms` (show `getTerms()`, send `acceptTerms: true`) and `healthConsent`.
1627
+ */
1628
+ missingFields: (CustomerField | CustomerConsent)[];
1629
+ /**
1630
+ * What those missing details stop until they are given - the shop's rule: `orders` (signed
1631
+ * in, but ordering and booking are refused) or `sign_in` (signed out everywhere but their own
1632
+ * account, so a members-only site stays locked). Null once nothing is missing. Ask for the
1633
+ * details either way; for `sign_in` there is no skipping them.
1634
+ */
1635
+ missingDetailsStop?: "orders" | "sign_in" | null;
1636
+ }
1637
+ /** A customer detail a shop may require, beyond the email. */
1638
+ export type CustomerField = "name" | "phone" | "dateOfBirth";
1639
+ /** A consent a shop may require, missing like a detail until it is given. */
1640
+ export type CustomerConsent = "terms" | "healthConsent";
1641
+ export type CustomerRequiredFields = Record<CustomerField, boolean>;
1642
+ /**
1643
+ * What a sign-in (or a refresh) answers with. Keep BOTH tokens where only the site's SERVER can
1644
+ * read them — httpOnly cookies, never browser storage — and pass `token` as `customerToken` to
1645
+ * the calls that take one.
1646
+ */
1647
+ export interface PublicCustomerSession {
1648
+ /** Short-lived (15 minutes by default) and not revocable: what the customer's calls carry. */
1649
+ token: string;
1650
+ /**
1651
+ * Trades for a new `token` and a new `refreshToken` (`refreshCustomerToken`) once `token`
1652
+ * lapses. Single use: keep the one each refresh answers with; a spent one stops working.
1653
+ */
1654
+ refreshToken: string;
1655
+ customer: PublicCustomer;
1656
+ }
1657
+ export interface RefreshCustomerTokenParams {
1658
+ refreshToken: string;
1659
+ }
1660
+ /** One of the signed-in customer's orders. */
1661
+ export interface PublicCustomerOrder {
1662
+ orderId: string;
1663
+ orderNumber: number;
1664
+ /** Its delivery's tracking number (`K7P-QX9-M2T`): with the order's email it opens the order on the tracking page. Null: not a delivery, or the shop does not let guests track. */
1665
+ trackingCode: string | null;
1666
+ paidAt: string;
1667
+ /** Minor units of `currency`. */
1668
+ totalCents: number;
1669
+ /** Refunded so far, minor units — zero for almost every order. */
1670
+ refundedCents: number;
1671
+ currency: string;
1672
+ /** Where it stands: being made / handed over, done, or called off. */
1673
+ status: "open" | "completed" | "cancelled";
1674
+ /** The step the shop has the order at, in the shop's own words. */
1675
+ state: string;
1676
+ orderType: string | null;
1677
+ locationName: string | null;
1678
+ /** Where a delivered order goes, with any flat or gate details; null when it is collected. */
1679
+ deliveryAddress?: string | null;
1680
+ /** How many things were ordered, quantities added up. */
1681
+ itemCount: number;
1682
+ /** The products in it, each once, first ordered first — thumbnails for a list. */
1683
+ productIds: string[];
1684
+ /** How far the shop has got; null once completed or cancelled. */
1685
+ progress: PublicCustomerOrderProgress | null;
1686
+ /** A delivered order's delivery number (`D-17`); null for any other order. */
1687
+ deliveryNumber?: string | null;
1688
+ /** Shipped by a carrier: who has it and where to follow it. Null until the shop ships it. */
1689
+ shipment?: PublicCustomerOrderShipment | null;
1690
+ /**
1691
+ * A delivered order's delivery: `pending`, `ready`, `picked_up` (on its way), `delivered`,
1692
+ * `failed` or `cancelled`; null for any other order. While it is on its way, `progress` ends
1693
+ * with a delivery stage.
1694
+ */
1695
+ deliveryStatus?: "pending" | "ready" | "picked_up" | "delivered" | "failed" | "cancelled" | null;
1696
+ }
1697
+ /** A parcel handed to a carrier. */
1698
+ export interface PublicCustomerOrderShipment {
1699
+ /** Who carries it (`NZ Post`). */
1700
+ carrier: string;
1701
+ trackingNumber: string;
1702
+ /** The carrier's own tracking page; null when the shop gave none. */
1703
+ trackingUrl: string | null;
1704
+ shippedAt: string;
1705
+ }
1706
+ /**
1707
+ * Find a placed order for a tracking page: `number` - the order's (`1042`, `#1042`) or its
1708
+ * delivery's (`D-17`) - together with the `email` it was placed with; or `checkoutId` alone (the
1709
+ * confirmation link's id). Those are the credential: no customer token is involved.
1710
+ */
1711
+ export interface TrackOrderParams {
1712
+ /** The delivery's tracking number (`K7P-QX9-M2T`) - with `email`. */
1713
+ code?: string;
1714
+ /** The email the order was placed with - with `code`. */
1715
+ email?: string;
1716
+ /** The confirmation link's checkout id - enough on its own. */
1717
+ checkoutId?: string;
1718
+ }
1719
+ /** Where an open order is in the shop's own workflow. */
1720
+ export interface PublicCustomerOrderProgress {
1721
+ /** The shop's working states, in its order — the endings ("Delivered") left out. */
1722
+ steps: string[];
1723
+ /** Index into `steps`; -1 before the shop picked it up, `steps.length` once the work is done. */
1724
+ current: number;
1725
+ }
1726
+ /** One line of a customer's order, as charged. Money in minor units. */
1727
+ export interface PublicCustomerOrderLine {
1728
+ /** Null on a combo line, and once the product is deleted. */
1729
+ productId: string | null;
1730
+ variantId: string | null;
1731
+ /** Set on a combo line. */
1732
+ comboId: string | null;
1733
+ /** The site's own configuration of the line, as the cart was sent it — to add it again. */
1734
+ variant: string;
1735
+ name: string;
1736
+ variantName: string | null;
1737
+ /** Size, extras — as the receipt says it. */
1738
+ detail: string;
1739
+ quantity: number;
1740
+ unitPriceCents: number;
1741
+ discountCents: number;
1742
+ /** `unitPrice × quantity − discount`. */
1743
+ totalCents: number;
1744
+ }
1745
+ /** One of the signed-in customer's orders, in full. */
1746
+ export interface PublicCustomerOrderDetail extends PublicCustomerOrder {
1747
+ subtotalCents: number;
1748
+ discountCents: number;
1749
+ taxCents: number;
1750
+ taxName: string;
1751
+ taxInclusive: boolean;
1752
+ paymentMethod: string;
1753
+ /** Who a delivered order is handed to, and the number the driver calls; null when collected. */
1754
+ recipientName?: string | null;
1755
+ recipientPhone?: string | null;
1756
+ readyBy: string | null;
1757
+ /**
1758
+ * When a delivery should be at the door - only while the shop tells its customers when a
1759
+ * delivery comes; null otherwise, and for an order that is not a delivery.
1760
+ */
1761
+ deliverBy?: string | null;
1762
+ scheduledFor: string | null;
1763
+ completedAt: string | null;
1764
+ cancelledAt: string | null;
1765
+ lines: PublicCustomerOrderLine[];
1766
+ }
1767
+ /** One of the signed-in customer's bookings. */
1768
+ export interface PublicCustomerBooking {
1769
+ bookingId: string;
1770
+ /** The booking's own number (`12`) - what your links name it by; taken wherever a `bookingId` is. */
1771
+ bookingNumber: number | null;
1772
+ /** Its location's number (`2`). */
1773
+ locationNumber: number | null;
1774
+ startsAt: string;
1775
+ durationMinutes: number;
1776
+ partySize: number;
1777
+ /** waiting, confirmed, seated, finished, cancelled, no_show. */
1778
+ status: string;
1779
+ locationId: string | null;
1780
+ locationName: string | null;
1781
+ /** The tables held, by their labels; empty for a time-only booking. */
1782
+ tables: string[];
1783
+ /** The entry booked - a specialist - by name, and its picture; null otherwise. */
1784
+ entryName?: string | null;
1785
+ entryImage?: string | null;
1786
+ /** What the visit is for - the product (a treatment), in the shop's language. */
1787
+ productName?: string | null;
1788
+ /** What the customer typed when booking online - never the shop's own notes about them. */
1789
+ notes: string;
1790
+ /**
1791
+ * Until when the customer may still call it off themselves (`cancelBooking`) - the shop's
1792
+ * notice before the start, applied by the server; null: no longer theirs to cancel for free.
1793
+ */
1794
+ cancellableUntil?: string | null;
1795
+ /**
1796
+ * Whether they may call it off now: free until `cancellableUntil`, and after it for
1797
+ * `cancelFee` where the shop charges a late-cancellation fee and the booking was paid.
1798
+ */
1799
+ canCancel?: boolean;
1800
+ /**
1801
+ * What cancelling now costs, in the currency's smallest unit - kept from the booking's payment,
1802
+ * the rest refunded. Null while it is free. Say it before they confirm.
1803
+ */
1804
+ cancelFee?: {
1805
+ feeCents: number;
1806
+ currency: string;
1807
+ } | null;
1808
+ /**
1809
+ * Held while it is paid for (`pending`): the shop's payment page to finish on - a path to
1810
+ * resolve against the page's own address, like `createBooking`'s `payment.checkoutUrl`.
1811
+ */
1812
+ paymentUrl?: string | null;
1813
+ /**
1814
+ * The order attached to it - placed at checkout for the booking (`paid`), or its draft, paid at
1815
+ * the table and changeable with `setCustomerBookingPreorder` until `cancellableUntil` - or null.
1816
+ */
1817
+ preorder?: PublicBookingPreorder | null;
1818
+ }
1819
+ /** One dish ordered ahead for a booking. Money in minor units. */
1820
+ export interface PublicBookingPreorderLine {
1821
+ /** Null once the product is deleted. */
1822
+ productId: string | null;
1823
+ name: string;
1824
+ quantity: number;
1825
+ unitPriceCents: number;
1826
+ /** `unitPrice × quantity − discount`. */
1827
+ totalCents: number;
1828
+ }
1829
+ /**
1830
+ * The order attached to a booking: placed at checkout for it (`createCheckout` with
1831
+ * `bookingId`; `paid`), or its draft - paid at the table, changeable with
1832
+ * `setCustomerBookingPreorder`.
1833
+ */
1834
+ export interface PublicBookingPreorder {
1835
+ orderId: string;
1836
+ orderNumber: number;
1837
+ lines: PublicBookingPreorderLine[];
1838
+ /** Minor units of `currency`. */
1839
+ totalCents: number;
1840
+ currency: string;
1841
+ /** Placed and paid (online or at the counter); false: a draft, paid at the table. */
1842
+ paid: boolean;
1843
+ }
1844
+ /** Every dish to order ahead for a booking and how many, replacing what was there. */
1845
+ export interface SetBookingPreorderParams extends CustomerTokenParams {
1846
+ /** The booking - its `bookingNumber` (`12`) or its `bookingId`. */
1847
+ bookingId: string | number;
1848
+ /** A product of the shop, on sale, 1 to 99 of it; empty: no preorder. At most 50 lines. */
1849
+ lines: {
1850
+ productId: string;
1851
+ quantity: number;
1852
+ }[];
1853
+ }
1854
+ /** A page of a customer's history. */
1855
+ export interface CustomerPage<T> {
1856
+ data: T[];
1857
+ pagination: {
1858
+ page: number;
1859
+ limit: number;
1860
+ hasNext: boolean;
1861
+ };
1862
+ }
1863
+ export interface CustomerHistoryParams {
1864
+ page?: number;
1865
+ /** At most 50; 20 by default. */
1866
+ limit?: number;
1867
+ }
1868
+ export interface CustomerBookingsParams extends CustomerHistoryParams {
1869
+ /** `upcoming` (default): still ahead, soonest first. `past`: over or called off, latest first. */
1870
+ scope?: "upcoming" | "past" | "all";
1871
+ }
1872
+ /**
1873
+ * The signed-in customer, with their latest five orders and next five bookings — an account
1874
+ * page's first screen. The full lists: `getCustomerOrders`, `getCustomerBookings`.
1875
+ */
1876
+ export interface PublicCustomerAccount extends PublicCustomer {
1877
+ orders: PublicCustomerOrder[];
1878
+ bookings: PublicCustomerBooking[];
1879
+ }
1880
+ export interface RequestSignInCodeParams {
1881
+ email: string;
1882
+ }
1883
+ export interface VerifySignInCodeParams {
1884
+ email: string;
1885
+ /** The six digits from the email. */
1886
+ code: string;
1887
+ }
1888
+ export interface SignInWithGoogleParams {
1889
+ /** The ID token (`credential`) Google Identity Services gave the page. */
1890
+ idToken: string;
1891
+ }
1892
+ export interface SignInWithAppleParams {
1893
+ /** The ID token (`credential`) the platform's Apple sign-in page posted back. */
1894
+ idToken: string;
1895
+ /**
1896
+ * The person's "First Last", which Apple posts beside the token on the FIRST sign-in only -
1897
+ * the token never carries it. Leave it out when there is none.
1898
+ */
1899
+ name?: string | null;
1900
+ }
1901
+ export interface CustomerTokenParams {
1902
+ /** The token from `verifySignInCode`, `signInWithGoogle` or `signInWithApple`. */
1903
+ customerToken: string;
1904
+ }
1905
+ /**
1906
+ * A place the signed-in customer has had an order delivered to, or saved themselves. One per
1907
+ * address and details: the same one again only moves `lastUsedAt`.
1908
+ */
1909
+ export interface PublicCustomerAddress {
1910
+ customerAddressId: string;
1911
+ /** The address as it was picked - one line. */
1912
+ address: string;
1913
+ /** Flat, floor, gate code - whatever the driver needs on top of the address. */
1914
+ details: string | null;
1915
+ /** Where it is; null for an address kept without a point. */
1916
+ latitude: number | null;
1917
+ longitude: number | null;
1918
+ postcode: string | null;
1919
+ /** ISO 8601. The list is ordered by it, the one used last first. */
1920
+ lastUsedAt: string;
1921
+ }
1922
+ /**
1923
+ * A card the signed-in customer saved paying at this shop: what it is and when it expires.
1924
+ * Nothing in it can pay - the card stays with Stripe, and `id` is only a handle for removing it.
1925
+ */
1926
+ export interface PublicCustomerPaymentMethod {
1927
+ /** A handle for `deleteCustomerPaymentMethod` - not Stripe's id, and of no use to pay with. */
1928
+ id: string;
1929
+ /** Stripe's card brand: `visa`, `mastercard`, `amex`... */
1930
+ brand: string;
1931
+ last4: string;
1932
+ expMonth: number;
1933
+ expYear: number;
1934
+ /** The wallet it was added from (`apple_pay`, `google_pay`), if any. */
1935
+ wallet: string | null;
1936
+ /** An upcoming booking keeps it (a late-cancellation fee): it cannot be removed until then. */
1937
+ inUse: boolean;
1938
+ }
1939
+ /** An address to save, as a checkout gives one: the address, and its point when known. */
1940
+ export interface AddCustomerAddressParams extends CustomerTokenParams {
1941
+ address: string;
1942
+ details?: string | null;
1943
+ latitude?: number | null;
1944
+ longitude?: number | null;
1945
+ postcode?: string | null;
1946
+ }
1947
+ export interface UpdateCustomerProfileParams extends CustomerTokenParams {
1948
+ name?: string | null;
1949
+ phone?: string | null;
1950
+ /** `YYYY-MM-DD`, in the past. */
1951
+ dateOfBirth?: string | null;
1952
+ /**
1953
+ * True: the customer accepts the shop's terms (`getTerms()`) - kept with its time, from the
1954
+ * first time. Only ever from a box they ticked themselves.
1955
+ */
1956
+ acceptTerms?: boolean;
1957
+ /** True: they consent to the shop keeping health information; false: withdrawn. */
1958
+ healthConsent?: boolean;
1959
+ /**
1960
+ * The language they just chose to read the shop in, an ISO code - kept on their account and
1961
+ * answered as `PublicCustomer.language` wherever they sign in. Null forgets it.
1962
+ */
1963
+ language?: string | null;
1964
+ }
1965
+ /** Money off for paying one way: an amount in MINOR units of the shop's currency, or a percent. */
1966
+ export interface PublicPaymentDiscount {
1967
+ kind: "amount" | "percent";
1968
+ value: number;
1969
+ }
1970
+ /** The discount for each way of paying, or null for none. */
1971
+ export interface PublicPaymentDiscounts {
1972
+ online: PublicPaymentDiscount | null;
1973
+ inStore: PublicPaymentDiscount | null;
1974
+ }
1975
+ /**
1976
+ * How customers vote, as the shop set it (Sales rules → Social): not at all, a like only (`up` -
1977
+ * no dislikes; its votes read as `like`, with `dislikes` 0), a like or a dislike, or stars.
1978
+ */
1979
+ export type ProductVoting = "off" | "up" | "like" | "range";
1980
+ /**
1981
+ * The votes on a product, the shop's way: stars (`range` - `average` of up to `max`) or likes
1982
+ * (`likes` and `dislikes`), and the viewer's own.
1983
+ */
1984
+ export interface PublicProductRating {
1985
+ method: "like" | "range";
1986
+ /** Average stars, to one decimal; null before anyone rated. */
1987
+ average: number | null;
1988
+ /** Customers who voted on it. */
1989
+ count: number;
1990
+ /** The top of the scale - 1 for likes. */
1991
+ max: number;
1992
+ likes: number;
1993
+ dislikes: number;
1994
+ /** The signed-in customer's own vote - stars, or 1 / -1; null when none. */
1995
+ mine: number | null;
1996
+ }
1997
+ /**
1998
+ * What a product takes - comments, stars, likes on comments - and what has been said. The
1999
+ * shop turns each on in its product settings; a product that takes none answers all `false`.
2000
+ */
2001
+ export interface PublicProductFeedback {
2002
+ allowComments: boolean;
2003
+ allowRating: boolean;
2004
+ allowCommentVotes: boolean;
2005
+ /** How customers vote on this product - `off` when they don't. */
2006
+ productVoting: ProductVoting;
2007
+ /** How customers vote on its comments - `off` when they don't (always, without comments). */
2008
+ commentVoting: ProductVoting;
2009
+ /** How many stars a comment is rated out of, while `commentVoting` is `range`. */
2010
+ commentStars: number;
2011
+ /** Comments and replies, together. */
2012
+ commentCount: number;
2013
+ rating: PublicProductRating;
2014
+ /**
2015
+ * A vote comes with a comment (Sales rules → Social): `rateProduct` is refused
2016
+ * (`vote_needs_comment`) until the customer has a comment of their own on the product - cast
2017
+ * it with the comment instead (`createProductComment`'s `vote`). Deleting their last comment
2018
+ * takes their vote back. Only while comments and product votes are both on.
2019
+ */
2020
+ voteNeedsComment: boolean;
2021
+ }
2022
+ /** One comment on a product, or a reply to one. Threads are one level deep. */
2023
+ export interface PublicProductComment {
2024
+ id: string;
2025
+ /** The root it replies to, or null for a root. */
2026
+ parentId: string | null;
2027
+ body: string;
2028
+ /** ISO timestamp. */
2029
+ createdAt: string;
2030
+ /** Replies under this root (0 on a reply). */
2031
+ replyCount: number;
2032
+ likes: number;
2033
+ dislikes: number;
2034
+ /** Average stars, while comments are voted on with stars; null before anyone rated. */
2035
+ ratingAverage: number | null;
2036
+ ratingCount: number;
2037
+ /**
2038
+ * Who wrote it. `fromShop`: the shop's own reply, written in its admin - `name` is then the
2039
+ * shop's name; mark it as the shop's.
2040
+ */
2041
+ author: {
2042
+ name: string | null;
2043
+ avatarUrl: string | null;
2044
+ fromShop: boolean;
2045
+ };
2046
+ /** The signed-in customer's vote on it: 1 / -1, or stars; 0 for none. */
2047
+ myVote: number;
2048
+ /**
2049
+ * The author's own vote on the product - stars, or 1 / -1 - for a review's stars or thumb
2050
+ * beside the name. Null when they cast none, and always on a reply.
2051
+ */
2052
+ authorVote: number | null;
2053
+ /** Written by the signed-in customer - they may delete it. */
2054
+ mine: boolean;
2055
+ }
2056
+ /** A page of comments. `total` counts every comment the page is a slice of. */
2057
+ export interface PublicProductCommentsPage {
2058
+ data: PublicProductComment[];
2059
+ pagination: {
2060
+ page: number;
2061
+ limit: number;
2062
+ hasNext: boolean;
2063
+ };
2064
+ total: number;
2065
+ }
2066
+ export interface GetProductFeedbackParams {
2067
+ productId: string;
2068
+ /** A signed-in customer, for their own stars. */
2069
+ customerToken?: string;
2070
+ }
2071
+ export interface GetProductCommentsParams {
2072
+ productId: string;
2073
+ /** A root comment: its replies, oldest first. Without it, the roots, newest first. */
2074
+ parentId?: string;
2075
+ page?: number;
2076
+ /** Up to 50; 20 by default. */
2077
+ limit?: number;
2078
+ /** A signed-in customer, for `mine` and `myVote`. */
2079
+ customerToken?: string;
2080
+ }
2081
+ export interface CreateProductCommentParams extends CustomerTokenParams {
2082
+ productId: string;
2083
+ /** Up to 2000 characters. */
2084
+ body: string;
2085
+ /** The comment this replies to - a reply to a reply is filed under the same root. */
2086
+ parentId?: string;
2087
+ /**
2088
+ * The customer's vote on the product, cast with the comment (a review) - the shop's way, as
2089
+ * `RateProductParams.value`. A root comment only; required in practice while
2090
+ * `voteNeedsComment` is on, as `rateProduct` alone is refused then.
2091
+ */
2092
+ vote?: number;
2093
+ }
2094
+ /** A comment's votes after one was cast. */
2095
+ export interface PublicCommentVoteResult {
2096
+ likes: number;
2097
+ dislikes: number;
2098
+ ratingAverage: number | null;
2099
+ ratingCount: number;
2100
+ myVote: number;
2101
+ }
2102
+ export interface RateProductParams extends CustomerTokenParams {
2103
+ productId: string;
2104
+ /**
2105
+ * The shop's way (`productVoting`): 1 to `rating.max` stars, or 1 like / -1 dislike - a like
2106
+ * (1) only, under `up`.
2107
+ */
2108
+ value: number;
2109
+ }
2110
+ export interface UnrateProductParams extends CustomerTokenParams {
2111
+ productId: string;
2112
+ }
2113
+ export interface VoteProductCommentParams extends CustomerTokenParams {
2114
+ productId: string;
2115
+ commentId: string;
2116
+ /** The shop's way (`commentVoting`): 1 / -1, or 1 to `commentStars`; 0 takes it back. */
2117
+ value: number;
2118
+ }
2119
+ export interface DeleteProductCommentParams extends CustomerTokenParams {
2120
+ productId: string;
2121
+ /** One of the customer's own comments. A root goes with its replies. */
2122
+ commentId: string;
2123
+ }