@v-office/website-sdk 2.0.0 → 2.1.1

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 (46) hide show
  1. package/README.md +33 -31
  2. package/dist/cli.mjs +6 -4
  3. package/dist/{client-BSUd3vuc.mjs → client-xkXV7Nf-.mjs} +32 -16
  4. package/dist/index.d.mts +613 -1140
  5. package/dist/index.mjs +3 -3
  6. package/dist/instructions/CHANGELOG.md +1 -0
  7. package/dist/instructions/MIGRATION.md +1 -0
  8. package/dist/instructions/README.md +14 -12
  9. package/dist/instructions/availability.md +9 -9
  10. package/dist/instructions/booking.md +33 -33
  11. package/dist/instructions/contact.md +34 -16
  12. package/dist/instructions/creation.md +48 -48
  13. package/dist/instructions/document-structured-json.md +100 -0
  14. package/dist/instructions/filter.md +5 -3
  15. package/dist/instructions/quote.md +72 -48
  16. package/dist/instructions/rentals.md +3 -3
  17. package/dist/instructions/search.md +36 -31
  18. package/dist/instructions/versions/2.0.0/MIGRATION.md +17 -17
  19. package/dist/instructions/versions/2.1.0/CHANGELOG.md +32 -0
  20. package/dist/instructions/versions/2.1.0/MIGRATION.md +89 -0
  21. package/dist/{quote-1uEIO44v.mjs → quote--25SMlYS.mjs} +27 -4
  22. package/dist/{rentals-Quwc78o2.mjs → rentals-DCKUaLnB.mjs} +1 -1
  23. package/dist/{search-GRQeXDvo.mjs → search-8iCC0Nel.mjs} +2 -2
  24. package/dist/{to-rental-highlights-FNZBR4aD.mjs → to-rental-highlights-CZYJeR1D.mjs} +12 -12
  25. package/dist/translations/shared/de-DE/contact.json +19 -0
  26. package/dist/translations/shared/de-DE/quote.json +5 -1
  27. package/dist/translations/shared/en-US/contact.json +19 -0
  28. package/dist/translations/shared/en-US/quote.json +5 -1
  29. package/dist/translations/v10/de-DE/mapped-search-filters.json +3 -0
  30. package/dist/translations/v10/en-US/mapped-search-filters.json +3 -0
  31. package/instructions/CHANGELOG.md +1 -0
  32. package/instructions/MIGRATION.md +1 -0
  33. package/instructions/README.md +14 -12
  34. package/instructions/availability.md +9 -9
  35. package/instructions/booking.md +33 -33
  36. package/instructions/contact.md +34 -16
  37. package/instructions/creation.md +48 -48
  38. package/instructions/document-structured-json.md +100 -0
  39. package/instructions/filter.md +5 -3
  40. package/instructions/quote.md +72 -48
  41. package/instructions/rentals.md +3 -3
  42. package/instructions/search.md +36 -31
  43. package/instructions/versions/2.0.0/MIGRATION.md +17 -17
  44. package/instructions/versions/2.1.0/CHANGELOG.md +32 -0
  45. package/instructions/versions/2.1.0/MIGRATION.md +89 -0
  46. package/package.json +4 -3
@@ -5,36 +5,36 @@
5
5
  Use the live quote API to price a stay and get selectable booking options:
6
6
 
7
7
  ```ts
8
- const result = await sdk.live.quote.quote(input)
8
+ const result = await sdk.live.quote.quote(input);
9
9
  ```
10
10
 
11
11
  If the quote is available, the returned `GuestQuote` can be updated through selection helpers:
12
12
 
13
13
  ```ts
14
- const withService = await sdk.live.quote.addAdditionalService({ quote, id: 'linen' })
15
- const withPolicy = await sdk.live.quote.selectCancellationPolicy({ quote, id: 'alternative' })
14
+ const withService = await sdk.live.quote.addAdditionalService({ quote, id: "linen" });
15
+ const withPolicy = await sdk.live.quote.selectCancellationPolicy({ quote, id: "alternative" });
16
16
  ```
17
17
 
18
18
  ## Input
19
19
 
