@v-office/website-sdk 2.9.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,9 +2,8 @@
2
2
 
3
3
  Website-facing SDK facade for vOffice backends.
4
4
 
5
- The 2.8.0 line adds the catalog-backed custom-attribute registry, backend-aware
6
- atomic filter compositions, and consistent custom-attribute display and highlight
7
- behavior.
5
+ The current SDK includes catalog-backed custom attributes, backend-aware search,
6
+ and localized v10 REST search discount details.
8
7
  See `instructions/CHANGELOG.md` for the complete release history.
9
8
 
10
9
  ## Install
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as createWebsiteSDK, zt as defineWebsiteSDKOptions } from "./client-CYK_5Vk7.mjs";
2
+ import { t as createWebsiteSDK, zt as defineWebsiteSDKOptions } from "./client-DYAHnU5F.mjs";
3
3
  import { SearchSearchSortSchema, defineCustomAttributesFromUnknown } from "@v-office/sdk-core";
4
4
  import { Console, Effect, FileSystem, Layer, Option, Path, Schema, Stdio, Terminal } from "effect";
5
5
  import { Command, Flag } from "effect/unstable/cli";
@@ -16,7 +16,7 @@ var CLICheckFailed = class extends Error {
16
16
  const toCLIError = (message, cause) => cause instanceof Error ? new CLICheckFailed(`${message}: ${cause.message}`, { cause }) : new CLICheckFailed(message, { cause });
17
17
  //#endregion
18
18
  //#region package.json
19
- var version = "2.9.0";
19
+ var version = "2.11.0";
20
20
  //#endregion
21
21
  //#region src/cli/output.ts
22
22
  const toJson = (value) => Effect.try({
@@ -3770,7 +3770,7 @@ const toBookingInput = ({ input }) => Effect.gen(function* () {
3770
3770
  message: "Expected a v9 quote for v9 booking."
3771
3771
  }));
3772
3772
  return {
3773
- action: "booking",
3773
+ action: input.kind === "OPTION" ? "option" : "booking",
3774
3774
  reservation: { customer: {
3775
3775
  ...input.contact.title === void 0 ? {} : { title: input.contact.title },
3776
3776
  forename: input.contact.forename,
@@ -4952,7 +4952,7 @@ const parseV9SearchCursor = (cursor) => Effect.gen(function* () {
4952
4952
  return page;
4953
4953
  });
4954
4954
  const loadV9SearchRuntime = Effect.tryPromise({
4955
- try: () => import("./search-CO9ID9op.mjs"),
4955
+ try: () => import("./search-QlZrI7ue.mjs"),
4956
4956
  catch: (cause) => new CoreSDKError({
4957
4957
  source: "v10",
4958
4958
  operation: "v9.search.runtime",
package/dist/index.d.mts CHANGED
@@ -350,6 +350,14 @@ declare const searchEffect: (input: SearchSearchInput$1) => Effect.Effect<{
350
350
  readonly province?: string;
351
351
  readonly country?: string;
352
352
  };
353
+ readonly formattedTotal?: string;
354
+ readonly discount?: {
355
+ readonly formattedOriginalTotal: string;
356
+ readonly applied: readonly {
357
+ readonly label: string;
358
+ readonly formattedAmount: string;
359
+ }[];
360
+ };
353
361
  readonly highlights?: readonly string[];
354
362
  readonly property?: {
355
363
  readonly id: string;
@@ -379,7 +387,6 @@ declare const searchEffect: (input: SearchSearchInput$1) => Effect.Effect<{
379
387
  readonly country?: string;
380
388
  };
381
389
  };
382
- readonly formattedTotal?: string;
383
390
  }[];
384
391
  readonly alternatives?: readonly {
385
392
  readonly item: {
@@ -411,6 +418,14 @@ declare const searchEffect: (input: SearchSearchInput$1) => Effect.Effect<{
411
418
  readonly province?: string;
412
419
  readonly country?: string;
413
420
  };
421
+ readonly formattedTotal?: string;
422
+ readonly discount?: {
423
+ readonly formattedOriginalTotal: string;
424
+ readonly applied: readonly {
425
+ readonly label: string;
426
+ readonly formattedAmount: string;
427
+ }[];
428
+ };
414
429
  readonly highlights?: readonly string[];
415
430
  readonly property?: {
416
431
  readonly id: string;
@@ -440,12 +455,18 @@ declare const searchEffect: (input: SearchSearchInput$1) => Effect.Effect<{
440
455
  readonly country?: string;
441
456
  };
442
457
  };
443
- readonly formattedTotal?: string;
444
458
  };
445
459
  readonly alternativePeriods: readonly {
460
+ readonly formattedTotal?: string;
461
+ readonly discount?: {
462
+ readonly formattedOriginalTotal: string;
463
+ readonly applied: readonly {
464
+ readonly label: string;
465
+ readonly formattedAmount: string;
466
+ }[];
467
+ };
446
468
  readonly start: string;
447
469
  readonly end: string;
448
- readonly formattedTotal?: string;
449
470
  }[];
450
471
  }[];
451
472
  readonly appliedFilters: readonly {
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as ServiceBeonDataSchema, A as ErgoBookRequestSchema, At as quoteEffect, B as OnOfficeUnitSchema, C as DocumentResourceSchema, Ct as clearAdditionalServicesEffect, D as DocumentTypeSchema, Dt as getRentalsEffect, E as DocumentSummarySchema, Et as getInitialAvailabilityEffect, F as ErgoPolicyNumberRequestSchema, Ft as selectInsurancePaymentEffect, G as QuotePricesResponseSchema, H as PaymentScheduleSchema, I as ErgoReadPreContractRequestSchema, It as submitContactEffect, J as RawObjectResponseSchema, K as QuoteSchema, L as ErgoTripAndCustomerRequestSchema, Lt as submitPaymentOption, M as ErgoCreatePreContractRequestSchema, Mt as searchEffect, N as ErgoPersonSchema, Nt as selectCancellationPolicyEffect, O as ErgoAddressSchema, Ot as getStartDateSelectedAvailabilityEffect, P as ErgoPlanSearchRequestSchema, Pt as selectInsuranceEffect, Q as SearchPropertiesResponseSchema, R as FacilityListResponseSchema, Rt as submitPaymentOptionEffect, S as DocumentResourceResponseSchema, St as bookInsuranceEffect, T as DocumentStatusUpdateRequestSchema, Tt as getFiltersEffect, U as QuoteLineSchema, V as PaymentScheduleItemSchema, W as QuotePricesPayloadSchema, X as RegionListResponseSchema, Y as RawVofficeObjectSchema, Z as RoomImageSchema, _ as CalendarDaySchema, _t as V1_OPERATIONS, at as TileCollectionResponseSchema, b as CustomerUnitSummarySchema, bt as addAdditionalServiceEffect, c as V0OpenApiClient, ct as TravelInsuranceBookingSchema, d as makeV0OpenApiClientLive, dt as UnitListItemSchema, et as ServiceImageSchema, f as V1OpenApiClient, ft as UnitListResponseSchema, g as ApiEnvelopeBaseSchema, gt as V1_BASE_URL, h as makeV1OpenApiClientLive, ht as UnitServicePriceSchema, it as SetupResponseSchema, j as ErgoCommonFieldsSchema, jt as removeAdditionalServiceEffect, k as ErgoBankSchema, kt as getTermsAndPrivacyPolicyEffect, l as V0OpenApiClientError, lt as TravelInsuranceBookingStoreRequestSchema, m as makeV1OpenApiClientFetchLive, mt as UnitResponseSchema, nt as ServiceListResponseSchema, ot as TileSchema, p as V1OpenApiClientError, pt as UnitOfferSchema, q as QuoteServiceSchema, rt as SetupDataSchema, st as TileTagSchema, t as createWebsiteSDK, tt as ServiceLimitSchema, u as makeV0OpenApiClientFetchLive, ut as UnitIdsResponseSchema, v as CalendarResponseSchema, vt as VideoResponseSchema, w as DocumentStatusSchema, wt as createInsurancePreContractEffect, x as DocumentCollectionResponseSchema, xt as bookEffect, y as CurrentMemberResponseSchema, yt as decodeV1OperationResponse, z as OnOfficeUnitCollectionResponseSchema, zt as defineWebsiteSDKOptions } from "./client-CYK_5Vk7.mjs";
1
+ import { $ as ServiceBeonDataSchema, A as ErgoBookRequestSchema, At as quoteEffect, B as OnOfficeUnitSchema, C as DocumentResourceSchema, Ct as clearAdditionalServicesEffect, D as DocumentTypeSchema, Dt as getRentalsEffect, E as DocumentSummarySchema, Et as getInitialAvailabilityEffect, F as ErgoPolicyNumberRequestSchema, Ft as selectInsurancePaymentEffect, G as QuotePricesResponseSchema, H as PaymentScheduleSchema, I as ErgoReadPreContractRequestSchema, It as submitContactEffect, J as RawObjectResponseSchema, K as QuoteSchema, L as ErgoTripAndCustomerRequestSchema, Lt as submitPaymentOption, M as ErgoCreatePreContractRequestSchema, Mt as searchEffect, N as ErgoPersonSchema, Nt as selectCancellationPolicyEffect, O as ErgoAddressSchema, Ot as getStartDateSelectedAvailabilityEffect, P as ErgoPlanSearchRequestSchema, Pt as selectInsuranceEffect, Q as SearchPropertiesResponseSchema, R as FacilityListResponseSchema, Rt as submitPaymentOptionEffect, S as DocumentResourceResponseSchema, St as bookInsuranceEffect, T as DocumentStatusUpdateRequestSchema, Tt as getFiltersEffect, U as QuoteLineSchema, V as PaymentScheduleItemSchema, W as QuotePricesPayloadSchema, X as RegionListResponseSchema, Y as RawVofficeObjectSchema, Z as RoomImageSchema, _ as CalendarDaySchema, _t as V1_OPERATIONS, at as TileCollectionResponseSchema, b as CustomerUnitSummarySchema, bt as addAdditionalServiceEffect, c as V0OpenApiClient, ct as TravelInsuranceBookingSchema, d as makeV0OpenApiClientLive, dt as UnitListItemSchema, et as ServiceImageSchema, f as V1OpenApiClient, ft as UnitListResponseSchema, g as ApiEnvelopeBaseSchema, gt as V1_BASE_URL, h as makeV1OpenApiClientLive, ht as UnitServicePriceSchema, it as SetupResponseSchema, j as ErgoCommonFieldsSchema, jt as removeAdditionalServiceEffect, k as ErgoBankSchema, kt as getTermsAndPrivacyPolicyEffect, l as V0OpenApiClientError, lt as TravelInsuranceBookingStoreRequestSchema, m as makeV1OpenApiClientFetchLive, mt as UnitResponseSchema, nt as ServiceListResponseSchema, ot as TileSchema, p as V1OpenApiClientError, pt as UnitOfferSchema, q as QuoteServiceSchema, rt as SetupDataSchema, st as TileTagSchema, t as createWebsiteSDK, tt as ServiceLimitSchema, u as makeV0OpenApiClientFetchLive, ut as UnitIdsResponseSchema, v as CalendarResponseSchema, vt as VideoResponseSchema, w as DocumentStatusSchema, wt as createInsurancePreContractEffect, x as DocumentCollectionResponseSchema, xt as bookEffect, y as CurrentMemberResponseSchema, yt as decodeV1OperationResponse, z as OnOfficeUnitCollectionResponseSchema, zt as defineWebsiteSDKOptions } from "./client-DYAHnU5F.mjs";
2
2
  import { AdditionalServiceLimitExceeded, CoreSDKError, CoreSDKError as CMSError, CustomAttributeCatalogSchema, GuestQuoteSchema, InvalidAdditionalServiceQuantity, LocaleSchema, SearchSearchFieldOrderBySchema, SearchSearchFieldSortSchema, SearchSearchInputSchema, SearchSearchOutputSchema, SearchSearchPriceSortSchema, SearchSearchRandomSortSchema, SearchSearchRatingSortSchema, SearchSearchSortSchema, SearchSortDirectionSchema, UnknownAdditionalService, defineCustomAttributes, defineCustomAttributesFromUnknown, fetchCustomAttributeCatalog, parseCustomAttributeCatalog, validateContactSubmitInput } from "@v-office/sdk-core";
3
3
  //#region codegen/v9/heuristic-generation/public-api.ts
4
4
  const customDataAttribute = (name) => name;
@@ -4,6 +4,8 @@ This file is the versioned changelog index for the website SDK instructions.
4
4
 
5
5
  ## Versions
6
6
 
7
+ - `versions/2.11.0/CHANGELOG.md`: `@v-office/website-sdk` 2.11.0 release notes.
8
+ - `versions/2.10.0/CHANGELOG.md`: `@v-office/website-sdk` 2.10.0 release notes.
7
9
  - `versions/2.9.0/CHANGELOG.md`: `@v-office/website-sdk` 2.9.0 release notes.
8
10
  - `versions/2.8.0/CHANGELOG.md`: `@v-office/website-sdk` 2.8.0 release notes.
9
11
  - `versions/2.7.0/CHANGELOG.md`: `@v-office/website-sdk` 2.7.0 release notes.
@@ -4,6 +4,8 @@ This file is the versioned migration index for the website SDK instructions.
4
4
 
5
5
  ## Available Guides
6
6
 
7
+ - `versions/2.11.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.10.0 to 2.11.0.
8
+ - `versions/2.10.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.9.0 to 2.10.0.
7
9
  - `versions/2.9.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.8.0 to 2.9.0.
8
10
  - `versions/2.8.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.7.0 to 2.8.0.
9
11
  - `versions/2.7.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.5.x to 2.7.0.
@@ -1,7 +1,7 @@
1
1
  # Website SDK Instructions
2
2
 
3
3
  These instructions describe the current source targeted for
4
- `@v-office/website-sdk` 2.9.0. Package versions remain unchanged until the release
4
+ `@v-office/website-sdk` 2.11.0. Package versions remain unchanged until the release
5
5
  workflow performs the coordinated core and website bumps.
6
6
 
7
7
  Use this directory as the consumer-facing reference for the package:
@@ -18,6 +18,9 @@ Use this directory as the consumer-facing reference for the package:
18
18
  - `document-structured-json.md`: `sdk.static.documents.getTermsAndPrivacyPolicy` and structured document JSON rendering rules.
19
19
  - `CHANGELOG.md`: versioned changelog index.
20
20
  - `MIGRATION.md`: versioned migration index.
21
+ - `versions/2.11.0/`: 2.11.0 search-discount release notes and
22
+ 2.10.0-to-2.11.0 migration guide.
23
+ - `versions/2.10.0/`: 2.10.0 option-booking release notes and 2.9.0-to-2.10.0 migration guide.
21
24
  - `versions/2.9.0/`: 2.9.0 highlight-selection release notes and 2.8.0-to-2.9.0 migration guide.
22
25
  - `versions/2.8.0/`: 2.8.0 custom-attribute release notes and 2.7.0-to-2.8.0 migration guide.
23
26
  - `versions/2.7.0/`: 2.7.0 release notes and 2.5.x-to-2.7.0 migration guide.
@@ -75,4 +78,6 @@ website-sdk --backend v10 search --locale de-DE --query "adults=2"
75
78
  website-sdk --backend v10 search --locale de-DE --query "adults=2" --sort '{"by":"field","orderBy":{"label":"ASC"}}'
76
79
  ```
77
80
 
78
- Config file examples in these docs use the flat `WebsiteSDKConfig` shape introduced in 2.0.0 and kept in 2.9.0. v10 config additionally requires `searchEndpoint` as of 2.5.0.
81
+ Config file examples in these docs use the flat `WebsiteSDKConfig` shape introduced
82
+ in 2.0.0 and kept in 2.11.0. v10 config additionally requires `searchEndpoint` as
83
+ of 2.5.0.
@@ -2,7 +2,8 @@
2
2
 
3
3
  ## Service
4
4
 
5
- Use the live booking API to turn an available `GuestQuote` into a booking:
5
+ Use the live booking API to turn an available `GuestQuote` into a confirmed or
6
+ option booking:
6
7
 
7
8
  ```ts
8
9
  const booking = await sdk.live.booking.book(input);
@@ -31,6 +32,7 @@ type BookingInput = {
31
32
  note?: string;
32
33
  };
33
34
  relativeRedirectUrl: string;
35
+ kind?: "CONFIRMED" | "OPTION";
34
36
  };
35
37
  ```
36
38
 
@@ -63,6 +65,8 @@ const booking = await sdk.live.booking.book({
63
65
  });
64
66
  ```
65
67
 
68
+ `kind: "OPTION"` creates an option booking on v10 and legacy v9. Omitting `kind`,
69
+ or passing `"CONFIRMED"`, retains the existing confirmed-booking behavior.
66
70
  `relativeRedirectUrl` is used for online payment redirects after booking creation.
67
71
 
68
72
  ## Output
@@ -227,6 +227,18 @@ The supported fields are `label`, `name`, all six `roomSummary` counters, `attri
227
227
 
228
228
  Returns `Promise<RentalSearchOutput>`.
229
229
 
230
+ Priced items and alternative periods share this optional discount shape:
231
+
232
+ ```ts
233
+ type SearchDiscount = {
234
+ readonly formattedOriginalTotal: string;
235
+ readonly applied: readonly {
236
+ readonly label: string;
237
+ readonly formattedAmount: string;
238
+ }[];
239
+ };
240
+ ```
241
+
230
242
  Sample:
231
243
 
232
244
  ```json
@@ -250,7 +262,16 @@ Sample:
250
262
  }
251
263
  ],
252
264
  "highlights": ["2 bedrooms", "WiFi", "Parking"],
253
- "formattedTotal": "1.234,00 €"
265
+ "formattedTotal": "1.111,00 €",
266
+ "discount": {
267
+ "formattedOriginalTotal": "1.234,00 €",
268
+ "applied": [
269
+ {
270
+ "label": "Frühbucher-Rabatt",
271
+ "formattedAmount": "-123,00 €"
272
+ }
273
+ ]
274
+ }
254
275
  }
255
276
  ],
256
277
  "alternatives": [
@@ -264,7 +285,16 @@ Sample:
264
285
  {
265
286
  "start": "2026-07-10",
266
287
  "end": "2026-07-17",
267
- "formattedTotal": "1.456,00 €"
288
+ "formattedTotal": "1.310,00 €",
289
+ "discount": {
290
+ "formattedOriginalTotal": "1.456,00 €",
291
+ "applied": [
292
+ {
293
+ "label": "Frühbucher-Rabatt",
294
+ "formattedAmount": "-146,00 €"
295
+ }
296
+ ]
297
+ }
268
298
  }
269
299
  ]
270
300
  }
@@ -288,7 +318,15 @@ Sample:
288
318
  }
289
319
  ```
290
320
 
291
- Search items share the rental base fields and may include `scope`, `address`, `property`, `highlights`, and `formattedTotal`. Exact-period results are returned in `items`; alternative-period suggestions are returned in root-level `alternatives`.
321
+ Search items share the rental base fields and may include `scope`, `address`,
322
+ `property`, `highlights`, and `formattedTotal`. A priced item or alternative period
323
+ may also include `discount`. When it does, `formattedTotal` is the final price and
324
+ `discount.formattedOriginalTotal` is the price before the applied discounts.
325
+ Discount totals, labels, and amounts are already localized and formatted for the
326
+ requested locale; backend numeric amounts and modifier type keys are not exposed.
327
+ `applied` may be empty when the backend supplies an original total without
328
+ individual modifier lines. Exact-period results are returned in `items`;
329
+ alternative-period suggestions are returned in root-level `alternatives`.
292
330
 
293
331
  `appliedFilters` reports what the backend actually applied, and is what a "remove
294
332
  this filter" chip should be built from. `label` is localized presentation and can
@@ -319,6 +357,8 @@ v10 search runs against the dedicated REST search backend (`POST` to the configu
319
357
  - `property` is the minimal `{ id, nameOrLabel }` shape. Hydrate `property.location`, `property.images`, or `property.address` from `sdk.static.rentals.getRentals(...)` when a card needs them.
320
358
  - Custom-attribute search filters and highlights require the `customAttributes` registry. A definition with no catalog ID cannot be executed, so its query key is left in `unusedFilterKeys`. v9 never executes a custom-attribute filter at all. See `custom-attributes.md`.
321
359
  - Fixed-period and flexible searches are priced by the REST backend and require occupancy.
360
+ - Priced items and alternative periods may include localized `discount` details when the REST backend returns them. Legacy v9 search does not populate this field.
361
+ - Search inputs are unchanged. The SDK keeps alternative-cancellation-policy pricing out of search; cancellation-policy selection remains part of the quote and booking flow.
322
362
  - Pagination uses the backend `from`/`size` window behind the same opaque `cursor`, capped at 1,000 results.
323
363
 
324
364
  ## Configuration
@@ -0,0 +1,26 @@
1
+ # Changelog: 2.10.0
2
+
3
+ This release adds option bookings to the shared booking input and supports them
4
+ consistently through the v10 and legacy v9 backends.
5
+
6
+ ## Added
7
+
8
+ - `BookingInput.kind` accepts `"CONFIRMED"` or `"OPTION"`.
9
+ - Passing `kind: "OPTION"` creates an option booking through
10
+ `sdk.live.booking.book(...)`.
11
+
12
+ ## Changed
13
+
14
+ - v10 maps `"OPTION"` to the GraphQL booking status `OPTION`.
15
+ - Legacy v9 maps `"OPTION"` to the v0 booking action `option`.
16
+ - Omitting `kind`, or passing `"CONFIRMED"`, retains the existing confirmed-booking
17
+ behavior on both backends.
18
+
19
+ ## Migration Impact
20
+
21
+ - Existing booking calls require no changes because `kind` is optional.
22
+ - The booking service name, remaining input fields, and `BookingOutput` are
23
+ unchanged.
24
+ - `relativeRedirectUrl` remains required for both booking kinds.
25
+ - Sites that want to create option bookings can opt in by passing
26
+ `kind: "OPTION"`. See `versions/2.10.0/MIGRATION.md`.
@@ -0,0 +1,63 @@
1
+ # Migration: 2.9.0 to 2.10.0
2
+
3
+ 2.10.0 adds an optional booking kind. Existing calls continue to create confirmed
4
+ bookings and require no migration.
5
+
6
+ ## 1. Choose the Booking Kind
7
+
8
+ `BookingInput` now includes:
9
+
10
+ ```ts
11
+ kind?: "CONFIRMED" | "OPTION";
12
+ ```
13
+
14
+ The values behave as follows:
15
+
16
+ - Omit `kind`, or pass `"CONFIRMED"`, to create a confirmed booking.
17
+ - Pass `"OPTION"` to create an option booking.
18
+
19
+ The SDK maps these values to the native backend representation:
20
+
21
+ - v10 uses booking status `CONFIRMED` or `OPTION`.
22
+ - Legacy v9 uses booking action `booking` or `option`.
23
+
24
+ ## 2. Create an Option Booking
25
+
26
+ Use the existing booking service and set `kind` to `"OPTION"`:
27
+
28
+ ```ts
29
+ const optionBooking = await sdk.live.booking.book({
30
+ quote,
31
+ contact,
32
+ relativeRedirectUrl: "/booking/payment-return",
33
+ kind: "OPTION",
34
+ });
35
+ ```
36
+
37
+ No separate option-booking method is required. The returned value remains a
38
+ `BookingOutput`.
39
+
40
+ ## 3. Keep Existing Confirmed Bookings Unchanged
41
+
42
+ Existing calls remain valid:
43
+
44
+ ```ts
45
+ const booking = await sdk.live.booking.book({
46
+ quote,
47
+ contact,
48
+ relativeRedirectUrl: "/booking/payment-return",
49
+ });
50
+ ```
51
+
52
+ Passing `kind: "CONFIRMED"` is equivalent to omitting the field. Other input
53
+ requirements, including `relativeRedirectUrl`, are unchanged.
54
+
55
+ ## Recommended Verification
56
+
57
+ 1. Create a booking without `kind` and confirm it remains confirmed.
58
+ 2. Create a booking with `kind: "OPTION"` and confirm the backend records it as an
59
+ option.
60
+ 3. Repeat both checks against v10 and legacy v9 when the site supports both
61
+ backends.
62
+ 4. Verify existing booking-result and payment handling still accepts the unchanged
63
+ `BookingOutput`.
@@ -0,0 +1,28 @@
1
+ # Changelog: 2.11.0
2
+
3
+ This release exposes localized v10 REST search discount details on priced search
4
+ results.
5
+
6
+ ## Added
7
+
8
+ - Priced v10 search items may include an optional `discount` with the localized
9
+ pre-discount total in `formattedOriginalTotal`.
10
+ - `discount.applied` lists each applied discount as a localized `label` and
11
+ `formattedAmount`.
12
+ - Alternative-period suggestions expose the same optional discount shape on each
13
+ priced period.
14
+
15
+ ## Changed
16
+
17
+ - When `discount` is present, `formattedTotal` remains the final price after the
18
+ listed discounts.
19
+ - Backend modifier types and numeric amounts remain internal; the public search
20
+ output contains presentation-ready localized strings.
21
+
22
+ ## Migration Impact
23
+
24
+ - Existing search calls require no changes because `discount` is optional.
25
+ - Search configuration and input are unchanged.
26
+ - Legacy v9 search does not populate `discount`.
27
+ - Sites can opt in to strike-through pricing and discount labels by reading the
28
+ new field. See `versions/2.11.0/MIGRATION.md` and `../../search.md`.
@@ -0,0 +1,72 @@
1
+ # Migration: 2.10.0 to 2.11.0
2
+
3
+ 2.11.0 adds optional localized discount information to priced v10 search results.
4
+ Existing search calls and rendering remain valid without changes.
5
+
6
+ ## 1. Read the Optional Discount
7
+
8
+ Exact-period items and individual alternative periods may now include:
9
+
10
+ ```ts
11
+ type SearchDiscount = {
12
+ readonly formattedOriginalTotal: string;
13
+ readonly applied: readonly {
14
+ readonly label: string;
15
+ readonly formattedAmount: string;
16
+ }[];
17
+ };
18
+ ```
19
+
20
+ The field is omitted when the REST search backend returns no discount. Keep
21
+ rendering `formattedTotal` as before and add discount presentation only when
22
+ `discount` is present.
23
+
24
+ ## 2. Distinguish Final and Original Totals
25
+
26
+ When a discount is present:
27
+
28
+ - `formattedTotal` is the final price after the applied discounts.
29
+ - `discount.formattedOriginalTotal` is the total before those discounts.
30
+ - `discount.applied` contains presentation-ready localized labels and formatted
31
+ amounts.
32
+
33
+ All monetary values already include locale-aware currency formatting. Backend
34
+ numeric amounts and modifier type keys are intentionally not exposed.
35
+
36
+ ## 3. Handle Exact and Alternative Periods
37
+
38
+ For a fixed-period match, read the field from the item:
39
+
40
+ ```ts
41
+ result.items[0]?.discount;
42
+ ```
43
+
44
+ For a nearby-period suggestion, read it from the individual period:
45
+
46
+ ```ts
47
+ result.alternatives?.[0]?.alternativePeriods[0]?.discount;
48
+ ```
49
+
50
+ Each alternative period has independent pricing and may have a different discount
51
+ or no discount.
52
+
53
+ ## 4. Keep Search Inputs Unchanged
54
+
55
+ No configuration or input migration is required. The SDK continues to request the
56
+ existing default v10 search pricing and does not opt search into alternative
57
+ cancellation-policy pricing.
58
+
59
+ Legacy v9 search does not populate `discount`; consumers supporting both backends
60
+ must treat it as optional.
61
+
62
+ ## Recommended Verification
63
+
64
+ 1. Run a priced v10 exact-period search that has a configured discount and verify
65
+ the final and original totals.
66
+ 2. Verify each applied entry has a localized label and formatted amount in every
67
+ supported locale.
68
+ 3. Run a priced search without a discount and confirm existing rendering is
69
+ unchanged.
70
+ 4. Check nearby alternative periods independently because discounts can differ by
71
+ period.
72
+ 5. If the site supports v9, confirm its existing search output remains unchanged.
@@ -121,6 +121,9 @@ The public output type is unchanged, but v10 search cards now reflect the REST p
121
121
  - `property` is the minimal `{ id, nameOrLabel }` shape. Hydrate `property.location`, `property.images`, or `property.address` from `sdk.static.rentals.getRentals(...)` when a search card needs them.
122
122
  - Exact-period matches are returned in `items` with `formattedTotal`; nearby suggestions are returned in root-level `alternatives`, unchanged.
123
123
 
124
+ Starting with 2.11.0, priced v10 items and alternative periods may also include
125
+ optional localized `discount` details. See `../../search.md`.
126
+
124
127
  ## Backend Behavior
125
128
 
126
129
  - Fixed-period and flexible searches are priced by the REST backend; occupancy is required for priced searches.
@@ -1,4 +1,4 @@
1
- import { a as parseQueryParameters, i as collectQueryParameters, n as makeV9CustomAttributeFilterCapabilities, o as toQueryString, r as toBasicQueryInputs, s as applyVofficeFilterDerivedBasicQueryInputs } from "./client-CYK_5Vk7.mjs";
1
+ import { a as parseQueryParameters, i as collectQueryParameters, n as makeV9CustomAttributeFilterCapabilities, o as toQueryString, r as toBasicQueryInputs, s as applyVofficeFilterDerivedBasicQueryInputs } from "./client-DYAHnU5F.mjs";
2
2
  import { a as searchQuery, c as VofficeUnitDataFieldSchemas, m as parseVofficeUnitData, n as toImages, r as toAddress, t as toRentalHighlights } from "./to-rental-highlights-B6a_fi0j.mjs";
3
3
  import { CoreSDKError, STABLE_SEARCH_INPUTS, daysBetweenLocalDates, expandCustomAttributeFilterCompositions, parseChildrenAges, parseOccupancyCount, resolveExpandedCompositions, toFormattedSearchPrice, toIsoDateFromPeriodQueryDate, toStableSearchInputBackendQueryKeys, toStableSearchInputParameterValues, toStableSearchInputQueryKeys, toUnusedFilterKeys } from "@v-office/sdk-core";
4
4
  import { Effect } from "effect";
@@ -4,6 +4,8 @@ This file is the versioned changelog index for the website SDK instructions.
4
4
 
5
5
  ## Versions
6
6
 
7
+ - `versions/2.11.0/CHANGELOG.md`: `@v-office/website-sdk` 2.11.0 release notes.
8
+ - `versions/2.10.0/CHANGELOG.md`: `@v-office/website-sdk` 2.10.0 release notes.
7
9
  - `versions/2.9.0/CHANGELOG.md`: `@v-office/website-sdk` 2.9.0 release notes.
8
10
  - `versions/2.8.0/CHANGELOG.md`: `@v-office/website-sdk` 2.8.0 release notes.
9
11
  - `versions/2.7.0/CHANGELOG.md`: `@v-office/website-sdk` 2.7.0 release notes.
@@ -4,6 +4,8 @@ This file is the versioned migration index for the website SDK instructions.
4
4
 
5
5
  ## Available Guides
6
6
 
7
+ - `versions/2.11.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.10.0 to 2.11.0.
8
+ - `versions/2.10.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.9.0 to 2.10.0.
7
9
  - `versions/2.9.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.8.0 to 2.9.0.
8
10
  - `versions/2.8.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.7.0 to 2.8.0.
9
11
  - `versions/2.7.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.5.x to 2.7.0.
@@ -1,7 +1,7 @@
1
1
  # Website SDK Instructions
2
2
 
3
3
  These instructions describe the current source targeted for
4
- `@v-office/website-sdk` 2.9.0. Package versions remain unchanged until the release
4
+ `@v-office/website-sdk` 2.11.0. Package versions remain unchanged until the release
5
5
  workflow performs the coordinated core and website bumps.
6
6
 
7
7
  Use this directory as the consumer-facing reference for the package:
@@ -18,6 +18,9 @@ Use this directory as the consumer-facing reference for the package:
18
18
  - `document-structured-json.md`: `sdk.static.documents.getTermsAndPrivacyPolicy` and structured document JSON rendering rules.
19
19
  - `CHANGELOG.md`: versioned changelog index.
20
20
  - `MIGRATION.md`: versioned migration index.
21
+ - `versions/2.11.0/`: 2.11.0 search-discount release notes and
22
+ 2.10.0-to-2.11.0 migration guide.
23
+ - `versions/2.10.0/`: 2.10.0 option-booking release notes and 2.9.0-to-2.10.0 migration guide.
21
24
  - `versions/2.9.0/`: 2.9.0 highlight-selection release notes and 2.8.0-to-2.9.0 migration guide.
22
25
  - `versions/2.8.0/`: 2.8.0 custom-attribute release notes and 2.7.0-to-2.8.0 migration guide.
23
26
  - `versions/2.7.0/`: 2.7.0 release notes and 2.5.x-to-2.7.0 migration guide.
@@ -75,4 +78,6 @@ website-sdk --backend v10 search --locale de-DE --query "adults=2"
75
78
  website-sdk --backend v10 search --locale de-DE --query "adults=2" --sort '{"by":"field","orderBy":{"label":"ASC"}}'
76
79
  ```
77
80
 
78
- Config file examples in these docs use the flat `WebsiteSDKConfig` shape introduced in 2.0.0 and kept in 2.9.0. v10 config additionally requires `searchEndpoint` as of 2.5.0.
81
+ Config file examples in these docs use the flat `WebsiteSDKConfig` shape introduced
82
+ in 2.0.0 and kept in 2.11.0. v10 config additionally requires `searchEndpoint` as
83
+ of 2.5.0.
@@ -2,7 +2,8 @@
2
2
 
3
3
  ## Service
4
4
 
5
- Use the live booking API to turn an available `GuestQuote` into a booking:
5
+ Use the live booking API to turn an available `GuestQuote` into a confirmed or
6
+ option booking:
6
7
 
7
8
  ```ts
8
9
  const booking = await sdk.live.booking.book(input);
@@ -31,6 +32,7 @@ type BookingInput = {
31
32
  note?: string;
32
33
  };
33
34
  relativeRedirectUrl: string;
35
+ kind?: "CONFIRMED" | "OPTION";
34
36
  };
35
37
  ```
36
38
 
@@ -63,6 +65,8 @@ const booking = await sdk.live.booking.book({
63
65
  });
64
66
  ```
65
67
 
68
+ `kind: "OPTION"` creates an option booking on v10 and legacy v9. Omitting `kind`,
69
+ or passing `"CONFIRMED"`, retains the existing confirmed-booking behavior.
66
70
  `relativeRedirectUrl` is used for online payment redirects after booking creation.
67
71
 
68
72
  ## Output
@@ -227,6 +227,18 @@ The supported fields are `label`, `name`, all six `roomSummary` counters, `attri
227
227
 
228
228
  Returns `Promise<RentalSearchOutput>`.
229
229
 
230
+ Priced items and alternative periods share this optional discount shape:
231
+
232
+ ```ts
233
+ type SearchDiscount = {
234
+ readonly formattedOriginalTotal: string;
235
+ readonly applied: readonly {
236
+ readonly label: string;
237
+ readonly formattedAmount: string;
238
+ }[];
239
+ };
240
+ ```
241
+
230
242
  Sample:
231
243
 
232
244
  ```json
@@ -250,7 +262,16 @@ Sample:
250
262
  }
251
263
  ],
252
264
  "highlights": ["2 bedrooms", "WiFi", "Parking"],
253
- "formattedTotal": "1.234,00 €"
265
+ "formattedTotal": "1.111,00 €",
266
+ "discount": {
267
+ "formattedOriginalTotal": "1.234,00 €",
268
+ "applied": [
269
+ {
270
+ "label": "Frühbucher-Rabatt",
271
+ "formattedAmount": "-123,00 €"
272
+ }
273
+ ]
274
+ }
254
275
  }
255
276
  ],
256
277
  "alternatives": [
@@ -264,7 +285,16 @@ Sample:
264
285
  {
265
286
  "start": "2026-07-10",
266
287
  "end": "2026-07-17",
267
- "formattedTotal": "1.456,00 €"
288
+ "formattedTotal": "1.310,00 €",
289
+ "discount": {
290
+ "formattedOriginalTotal": "1.456,00 €",
291
+ "applied": [
292
+ {
293
+ "label": "Frühbucher-Rabatt",
294
+ "formattedAmount": "-146,00 €"
295
+ }
296
+ ]
297
+ }
268
298
  }
269
299
  ]
270
300
  }
@@ -288,7 +318,15 @@ Sample:
288
318
  }
289
319
  ```
290
320
 
291
- Search items share the rental base fields and may include `scope`, `address`, `property`, `highlights`, and `formattedTotal`. Exact-period results are returned in `items`; alternative-period suggestions are returned in root-level `alternatives`.
321
+ Search items share the rental base fields and may include `scope`, `address`,
322
+ `property`, `highlights`, and `formattedTotal`. A priced item or alternative period
323
+ may also include `discount`. When it does, `formattedTotal` is the final price and
324
+ `discount.formattedOriginalTotal` is the price before the applied discounts.
325
+ Discount totals, labels, and amounts are already localized and formatted for the
326
+ requested locale; backend numeric amounts and modifier type keys are not exposed.
327
+ `applied` may be empty when the backend supplies an original total without
328
+ individual modifier lines. Exact-period results are returned in `items`;
329
+ alternative-period suggestions are returned in root-level `alternatives`.
292
330
 
293
331
  `appliedFilters` reports what the backend actually applied, and is what a "remove
294
332
  this filter" chip should be built from. `label` is localized presentation and can
@@ -319,6 +357,8 @@ v10 search runs against the dedicated REST search backend (`POST` to the configu
319
357
  - `property` is the minimal `{ id, nameOrLabel }` shape. Hydrate `property.location`, `property.images`, or `property.address` from `sdk.static.rentals.getRentals(...)` when a card needs them.
320
358
  - Custom-attribute search filters and highlights require the `customAttributes` registry. A definition with no catalog ID cannot be executed, so its query key is left in `unusedFilterKeys`. v9 never executes a custom-attribute filter at all. See `custom-attributes.md`.
321
359
  - Fixed-period and flexible searches are priced by the REST backend and require occupancy.
360
+ - Priced items and alternative periods may include localized `discount` details when the REST backend returns them. Legacy v9 search does not populate this field.
361
+ - Search inputs are unchanged. The SDK keeps alternative-cancellation-policy pricing out of search; cancellation-policy selection remains part of the quote and booking flow.
322
362
  - Pagination uses the backend `from`/`size` window behind the same opaque `cursor`, capped at 1,000 results.
323
363
 
324
364
  ## Configuration
@@ -0,0 +1,26 @@
1
+ # Changelog: 2.10.0
2
+
3
+ This release adds option bookings to the shared booking input and supports them
4
+ consistently through the v10 and legacy v9 backends.
5
+
6
+ ## Added
7
+
8
+ - `BookingInput.kind` accepts `"CONFIRMED"` or `"OPTION"`.
9
+ - Passing `kind: "OPTION"` creates an option booking through
10
+ `sdk.live.booking.book(...)`.
11
+
12
+ ## Changed
13
+
14
+ - v10 maps `"OPTION"` to the GraphQL booking status `OPTION`.
15
+ - Legacy v9 maps `"OPTION"` to the v0 booking action `option`.
16
+ - Omitting `kind`, or passing `"CONFIRMED"`, retains the existing confirmed-booking
17
+ behavior on both backends.
18
+
19
+ ## Migration Impact
20
+
21
+ - Existing booking calls require no changes because `kind` is optional.
22
+ - The booking service name, remaining input fields, and `BookingOutput` are
23
+ unchanged.
24
+ - `relativeRedirectUrl` remains required for both booking kinds.
25
+ - Sites that want to create option bookings can opt in by passing
26
+ `kind: "OPTION"`. See `versions/2.10.0/MIGRATION.md`.
@@ -0,0 +1,63 @@
1
+ # Migration: 2.9.0 to 2.10.0
2
+
3
+ 2.10.0 adds an optional booking kind. Existing calls continue to create confirmed
4
+ bookings and require no migration.
5
+
6
+ ## 1. Choose the Booking Kind
7
+
8
+ `BookingInput` now includes:
9
+
10
+ ```ts
11
+ kind?: "CONFIRMED" | "OPTION";
12
+ ```
13
+
14
+ The values behave as follows:
15
+
16
+ - Omit `kind`, or pass `"CONFIRMED"`, to create a confirmed booking.
17
+ - Pass `"OPTION"` to create an option booking.
18
+
19
+ The SDK maps these values to the native backend representation:
20
+
21
+ - v10 uses booking status `CONFIRMED` or `OPTION`.
22
+ - Legacy v9 uses booking action `booking` or `option`.
23
+
24
+ ## 2. Create an Option Booking
25
+
26
+ Use the existing booking service and set `kind` to `"OPTION"`:
27
+
28
+ ```ts
29
+ const optionBooking = await sdk.live.booking.book({
30
+ quote,
31
+ contact,
32
+ relativeRedirectUrl: "/booking/payment-return",
33
+ kind: "OPTION",
34
+ });
35
+ ```
36
+
37
+ No separate option-booking method is required. The returned value remains a
38
+ `BookingOutput`.
39
+
40
+ ## 3. Keep Existing Confirmed Bookings Unchanged
41
+
42
+ Existing calls remain valid:
43
+
44
+ ```ts
45
+ const booking = await sdk.live.booking.book({
46
+ quote,
47
+ contact,
48
+ relativeRedirectUrl: "/booking/payment-return",
49
+ });
50
+ ```
51
+
52
+ Passing `kind: "CONFIRMED"` is equivalent to omitting the field. Other input
53
+ requirements, including `relativeRedirectUrl`, are unchanged.
54
+
55
+ ## Recommended Verification
56
+
57
+ 1. Create a booking without `kind` and confirm it remains confirmed.
58
+ 2. Create a booking with `kind: "OPTION"` and confirm the backend records it as an
59
+ option.
60
+ 3. Repeat both checks against v10 and legacy v9 when the site supports both
61
+ backends.
62
+ 4. Verify existing booking-result and payment handling still accepts the unchanged
63
+ `BookingOutput`.
@@ -0,0 +1,28 @@
1
+ # Changelog: 2.11.0
2
+
3
+ This release exposes localized v10 REST search discount details on priced search
4
+ results.
5
+
6
+ ## Added
7
+
8
+ - Priced v10 search items may include an optional `discount` with the localized
9
+ pre-discount total in `formattedOriginalTotal`.
10
+ - `discount.applied` lists each applied discount as a localized `label` and
11
+ `formattedAmount`.
12
+ - Alternative-period suggestions expose the same optional discount shape on each
13
+ priced period.
14
+
15
+ ## Changed
16
+
17
+ - When `discount` is present, `formattedTotal` remains the final price after the
18
+ listed discounts.
19
+ - Backend modifier types and numeric amounts remain internal; the public search
20
+ output contains presentation-ready localized strings.
21
+
22
+ ## Migration Impact
23
+
24
+ - Existing search calls require no changes because `discount` is optional.
25
+ - Search configuration and input are unchanged.
26
+ - Legacy v9 search does not populate `discount`.
27
+ - Sites can opt in to strike-through pricing and discount labels by reading the
28
+ new field. See `versions/2.11.0/MIGRATION.md` and `../../search.md`.
@@ -0,0 +1,72 @@
1
+ # Migration: 2.10.0 to 2.11.0
2
+
3
+ 2.11.0 adds optional localized discount information to priced v10 search results.
4
+ Existing search calls and rendering remain valid without changes.
5
+
6
+ ## 1. Read the Optional Discount
7
+
8
+ Exact-period items and individual alternative periods may now include:
9
+
10
+ ```ts
11
+ type SearchDiscount = {
12
+ readonly formattedOriginalTotal: string;
13
+ readonly applied: readonly {
14
+ readonly label: string;
15
+ readonly formattedAmount: string;
16
+ }[];
17
+ };
18
+ ```
19
+
20
+ The field is omitted when the REST search backend returns no discount. Keep
21
+ rendering `formattedTotal` as before and add discount presentation only when
22
+ `discount` is present.
23
+
24
+ ## 2. Distinguish Final and Original Totals
25
+
26
+ When a discount is present:
27
+
28
+ - `formattedTotal` is the final price after the applied discounts.
29
+ - `discount.formattedOriginalTotal` is the total before those discounts.
30
+ - `discount.applied` contains presentation-ready localized labels and formatted
31
+ amounts.
32
+
33
+ All monetary values already include locale-aware currency formatting. Backend
34
+ numeric amounts and modifier type keys are intentionally not exposed.
35
+
36
+ ## 3. Handle Exact and Alternative Periods
37
+
38
+ For a fixed-period match, read the field from the item:
39
+
40
+ ```ts
41
+ result.items[0]?.discount;
42
+ ```
43
+
44
+ For a nearby-period suggestion, read it from the individual period:
45
+
46
+ ```ts
47
+ result.alternatives?.[0]?.alternativePeriods[0]?.discount;
48
+ ```
49
+
50
+ Each alternative period has independent pricing and may have a different discount
51
+ or no discount.
52
+
53
+ ## 4. Keep Search Inputs Unchanged
54
+
55
+ No configuration or input migration is required. The SDK continues to request the
56
+ existing default v10 search pricing and does not opt search into alternative
57
+ cancellation-policy pricing.
58
+
59
+ Legacy v9 search does not populate `discount`; consumers supporting both backends
60
+ must treat it as optional.
61
+
62
+ ## Recommended Verification
63
+
64
+ 1. Run a priced v10 exact-period search that has a configured discount and verify
65
+ the final and original totals.
66
+ 2. Verify each applied entry has a localized label and formatted amount in every
67
+ supported locale.
68
+ 3. Run a priced search without a discount and confirm existing rendering is
69
+ unchanged.
70
+ 4. Check nearby alternative periods independently because discounts can differ by
71
+ period.
72
+ 5. If the site supports v9, confirm its existing search output remains unchanged.
@@ -121,6 +121,9 @@ The public output type is unchanged, but v10 search cards now reflect the REST p
121
121
  - `property` is the minimal `{ id, nameOrLabel }` shape. Hydrate `property.location`, `property.images`, or `property.address` from `sdk.static.rentals.getRentals(...)` when a search card needs them.
122
122
  - Exact-period matches are returned in `items` with `formattedTotal`; nearby suggestions are returned in root-level `alternatives`, unchanged.
123
123
 
124
+ Starting with 2.11.0, priced v10 items and alternative periods may also include
125
+ optional localized `discount` details. See `../../search.md`.
126
+
124
127
  ## Backend Behavior
125
128
 
126
129
  - Fixed-period and flexible searches are priced by the REST backend; occupancy is required for priced searches.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@v-office/website-sdk",
3
- "version": "2.9.0",
3
+ "version": "2.11.0",
4
4
  "description": "Website-facing SDK facade backed by @v-office/sdk-core",
5
5
  "bin": {
6
6
  "website-sdk": "./dist/cli.mjs"
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@graphql-typed-document-node/core": "3.2.0",
44
- "@v-office/sdk-core": "^1.9.0",
44
+ "@v-office/sdk-core": "^1.11.0",
45
45
  "effect": "4.0.0-beta.85",
46
46
  "graphql": "16.14.2",
47
47
  "yaml": "^2.9.0"