20
20
  ```ts
21
21
  type QuoteQuoteInput = {
22
- locale: 'de-DE' | 'en-US'
23
- rentalId: string
22
+ locale: "de-DE" | "en-US";
23
+ rentalId: string;
24
24
  period: {
25
- start: string
26
- end: string
27
- }
25
+ start: string;
26
+ end: string;
27
+ };
28
28
  occupancy: {
29
- adults: number
30
- children: number
31
- childrenAges?: number[]
32
- babies: number
33
- pets: number
34
- }
35
- destinationCountryCode?: string
36
- voucher?: string
37
- }
29
+ adults: number;
30
+ children: number;
31
+ childrenAges?: number[];
32
+ babies: number;
33
+ pets: number;
34
+ };
35
+ destinationCountryCode?: string;
36
+ voucher?: string;
37
+ };
38
38
  ```
39
39
 
40
40
  `GuestQuoteInput` remains available as a legacy alias.
@@ -62,6 +62,7 @@ Sample:
62
62
  ```
63
63
 
64
64
  Dates are local dates formatted as `YYYY-MM-DD`. For `v9`, `rentalId` must be a numeric vOffice unit id.
65
+ Both backends accept `voucher` on quote and booking flows. `v10` can expose voucher discounts as booking-card modifiers when the backend returns voucher modifiers; `v9` reflects voucher effects in the quoted totals but does not expose a separate voucher modifier line.
65
66
 
66
67
  ## Output
67
68
 
@@ -88,6 +89,11 @@ Available sample:
88
89
  ],
89
90
  "total": "1,200.00 EUR"
90
91
  },
92
+ "voucher": {
93
+ "code": "SUMMER26",
94
+ "status": "applied",
95
+ "message": "The voucher code was applied."
96
+ },
91
97
  "additionalServices": [
92
98
  {
93
99
  "id": "linen",
@@ -131,7 +137,23 @@ Unavailable sample:
131
137
  }
132
138
  ```
133
139
 
134
- Selection methods return `{ ok: true, quote }` or `{ ok: false, error }`. Possible selection errors include unknown additional service, additional service limit exceeded, unknown cancellation policy, and unavailable cancellation policy quote.
140
+ Selection methods return `{ ok: true, quote }` or `{ ok: false, error }`. Possible selection errors include unknown additional service, additional service limit exceeded, unknown cancellation policy, unavailable cancellation policy quote, and unavailable quote combination.
141
+
142
+ ## Vouchers
143
+
144
+ When `voucher` is provided in the quote input, an available quote may include `quote.voucher`:
145
+
146
+ ```json
147
+ {
148
+ "code": "SUMMER26",
149
+ "status": "applied",
150
+ "message": "The voucher code was applied."
151
+ }
152
+ ```
153
+
154
+ `status` is `"applied"`, `"not_applied"`, or `"unknown"`. `v10` reports `"applied"` when the backend returns a non-zero voucher modifier and `"not_applied"` when no voucher modifier is returned for the requested voucher. `v9` returns `"unknown"` for available voucher quotes because the legacy response does not provide a reliable voucher modifier signal.
155
+
156
+ Voucher modifiers can appear in `bookingCardInformation.sections`. Sections are returned in display order.
135
157
 
136
158
  ## Additional Services
137
159
 
@@ -142,6 +164,7 @@ Additional services are exposed on an available quote as `quote.additionalServic
142
164
  "id": "linen",
143
165
  "label": "Bed linen",
144
166
  "charge": "25.00 EUR",
167
+ "available": true,
145
168
  "maxPerBooking": 1,
146
169
  "description": "Bed linen package"
147
170
  }
@@ -150,17 +173,17 @@ Additional services are exposed on an available quote as `quote.additionalServic
150
173
  Use the service `id` to add or remove a service selection:
151
174
 
152
175
  ```ts
153
- const added = await sdk.live.quote.addAdditionalService({ quote, id: 'linen' })
154
- if (added.ok) quote = added.quote
176
+ const added = await sdk.live.quote.addAdditionalService({ quote, id: "linen" });
177
+ if (added.ok) quote = added.quote;
155
178
 
156
- const removed = await sdk.live.quote.removeAdditionalService({ quote, id: 'linen' })
157
- if (removed.ok) quote = removed.quote
179
+ const removed = await sdk.live.quote.removeAdditionalService({ quote, id: "linen" });
180
+ if (removed.ok) quote = removed.quote;
158
181
 
159
- const cleared = await sdk.live.quote.clearAdditionalServices({ quote })
160
- if (cleared.ok) quote = cleared.quote
182
+ const cleared = await sdk.live.quote.clearAdditionalServices({ quote });
183
+ if (cleared.ok) quote = cleared.quote;
161
184
  ```
162
185
 
163
- Each successful change returns a new quote with recalculated `bookingCardInformation.total`. Handle `{ ok: false, error }` for unknown service ids or quantity limits.
186
+ Each successful change returns a new quote with recalculated `bookingCardInformation.total`. v10 can mark unavailable service/policy combinations with `available: false` and `unavailableReason`; disable those options in the UI. Handle `{ ok: false, error }` for unknown service ids, quantity limits, or `UnavailableQuoteCombination`.
164
187
 
165
188
  ## Cancellation Policies
166
189
 
@@ -171,6 +194,7 @@ Cancellation policies are exposed on `quote.cancellationPolicies` when the backe
171
194
  "id": "alternative",
172
195
  "label": "Flexible cancellation",
173
196
  "selected": false,
197
+ "available": true,
174
198
  "markUpPercentage": "10%",
175
199
  "processingFee": "25.00 EUR",
176
200
  "rules": [
@@ -187,10 +211,10 @@ Select a policy by id:
187
211
  ```ts
188
212
  const selected = await sdk.live.quote.selectCancellationPolicy({
189
213
  quote,
190
- id: 'alternative',
191
- })
214
+ id: "alternative",
215
+ });
192
216
 
193
- if (selected.ok) quote = selected.quote
217
+ if (selected.ok) quote = selected.quote;
194
218
  ```
195
219
 
196
220
  The selected policy is marked with `selected: true`, and the booking card total is recalculated if the policy changes the price. Handle selection errors for unknown or unavailable policy ids.
@@ -228,18 +252,18 @@ Use `selectInsurance` to choose no insurance or a product:
228
252
  quote = await sdk.live.quote.selectInsurance({
229
253
  quote,
230
254
  selection: {
231
- kind: 'insurance',
232
- id: 'ergo',
255
+ kind: "insurance",
256
+ id: "ergo",
233
257
  travelers: [
234
258
  {
235
- salutation: 'Ms',
236
- forename: 'Jane',
237
- surname: 'Doe',
238
- birthday: '1990-01-01',
259
+ salutation: "Ms",
260
+ forename: "Jane",
261
+ surname: "Doe",
262
+ birthday: "1990-01-01",
239
263
  },
240
264
  ],
241
265
  },
242
- })
266
+ });
243
267
  ```
244
268
 
245
269
  For insurance products that require a pre-contract, provide customer information:
@@ -248,18 +272,18 @@ For insurance products that require a pre-contract, provide customer information
248
272
  quote = await sdk.live.quote.createInsurancePreContract({
249
273
  quote,
250
274
  customerInformation: {
251
- destinationCountryCode: 'DE',
275
+ destinationCountryCode: "DE",
252
276
  address: {
253
- street: 'Main Street',
254
- housenumber: '1',
255
- postalcode: '12345',
256
- city: 'Berlin',
257
- countryCode: 'DE',
277
+ street: "Main Street",
278
+ housenumber: "1",
279
+ postalcode: "12345",
280
+ city: "Berlin",
281
+ countryCode: "DE",
258
282
  },
259
- email: 'jane@example.com',
260
- mobile: '+49123456789',
283
+ email: "jane@example.com",
284
+ mobile: "+49123456789",
261
285
  },
262
- })
286
+ });
263
287
  ```
264
288
 
265
289
  Select an insurance payment method before booking insurance:
@@ -268,10 +292,10 @@ Select an insurance payment method before booking insurance:
268
292
  quote = await sdk.live.quote.selectInsurancePayment({
269
293
  quote,
270
294
  paymentInformation: {
271
- kind: 'sepa_debit',
272
- iban: 'DE02120300000000202051',
295
+ kind: "sepa_debit",
296
+ iban: "DE02120300000000202051",
273
297
  },
274
- })
298
+ });
275
299
  ```
276
300
 
277
301
  After the rental booking is created, complete insurance booking with the booking number and guest token:
@@ -281,7 +305,7 @@ const insuranceBooking = await sdk.live.quote.bookInsurance({
281
305
  quote,
282
306
  bookingNumber: booking.bookingNumber,
283
307
  guestToken: booking.guestToken,
284
- })
308
+ });
285
309
  ```
286
310
 
287
311
  `v9` supports real insurance option refresh, pre-contract, payment selection, and booking. `v10` currently returns a no-insurance placeholder and insurance actions resolve as not required.
@@ -5,7 +5,7 @@
5
5
  Use the static rentals API to fetch localized rental summaries:
6
6
 
7
7
  ```ts
8
- const rentals = await sdk.static.rentals.getRentals({ locale: 'de-DE' })
8
+ const rentals = await sdk.static.rentals.getRentals({ locale: "de-DE" });
9
9
  ```
10
10
 
11
11
  The service is implemented for both `v9` and `v10` backends and returns one normalized item per rental.
@@ -14,8 +14,8 @@ The service is implemented for both `v9` and `v10` backends and returns one norm
14
14
 
15
15
  ```ts
16
16
  type RentalRentalsInput = {
17
- locale: 'de-DE' | 'en-US'
18
- }
17
+ locale: "de-DE" | "en-US";
18
+ };
19
19
  ```
20
20
 
21
21
  Sample:
@@ -6,9 +6,9 @@ Use the live search API to search rentals with a URL query-string style input:
6
6
 
7
7
  ```ts
8
8
  const result = await sdk.live.search.search({
9
- locale: 'de-DE',
10
- query: 'start=01-07-2026&end=08-07-2026&adults=2&wifi=true',
11
- })
9
+ locale: "de-DE",
10
+ query: "start=01-07-2026&end=08-07-2026&adults=2&wifi=true",
11
+ });
12
12
  ```
13
13
 
14
14
  The service is implemented for both `v9` and `v10` backends and returns normalized rental result items. Filtering by `rentalIdsIn` is currently implemented for `v10` only.
@@ -17,12 +17,13 @@ The service is implemented for both `v9` and `v10` backends and returns normaliz
17
17
 
18
18
  ```ts
19
19
  type RentalSearchInput = {
20
- locale: 'de-DE' | 'en-US'
21
- query: string
22
- rentalIdsIn?: readonly string[]
23
- limit?: number
24
- cursor?: string
25
- }
20
+ locale: "de-DE" | "en-US";
21
+ query: string;
22
+ rentalIdsIn?: readonly string[];
23
+ voucher?: string;
24
+ limit?: number;
25
+ cursor?: string;
26
+ };
26
27
  ```
27
28
 
28
29
  Sample:
@@ -32,6 +33,7 @@ Sample:
32
33
  "locale": "de-DE",
33
34
  "query": "start=01-07-2026&end=08-07-2026&adults=2&children=1&wifi=true",
34
35
  "rentalIdsIn": ["123", "456"],
36
+ "voucher": "SUMMER26",
35
37
  "limit": 20
36
38
  }
37
39
  ```
@@ -49,7 +51,7 @@ The `query` field is a URL query-string style value without a leading `?`.
49
51
  Use `&` to combine period, occupancy, and filter parameters:
50
52
 
51
53
  ```ts
52
- 'start=20-06-2026&end=27-06-2026&adults=2&wifi'
54
+ "start=20-06-2026&end=27-06-2026&adults=2&wifi";
53
55
  ```
54
56
 
55
57
  ### Period Queries
@@ -59,25 +61,25 @@ Use one supported period structure per query.
59
61
  Exact period search:
60
62
 
61
63
  ```ts
62
- 'start=20-06-2026&end=27-06-2026'
64
+ "start=20-06-2026&end=27-06-2026";
63
65
  ```
64
66
 
65
67
  Flexible search by month:
66
68
 
67
69
  ```ts
68
- 'month=06-2026&nights=7'
69
- 'month=06-2026&month=07-2026&nights=7'
70
- 'month=06-2026&weekend'
71
- 'month=06-2026&month=07-2026&weekend'
70
+ "month=06-2026&nights=7";
71
+ "month=06-2026&month=07-2026&nights=7";
72
+ "month=06-2026&weekend";
73
+ "month=06-2026&month=07-2026&weekend";
72
74
  ```
73
75
 
74
76
  Flexible search by exact date tuples:
75
77
 
76
78
  ```ts
77
- 'dates=20-06-2026,22-06-2026&nights=2'
78
- 'dates=20-06-2026,22-06-2026&dates=04-07-2026,11-07-2026&nights=2'
79
- 'dates=20-06-2026,22-06-2026&weekend'
80
- 'dates=20-06-2026,22-06-2026&dates=04-07-2026,11-07-2026&weekend'
79
+ "dates=20-06-2026,22-06-2026&nights=2";
80
+ "dates=20-06-2026,22-06-2026&dates=04-07-2026,11-07-2026&nights=2";
81
+ "dates=20-06-2026,22-06-2026&weekend";
82
+ "dates=20-06-2026,22-06-2026&dates=04-07-2026,11-07-2026&weekend";
81
83
  ```
82
84
 
83
85
  ### Occupancy And Filters
@@ -85,16 +87,16 @@ Flexible search by exact date tuples:
85
87
  Append occupancy and filter parameters with `&`:
86
88
 
87
89
  ```ts
88
- 'start=20-06-2026&end=27-06-2026&adults=2'
89
- 'start=20-06-2026&end=27-06-2026&adults=2&childrenAges=5%2C13&babies=1&pets=1'
90
- 'start=20-06-2026&end=27-06-2026&adults=2&wifi'
90
+ "start=20-06-2026&end=27-06-2026&adults=2";
91
+ "start=20-06-2026&end=27-06-2026&adults=2&childrenAges=5%2C13&babies=1&pets=1";
92
+ "start=20-06-2026&end=27-06-2026&adults=2&wifi";
91
93
  ```
92
94
 
93
95
  Boolean filters can be provided as presence-only flags when supported:
94
96
 
95
97
  ```ts
96
- 'wifi'
97
- 'wifi&bbq=true'
98
+ "wifi";
99
+ "wifi&bbq=true";
98
100
  ```
99
101
 
100
102
  ### Invalid Combinations
@@ -102,27 +104,29 @@ Boolean filters can be provided as presence-only flags when supported:
102
104
  Do not mix exact period search with flexible period options:
103
105
 
104
106
  ```ts
105
- 'start=20-06-2026&end=27-06-2026&nights=7'
106
- 'start=20-06-2026&end=27-06-2026&weekend'
107
+ "start=20-06-2026&end=27-06-2026&nights=7";
108
+ "start=20-06-2026&end=27-06-2026&weekend";
107
109
  ```
108
110
 
109
111
  Do not mix `month` and `dates` in the same flexible query:
110
112
 
111
113
  ```ts
112
- 'month=06-2026&dates=20-06-2026,22-06-2026&nights=2'
114
+ "month=06-2026&dates=20-06-2026,22-06-2026&nights=2";
113
115
  ```
114
116
 
115
117
  Flexible queries require either `nights` or `weekend`, but not both:
116
118
 
117
119
  ```ts
118
- 'month=06-2026'
119
- 'dates=20-06-2026,22-06-2026'
120
- 'month=06-2026&nights=7&weekend'
120
+ "month=06-2026";
121
+ "dates=20-06-2026,22-06-2026";
122
+ "month=06-2026&nights=7&weekend";
121
123
  ```
122
124
 
123
125
  Dates should use `DD-MM-YYYY`; months should use `MM-YYYY`.
124
126
 
125
127
  Use `rentalIdsIn` to restrict results to specific rental IDs. This option is currently supported by `v10` only.
128
+ Use `voucher` to price v10 search results with a voucher code. This option is currently supported by `v10` only.
129
+ For v10, `pets` is a mapped BooleanFilter exposed by `getFilters` and maps to one pet; use `petsCount` for an exact count and do not send both keys in one query.
126
130
 
127
131
  `limit` defaults to `20`. Treat `cursor` as opaque and pass back `pageInfo.nextCursor` unchanged.
128
132
 
@@ -209,10 +213,11 @@ website-sdk --backend v10 search --locale de-DE --query "adults=2" --limit 10
209
213
  website-sdk --backend v10 search --locale de-DE --query "adults=2" --limit 10 --cursor "10"
210
214
  ```
211
215
 
212
- Restrict results to specific rental IDs with `--rental-ids-in` (`v10` only):
216
+ Restrict results to specific rental IDs or price with a voucher code (`v10` only):
213
217
 
214
218
  ```sh
215
219
  website-sdk --backend v10 search --locale de-DE --query "adults=2" --rental-ids-in "123,456"
220
+ website-sdk --backend v10 search --locale de-DE --query "adults=2" --voucher SUMMER26
216
221
  ```
217
222
 
218
223
  Use files instead of environment variables:
@@ -25,7 +25,7 @@ Legacy 1.x-style API:
25
25
  ## Package Import
26
26
 
27
27
  ```ts
28
- import { createWebsiteSDK, defineWebsiteSDKOptions } from '@v-office/website-sdk'
28
+ import { createWebsiteSDK, defineWebsiteSDKOptions } from "@v-office/website-sdk";
29
29
  ```
30
30
 
31
31
  The new package still exports `defineCMSSDKOptions` as an alias for `defineWebsiteSDKOptions`, but new code should use the Website naming.
@@ -35,41 +35,41 @@ The new package still exports `defineCMSSDKOptions` as an alias for `defineWebsi
35
35
  Before:
36
36
 
37
37
  ```ts
38
- import { createCMSSDKFromParsedConfig, defineCMSSDKOptions } from '@v-office/website-sdk'
38
+ import { createCMSSDKFromParsedConfig, defineCMSSDKOptions } from "@v-office/website-sdk";
39
39
 
40
40
  const sdk = createCMSSDKFromParsedConfig({
41
- backend: 'v10',
41
+ backend: "v10",
42
42
  v10: {
43
- apiEndpoint: 'https://api.example.com/graphql',
44
- accessToken: '...',
45
- imageBaseUrl: 'https://images.example.com',
43
+ apiEndpoint: "https://api.example.com/graphql",
44
+ accessToken: "...",
45
+ imageBaseUrl: "https://images.example.com",
46
46
  },
47
47
  options: defineCMSSDKOptions({
48
48
  rentalScope: {
49
- propertyId: 'property-1',
49
+ propertyId: "property-1",
50
50
  },
51
51
  }),
52
- })
52
+ });
53
53
  ```
54
54
 
55
55
  After:
56
56
 
57
57
  ```ts
58
- import { createWebsiteSDK, defineWebsiteSDKOptions } from '@v-office/website-sdk'
58
+ import { createWebsiteSDK, defineWebsiteSDKOptions } from "@v-office/website-sdk";
59
59
 
60
60
  const sdk = createWebsiteSDK({
61
61
  config: {
62
- backend: 'v10',
63
- apiEndpoint: 'https://api.example.com/graphql',
64
- accessToken: '...',
65
- imageBaseUrl: 'https://images.example.com',
62
+ backend: "v10",
63
+ apiEndpoint: "https://api.example.com/graphql",
64
+ accessToken: "...",
65
+ imageBaseUrl: "https://images.example.com",
66
66
  },
67
67
  options: defineWebsiteSDKOptions({
68
68
  rentalScope: {
69
- propertyId: 'property-1',
69
+ propertyId: "property-1",
70
70
  },
71
71
  }),
72
- })
72
+ });
73
73
  ```
74
74
 
75
75
  ## Config Shape
@@ -123,7 +123,7 @@ Several legacy domain aliases remain exported, including `BookingInput`, `Bookin
123
123
  Legacy errors exposed `CMSError` with a `backend` field:
124
124
 
125
125
  ```ts
126
- if (error instanceof CMSError && error.backend === 'v9') {
126
+ if (error instanceof CMSError && error.backend === "v9") {
127
127
  // legacy handling
128
128
  }
129
129
  ```
@@ -132,7 +132,7 @@ if (error instanceof CMSError && error.backend === 'v9') {
132
132
 
133
133
  ```ts
134
134
  if (error instanceof CoreSDKError) {
135
- console.error(error.source, error.operation, error.message)
135
+ console.error(error.source, error.operation, error.message);
136
136
  }
137
137
  ```
138
138
 
@@ -0,0 +1,32 @@
1
+ # Changelog: 2.1.0
2
+
3
+ Release date: 2026-07-08
4
+
5
+ This release extends the 2.0.0 website SDK facade without changing the flat config shape or main SDK construction API.
6
+
7
+ ## Added
8
+
9
+ - Added v10 legal document access through `sdk.static.documents.getTermsAndPrivacyPolicy({ locale })` and `getTermsAndPrivacyPolicyEffect`.
10
+ - Added `document-structured-json.md` instructions for legal document output and structured document rendering.
11
+ - Added v10 contact submission through `messengeremail_newContactRequest`, with shared validation for v9 and v10 contact requests.
12
+ - Added `validateContactSubmitInput`, `ContactSubmitValidationIssue`, and `ContactSubmitValidationIssueCode` exports.
13
+ - Added v10 search voucher pricing via `SearchSearchInput.voucher` and CLI `--voucher`.
14
+ - Added `quote.voucher` metadata for quoted voucher status.
15
+ - Added v10 mapped `pets` search filter, exposed by `static.filter.getFilters` as a localized BooleanFilter.
16
+ - Added backend-specific website SDK facade types such as `WebsiteSDKV9`, `WebsiteSDKV10`, `WebsiteSDKV10Static`, and `WebsiteSDKV10Live`.
17
+
18
+ ## Changed
19
+
20
+ - v10 quote multi-rate handling now marks unavailable additional services and cancellation policies with `available: false` and `unavailableReason`.
21
+ - Quote selection errors can now include `UnavailableQuoteCombination` when a selected add-on/policy combination cannot be priced.
22
+ - Booking card sections now use a stable display order so included lines, selected add-ons, taxes, modifiers, and fallback sections render predictably.
23
+ - Contact validation now rejects blank required fields, invalid email addresses, invalid country codes, and overly long values before backend submission.
24
+ - v9 contact submission now uses the same core contact input and validation path as v10.
25
+
26
+ ## Migration Impact
27
+
28
+ - No config migration is required from 2.0.0.
29
+ - Existing search calls continue to work; use `voucher` only for v10 voucher pricing and use either `pets` or `petsCount`, not both.
30
+ - Existing quote rendering should tolerate the new optional `voucher`, `available`, and `unavailableReason` fields.
31
+ - Existing quote selection error handling should add a fallback for `UnavailableQuoteCombination`.
32
+ - Existing contact forms should surface `CoreSDKError` validation issues from `error.cause.issues`.
@@ -0,0 +1,89 @@
1
+ # Migration: 2.0.0 to 2.1.0
2
+
3
+ This guide covers upgrading `@v-office/website-sdk` from 2.0.0 to 2.1.0.
4
+
5
+ 2.1.0 is a minor release. Keep using `createWebsiteSDK({ config, options })`, the flat `WebsiteSDKConfig`, and separate `WebsiteSDKOptions`.
6
+
7
+ ## What To Review
8
+
9
+ ### Documents
10
+
11
+ v10 SDK instances now expose:
12
+
13
+ ```ts
14
+ const documents = await sdk.static.documents.getTermsAndPrivacyPolicy({ locale: "de-DE" });
15
+ ```
16
+
17
+ The output may contain `terms` and/or `privacyPolicy`, each with `{ subject, data }`. `data` is the published document revision data as a string. If your app renders this data, see `../../document-structured-json.md`.
18
+
19
+ This API is v10-only. Code that handles both backends should narrow by `sdk.backend === "v10"` before calling `sdk.static.documents`.
20
+
21
+ ### Contact
22
+
23
+ Contact requests are validated before submission on both v9 and v10. Validation failures reject with `CoreSDKError` using `operation: "contact.submit.validation"` and field details in `error.cause.issues`.
24
+
25
+ Required fields are `title`, `surname`, `email`, `subject`, and `message`. Validation also checks email format, two-letter uppercase country codes, and maximum field lengths.
26
+
27
+ Migration: update contact forms to display field-level validation issues instead of treating every contact error as a backend failure.
28
+
29
+ ### Search
30
+
31
+ `SearchSearchInput` now accepts `voucher?: string` for v10 pricing:
32
+
33
+ ```ts
34
+ await sdk.live.search.search({
35
+ locale: "de-DE",
36
+ query: "adults=2",
37
+ voucher: "SUMMER26",
38
+ });
39
+ ```
40
+
41
+ The CLI equivalent is `--voucher SUMMER26`.
42
+
43
+ v10 filters now expose a mapped BooleanFilter with `searchParameterQueryKey: "pets"` and localized labels (`Dogs welcome` / `Hunde willkommen`). It maps to one pet in occupancy. Use either `pets` or `petsCount`, not both.
44
+
45
+ ### Quote
46
+
47
+ Available quotes can include:
48
+
49
+ ```ts
50
+ quote.voucher; // { code, status, message? }
51
+ ```
52
+
53
+ `status` is `"applied"`, `"not_applied"`, or `"unknown"`. v10 can detect applied voucher modifiers; v9 uses `"unknown"` for available voucher quotes.
54
+
55
+ Additional services and cancellation policies may now include:
56
+
57
+ ```ts
58
+ {
59
+ available: false,
60
+ unavailableReason: "..."
61
+ }
62
+ ```
63
+
64
+ Migration: disable unavailable options in the UI and keep handling unknown optional fields gracefully.
65
+
66
+ Quote selection errors can now include `UnavailableQuoteCombination` when a selected add-on/cancellation-policy combination cannot be priced. Add a generic message for unsupported combinations.
67
+
68
+ ### Public Types
69
+
70
+ The root package now exports backend-specific facade types:
71
+
72
+ - `WebsiteSDKV9`
73
+ - `WebsiteSDKV10`
74
+ - `WebsiteSDKSharedStatic`
75
+ - `WebsiteSDKSharedLive`
76
+ - `WebsiteSDKV10Static`
77
+ - `WebsiteSDKV10Live`
78
+
79
+ Use these only when you need backend-specific narrowing. Existing `WebsiteSDK` imports remain valid.
80
+
81
+ ## Recommended Steps
82
+
83
+ 1. Upgrade to `@v-office/website-sdk` 2.1.0.
84
+ 2. Update contact form error handling for `error.cause.issues`.
85
+ 3. If you render quotes, support optional `quote.voucher`, `available`, and `unavailableReason`.
86
+ 4. Add handling for `UnavailableQuoteCombination` in quote selection failures.
87
+ 5. If you use v10 search filters, render the new `pets` BooleanFilter and avoid combining it with `petsCount`.
88
+ 6. Use `sdk.static.documents.getTermsAndPrivacyPolicy` for v10 terms/privacy output where needed.
89
+ 7. Run a focused smoke test for search, quote selection, booking, contact submission, and v10 documents.
@@ -1,4 +1,4 @@
1
- import { GuestQuote, addGuestQuoteAdditionalServiceSelection, formatCurrency, toNightCount } from "@v-office/sdk-core";
1
+ import { GuestQuote, GuestQuoteBookingCardDisplayOrder, addGuestQuoteAdditionalServiceSelection, formatCurrency, toNightCount } from "@v-office/sdk-core";
2
2
  import { DateTime, Effect } from "effect";
3
3
  //#region src/legacy-v9/parser/quote/to-additional-service-calculation.ts
4
4
  const toAdditionalServiceCalculation = (line) => {
@@ -243,9 +243,18 @@ const toSections = ({ input, guestQuoteResult, locale, translations }) => Effect
243
243
  locale,
244
244
  translations
245
245
  });
246
- if (hasSectionLineContent(sectionsIncluded)) sections.push({ lines: [sectionsIncluded] });
247
- if (hasSectionLineContent(sectionsTax)) sections.push({ lines: [sectionsTax] });
248
- if (sectionsOther.length > 0) sections.push({ lines: sectionsOther });
246
+ if (hasSectionLineContent(sectionsIncluded)) sections.push({
247
+ lines: [sectionsIncluded],
248
+ displayOrder: GuestQuoteBookingCardDisplayOrder.inclusive
249
+ });
250
+ if (hasSectionLineContent(sectionsTax)) sections.push({
251
+ lines: [sectionsTax],
252
+ displayOrder: GuestQuoteBookingCardDisplayOrder.tax
253
+ });
254
+ if (sectionsOther.length > 0) sections.push({
255
+ lines: sectionsOther,
256
+ displayOrder: GuestQuoteBookingCardDisplayOrder.other
257
+ });
249
258
  return sections;
250
259
  });
251
260
  //#endregion
@@ -261,6 +270,14 @@ const toErrorReason = (guestQuoteResult) => {
261
270
  const messages = (Array.isArray(errors) ? errors : [errors]).flatMap((error) => Object.values(error).filter((value) => typeof value === "string" && value.trim().length > 0));
262
271
  return messages.length === 0 ? void 0 : messages.join(" ");
263
272
  };
273
+ const toVoucher = ({ input, locale, translations }) => Effect.gen(function* () {
274
+ if (input.voucher === void 0) return void 0;
275
+ return {
276
+ code: input.voucher,
277
+ status: "unknown",
278
+ message: yield* translations.translate(locale, "quote.voucher.unknown", "The backend did not confirm whether the voucher code was applied.")
279
+ };
280
+ });
264
281
  const toGuestQuote = (input, guestQuoteResult, locale, translations) => Effect.gen(function* () {
265
282
  const errorReason = toErrorReason(guestQuoteResult);
266
283
  if (errorReason !== void 0) return {
@@ -281,6 +298,11 @@ const toGuestQuote = (input, guestQuoteResult, locale, translations) => Effect.g
281
298
  });
282
299
  const baseTotal = toBaseTotal(guestQuoteResult);
283
300
  const currency = guestQuoteResult?.currency ?? "EUR";
301
+ const voucher = yield* toVoucher({
302
+ input,
303
+ locale,
304
+ translations
305
+ });
284
306
  let guestQuote = new GuestQuote({
285
307
  input,
286
308
  bookingCardInformation: {
@@ -290,6 +312,7 @@ const toGuestQuote = (input, guestQuoteResult, locale, translations) => Effect.g
290
312
  baseTotal,
291
313
  currency,
292
314
  additionalServices,
315
+ ...voucher === void 0 ? {} : { voucher },
293
316
  backendContext: toV9QuoteBackendContext(input, guestQuoteResult),
294
317
  updateBackendContext: updateV9QuoteBackendContext
295
318
  });