@v-office/website-sdk 2.4.3 → 2.5.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.
@@ -0,0 +1,43 @@
1
+ # Changelog: 2.5.0
2
+
3
+ Release date: 2026-07-21
4
+
5
+ This release moves v10 rental search onto the dedicated REST search backend, adds optional cross-backend search sorting, and updates static v10 rental loading. Existing public calls and output types remain compatible.
6
+
7
+ ## Added
8
+
9
+ - Added the required `searchEndpoint` field to v10 backend config for the REST search endpoint (for example `https://search.example.com/search`).
10
+ - Added the optional `customAttributeDefinitionManifest` SDK option that maps custom-attribute keys to backend definition IDs for v10 search.
11
+ - Added the `VOFFICE_SEARCH_ENDPOINT` environment variable and the `searchEndpoint` config-file field for the CLI.
12
+ - Added optional `SearchSearchInput.sort` support with Effect schemas and exported types for price, random, rating, and a closed v10 rental-summary field-ordering contract.
13
+ - Added the v9-narrowed `V9SearchSearchSort`, which supports price, random, and rating but excludes v10 field ordering.
14
+ - Added schema-validated CLI `search --sort '<JSON>'` support.
15
+
16
+ ## Changed
17
+
18
+ - v10 `sdk.live.search.search` now calls the REST search backend instead of GraphQL. Period, flexible, occupancy, voucher, filter, and cursor behavior is unchanged.
19
+ - v10 search cards now return at most five images and no image `category`.
20
+ - v10 search-result `property` is now the minimal `{ id, nameOrLabel }` shape; per-property `location`, `images`, and `address` are no longer returned on search cards.
21
+ - v10 custom-attribute search filters and highlights now resolve through `customAttributeDefinitionManifest` instead of a per-search backend lookup.
22
+ - v10 pagination now uses the backend `from`/`size` window directly; the opaque `cursor` and 1,000-result window are unchanged.
23
+ - Price sorting maps to `price_asc`/`price_desc` on v9 and `totalOrderBy` on v10. v10 validates that price sorting has a fixed or flexible pricing mode and occupancy before making a REST request.
24
+ - Supported field sorting maps to v10 `rentalSummaryOrderBy`. The stable subset covers names, room-summary counters, square meters, and beach/city distances. v10 random and rating variants intentionally retain default ordering; v9 forwards them to its backend.
25
+ - v10 `sdk.static.rentals.getRentals` now loads base records from `rentals_listRental` instead of `rentals_listRentalSummary`.
26
+ - v10 rental images are loaded in batches from `rentals_listRentalImage`; only uploaded images are included and existing image output/order is preserved.
27
+ - v10 rental room summaries and room-summary highlights are derived from room types and bed occupancy data, with validation for invalid bed kinds and amounts.
28
+ - v10 rental and rental-image traversal now uses serial keyset pagination instead of offsets. Cursor progress is validated, while the existing public rental and image ordering remains unchanged.
29
+ - The REST search request types retain the `RentalSummary` filter contract independently of static rental GraphQL loading.
30
+
31
+ ## Removed
32
+
33
+ - Removed the internal per-search GraphQL custom-attribute definition lookup and the temporary v10 search-result cache. Both were internal and have no public API surface.
34
+ - Removed the static-rental dependency on `rentals_listRentalSummary`, including its embedded rental images, room summary, and offset pagination.
35
+
36
+ ## Migration Impact
37
+
38
+ - v10 config now requires `searchEndpoint`; add it wherever a v10 `WebsiteSDKConfig` is constructed, and set `VOFFICE_SEARCH_ENDPOINT` for environment/CLI usage. See `versions/2.5.0/MIGRATION.md`.
39
+ - To keep custom-attribute search filters and highlights working on v10, provide `customAttributeDefinitionManifest`.
40
+ - v10 consumers that render `property.location`, `property.images`, or `property.address` from search results must hydrate them from `sdk.static.rentals.getRentals(...)` instead.
41
+ - Existing consumers do not need to add sorting because `sort` is optional. See `versions/2.5.0/MIGRATION.md` before adopting backend-specific sorting.
42
+ - Static rental consumers require no code changes, but custom v10 access tokens must permit both `rentals_listRental` and `rentals_listRentalImage`.
43
+ - v9 config and options are unchanged.
@@ -0,0 +1,135 @@
1
+ # Migration: 2.4.3 to 2.5.0
2
+
3
+ This guide covers upgrading `@v-office/website-sdk` from 2.4.3 to 2.5.0.
4
+
5
+ 2.5.0 keeps `createWebsiteSDK({ config, options })`, the flat `WebsiteSDKConfig`, and existing SDK calls. v10 search now runs against the dedicated REST search backend, which requires one new config field and, for custom-attribute search, one new option. Search input also gains optional sorting, and static v10 rental loading uses the full Rental APIs internally. Existing calls and output types remain compatible.
6
+
7
+ ## Required: v10 searchEndpoint
8
+
9
+ v10 config now requires `searchEndpoint`, the full REST search URL including the `/search` path:
10
+
11
+ ```ts
12
+ const sdk = createWebsiteSDK({
13
+ config: {
14
+ backend: "v10",
15
+ apiEndpoint: "https://api.example.com/graphql",
16
+ searchEndpoint: "https://search.example.com/search",
17
+ accessToken: "...",
18
+ imageBaseUrl: "https://images.example.com",
19
+ },
20
+ });
21
+ ```
22
+
23
+ Provide the same value wherever v10 config is built:
24
+
25
+ - CLI config files add a `searchEndpoint` string field.
26
+ - Environment-based CLI usage reads `VOFFICE_SEARCH_ENDPOINT`.
27
+
28
+ `apiEndpoint` is still required: v10 rentals, filters, quote, availability, booking, and contact continue to use GraphQL. `searchEndpoint` is a separate host and should be configured explicitly rather than derived from `apiEndpoint`.
29
+
30
+ ## Static Rental Loading (v10)
31
+
32
+ `sdk.static.rentals.getRentals(...)` keeps the same input, output, rental ordering, image ordering, and localization behavior. Internally, 2.5.0:
33
+
34
+ - Loads rentals from `rentals_listRental` instead of `rentals_listRentalSummary`.
35
+ - Batch-loads uploaded rental images from `rentals_listRentalImage`.
36
+ - Derives room counts and occupancy summaries from rooms and beds.
37
+ - Uses validated serial keyset pagination for rentals and images instead of offset pagination.
38
+
39
+ Most consumers require no changes. If your v10 access token uses a custom role or restricted operation allowlist, grant access to both `rentals_listRental` and `rentals_listRentalImage`. A token that can only call `rentals_listRentalSummary` will no longer be sufficient for `getRentals`.
40
+
41
+ ## Custom Attribute Manifest
42
+
43
+ The REST search backend filters and returns custom attributes by definition ID, while SDK configuration and query strings use keys. Because definition IDs are workspace/environment specific, the SDK no longer looks them up at search time. To use searchable custom-attribute filters or to surface custom-attribute highlights on v10 search results, provide a `customAttributeDefinitionManifest` that maps keys to IDs:
44
+
45
+ ```ts
46
+ const options = defineWebsiteSDKOptions({
47
+ customAttributeDefinitionManifest: {
48
+ byKey: {
49
+ region: { id: "def-1", key: "region", type: "OPTION", visibility: "PUBLIC" },
50
+ },
51
+ byId: {
52
+ "def-1": { id: "def-1", key: "region", type: "OPTION", visibility: "PUBLIC" },
53
+ },
54
+ },
55
+ });
56
+ ```
57
+
58
+ Generate the manifest at build time from your definitions source, and pass a separate manifest per workspace/environment because IDs are not portable. Without a manifest:
59
+
60
+ - Custom-attribute query keys are left in `unusedFilterKeys` rather than applied.
61
+ - Custom-attribute highlights are not added to search items.
62
+ - All other search behavior (period, occupancy, catalog filters, voucher, pagination) is unchanged.
63
+
64
+ Definitions with `visibility` of `PUBLIC` (or `null`) are surfaced as highlights; others are ignored.
65
+
66
+ ## Optional Search Sorting
67
+
68
+ `SearchSearchInput` now accepts an optional discriminated sort:
69
+
70
+ ```ts
71
+ type SearchSearchSort =
72
+ | { by: "price"; direction: "ASC" | "DESC" }
73
+ | { by: "random" }
74
+ | { by: "rating" }
75
+ | { by: "field"; orderBy: SearchSearchFieldOrderBy };
76
+ ```
77
+
78
+ Existing searches require no change. When adopting sorting:
79
+
80
+ - Price, random, and rating inputs are source-compatible between v9 and v10.
81
+ - v9 price sorting maps to `price_asc`/`price_desc`; random and rating are forwarded to the v9 backend.
82
+ - v10 price sorting maps to `totalOrderBy`. It requires a fixed-period or flexible-date pricing query with occupancy and fails validation before transport when either is missing.
83
+ - v10 random and rating currently select the default backend order.
84
+ - The closed `field` contract maps supported name, room-summary, square-meter, and distance fields to v10 `rentalSummaryOrderBy`; it is excluded from `V9SearchSearchSort`.
85
+ - v9 may retain promoted results before the requested order. v10 price results are ordered by backend boost first and total second.
86
+
87
+ Examples:
88
+
89
+ ```ts
90
+ await sdk.live.search.search({
91
+ locale: "de-DE",
92
+ query: "start=01-08-2026&end=08-08-2026&adults=2",
93
+ sort: { by: "price", direction: "ASC" },
94
+ });
95
+
96
+ await sdk.live.search.search({
97
+ locale: "de-DE",
98
+ query: "adults=2",
99
+ sort: { by: "field", orderBy: { label: "ASC" } }, // v10 only
100
+ });
101
+ ```
102
+
103
+ The CLI accepts the same schema as JSON:
104
+
105
+ ```sh
106
+ website-sdk --backend v10 search --locale de-DE --query "start=01-08-2026&end=08-08-2026&adults=2" --sort '{"by":"price","direction":"ASC"}'
107
+ ```
108
+
109
+ See `../../search.md` for all variants, supported field-order examples, backend behavior, and CLI usage.
110
+
111
+ ## Search Result Changes (v10)
112
+
113
+ The public output type is unchanged, but v10 search cards now reflect the REST projection:
114
+
115
+ - At most five images per item; search images no longer include `category`.
116
+ - `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.
117
+ - Exact-period matches are returned in `items` with `formattedTotal`; nearby suggestions are returned in root-level `alternatives`, unchanged.
118
+
119
+ ## Backend Behavior
120
+
121
+ - Fixed-period and flexible searches are priced by the REST backend; occupancy is required for priced searches.
122
+ - Pagination uses `from`/`size` with the existing opaque `cursor`; a cursor is never advertised beyond the 1,000-result window.
123
+ - Requests remain rate-limited to one backend request per second with a queue size of five.
124
+ - Existing v9 search calls remain compatible; sorting is the only added v9 search capability.
125
+
126
+ ## Recommended Steps
127
+
128
+ 1. Upgrade to `@v-office/website-sdk` 2.5.0.
129
+ 2. Add `searchEndpoint` to every v10 `WebsiteSDKConfig` and set `VOFFICE_SEARCH_ENDPOINT` for environment/CLI runs.
130
+ 3. If you use custom-attribute search filters or highlights, generate and pass `customAttributeDefinitionManifest`.
131
+ 4. Update any search-card UI that reads `property.location`, `property.images`, or `property.address` to hydrate from rentals.
132
+ 5. Cap rendered search images at five and stop relying on image `category` for v10 search cards.
133
+ 6. If adopting sorting, use only shared variants for code that can run against v9, and keep field ordering in v10-narrowed code.
134
+ 7. Confirm the v10 access token permits `rentals_listRental` and `rentals_listRentalImage`, then smoke-test `sdk.static.rentals.getRentals`.
135
+ 8. Smoke-test unpriced, fixed-period, and flexible v10 searches, including pagination and any requested ordering.
@@ -1,4 +1,4 @@
1
- import { n as stable_filters_default } from "./client-BORwUo4_.mjs";
1
+ import { n as stable_filters_default } from "./client-Cnf-pbry.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-CxWlq76f.mjs";
3
3
  import { CoreSDKError, STABLE_SEARCH_INPUTS, collectQueryParameters, daysBetweenLocalDates, expandCustomAttributeFilterCompositions, parseChildrenAges, parseOccupancyCount, parseQueryParameters, toCustomAttributeFilterLabel, toFormattedSearchPrice, toIsoDateFromPeriodQueryDate, toQueryString, toStableSearchInputBackendQueryKeys, toStableSearchInputParameterValues, toStableSearchInputQueryKeys, toUnusedFilterKeys } from "@v-office/sdk-core";
4
4
  import { Effect } from "effect";
@@ -292,8 +292,18 @@ const toPeriodInput = ({ query }) => Effect.gen(function* () {
292
292
  };
293
293
  });
294
294
  //#endregion
295
+ //#region src/legacy-v9/parser/search/input/to-voffice-sorting.ts
296
+ const toVofficeSorting = (sort) => {
297
+ if (sort === void 0) return void 0;
298
+ switch (sort.by) {
299
+ case "price": return sort.direction === "ASC" ? "price_asc" : "price_desc";
300
+ case "random": return "random";
301
+ case "rating": return "rating";
302
+ }
303
+ };
304
+ //#endregion
295
305
  //#region src/legacy-v9/parser/search/input/to-query-input.ts
296
- const toQueryInput = ({ query, customAttributeFilterDefinitions, locale, translations }) => Effect.gen(function* () {
306
+ const toQueryInput = ({ query, sort, customAttributeFilterDefinitions, locale, translations }) => Effect.gen(function* () {
297
307
  const compositionResult = expandCustomAttributeFilterCompositions({
298
308
  customAttributeFilterDefinitions,
299
309
  locale,
@@ -325,7 +335,8 @@ const toQueryInput = ({ query, customAttributeFilterDefinitions, locale, transla
325
335
  queryInput: {
326
336
  vofficeData: {
327
337
  filter: Object.keys(filter).length > 0 ? filter : void 0,
328
- alternatives: true
338
+ alternatives: true,
339
+ sorting: toVofficeSorting(sort)
329
340
  },
330
341
  basicQueryInputs
331
342
  },
@@ -4,6 +4,7 @@ This file is the versioned changelog index for the website SDK instructions.
4
4
 
5
5
  ## Versions
6
6
 
7
+ - `versions/2.5.0/CHANGELOG.md`: `@v-office/website-sdk` 2.5.0 release notes.
7
8
  - `versions/2.4.3/CHANGELOG.md`: `@v-office/website-sdk` 2.4.3 documentation release notes.
8
9
  - `versions/2.4.2/CHANGELOG.md`: `@v-office/website-sdk` 2.4.2 release notes.
9
10
  - `versions/2.4.0/CHANGELOG.md`: `@v-office/website-sdk` 2.4.0 release notes.
@@ -4,6 +4,7 @@ This file is the versioned migration index for the website SDK instructions.
4
4
 
5
5
  ## Available Guides
6
6
 
7
+ - `versions/2.5.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.4.3 to 2.5.0.
7
8
  - `versions/2.4.3/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.4.2 to 2.4.3.
8
9
  - `versions/2.4.2/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.4.1 to 2.4.2.
9
10
  - `versions/2.4.0/MIGRATION.md`: migrate from `@v-office/website-sdk` 2.3.x to 2.4.0.
@@ -1,6 +1,6 @@
1
1
  # Website SDK Instructions
2
2
 
3
- These instructions describe `@v-office/website-sdk` 2.4.3.
3
+ These instructions describe `@v-office/website-sdk` 2.5.0.
4
4
 
5
5
  Use this directory as the consumer-facing reference for the package:
6
6
 
@@ -15,6 +15,7 @@ Use this directory as the consumer-facing reference for the package:
15
15
  - `document-structured-json.md`: `sdk.static.documents.getTermsAndPrivacyPolicy` and structured document JSON rendering rules.
16
16
  - `CHANGELOG.md`: versioned changelog index.
17
17
  - `MIGRATION.md`: versioned migration index.
18
+ - `versions/2.5.0/`: 2.5.0 release notes and 2.4.3-to-2.5.0 migration guide.
18
19
  - `versions/2.4.3/`: 2.4.3 documentation release notes and migration guide.
19
20
  - `versions/2.4.2/`: 2.4.2 release notes and 2.4.1-to-2.4.2 migration guide.
20
21
  - `versions/2.4.0/`: 2.4.0 release notes and 2.3.x-to-2.4.0 migration guide.
@@ -39,6 +40,7 @@ const sdk = createWebsiteSDK({
39
40
  config: {
40
41
  backend: "v10",
41
42
  apiEndpoint: "https://api.example.com/graphql",
43
+ searchEndpoint: "https://search.example.com/search",
42
44
  accessToken: "...",
43
45
  imageBaseUrl: "https://images.example.com",
44
46
  },
@@ -63,6 +65,7 @@ try {
63
65
  website-sdk --backend v10 rentals --locale de-DE
64
66
  website-sdk --backend v9 filters --locale en-US
65
67
  website-sdk --backend v10 search --locale de-DE --query "adults=2"
68
+ website-sdk --backend v10 search --locale de-DE --query "adults=2" --sort '{"by":"field","orderBy":{"label":"ASC"}}'
66
69
  ```
67
70
 
68
- Config file examples in these docs use the flat `WebsiteSDKConfig` shape introduced in 2.0.0 and kept in 2.4.3.
71
+ Config file examples in these docs use the flat `WebsiteSDKConfig` shape introduced in 2.0.0 and kept in 2.5.0. v10 config additionally requires `searchEndpoint` as of 2.5.0.
@@ -118,6 +118,7 @@ Use flat `WebsiteSDKConfig` files.
118
118
  {
119
119
  "backend": "v10",
120
120
  "apiEndpoint": "https://api.example.com/graphql",
121
+ "searchEndpoint": "https://search.example.com/search",
121
122
  "accessToken": "...",
122
123
  "imageBaseUrl": "https://images.example.com"
123
124
  }
@@ -154,4 +155,4 @@ website-sdk --backend v10 availability initial --rental-id 123 --calculate-from-
154
155
  Environment variables:
155
156
 
156
157
  - `v9`: `HUB_GRAPHQL_URL`, `HUB_V1_API_BASE_URL`, optional `HUB_V0_API_BASE_URL`, `HUB_API_KEY`, `IMAGE_PROXY_BASE_URL`.
157
- - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
158
+ - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_SEARCH_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
@@ -162,4 +162,4 @@ website-sdk --backend v10 --config ./website-sdk-config.json booking book --quot
162
162
  Environment variables:
163
163
 
164
164
  - `v9`: `HUB_GRAPHQL_URL`, `HUB_V1_API_BASE_URL`, optional `HUB_V0_API_BASE_URL`, `HUB_API_KEY`, `IMAGE_PROXY_BASE_URL`.
165
- - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
165
+ - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_SEARCH_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
@@ -107,4 +107,4 @@ Without `--yes`, the command fails before submitting because contact requests se
107
107
  Environment variables:
108
108
 
109
109
  - `v9`: `HUB_GRAPHQL_URL`, `HUB_V1_API_BASE_URL`, optional `HUB_V0_API_BASE_URL`, `HUB_API_KEY`, `IMAGE_PROXY_BASE_URL`.
110
- - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
110
+ - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_SEARCH_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
@@ -11,6 +11,7 @@ const sdk = createWebsiteSDK({
11
11
  config: {
12
12
  backend: "v10",
13
13
  apiEndpoint: "https://api.example.com/graphql",
14
+ searchEndpoint: "https://search.example.com/search",
14
15
  accessToken: "...",
15
16
  imageBaseUrl: "https://images.example.com",
16
17
  },
@@ -58,6 +59,7 @@ const sdk = createWebsiteSDK({
58
59
  config: {
59
60
  backend: "v10",
60
61
  apiEndpoint: "https://api.example.com/graphql",
62
+ searchEndpoint: "https://search.example.com/search",
61
63
  accessToken: "...",
62
64
  imageBaseUrl: "https://images.example.com",
63
65
  },
@@ -66,6 +68,8 @@ const sdk = createWebsiteSDK({
66
68
 
67
69
  For v10, `backend: "v10"` is optional in TypeScript, but including it is clearer when config files are shared with the CLI.
68
70
 
71
+ For v10, `searchEndpoint` is required as of 2.5.0. It is the full REST search URL including the `/search` path and is a separate host from `apiEndpoint` (which still serves rentals, filters, quote, availability, booking, and contact over GraphQL). Configure it explicitly rather than deriving it from `apiEndpoint`.
72
+
69
73
  ## WebsiteSDKOptions
70
74
 
71
75
  `options` is optional and is passed separately from backend config:
@@ -88,6 +92,7 @@ const options = defineWebsiteSDKOptions({
88
92
  type WebsiteSDKOptions = {
89
93
  translationOverrides?: TranslationOverrides;
90
94
  customAttributeFilterDefinitions?: readonly CustomAttributeFilterDefinition[];
95
+ customAttributeDefinitionManifest?: CustomAttributeDefinitionManifest;
91
96
  rentalHighlightPrioritization?: readonly RentalHighlightPrioritizationKey[];
92
97
  rentalPropertyHighlightPrioritization?: readonly RentalPropertyHighlightPrioritizationKey[];
93
98
  rentalScope?: RentalScope;
@@ -98,6 +103,7 @@ type WebsiteSDKOptions = {
98
103
  Unset options are normalized by the SDK:
99
104
 
100
105
  - `customAttributeFilterDefinitions` defaults to `[]`.
106
+ - `customAttributeDefinitionManifest` is omitted unless provided; an absent manifest is treated as empty.
101
107
  - `rentalHighlightPrioritization` defaults to the SDK default rental highlight order.
102
108
  - `rentalPropertyHighlightPrioritization` defaults to the SDK default property highlight order.
103
109
  - `rentalScope` defaults to `{}`.
@@ -176,6 +182,43 @@ Visibility:
176
182
  - `internal: true` keeps filters usable by search and compositions but hides them from `getFilters`.
177
183
  - `searchable: false` keeps custom attributes as display metadata only.
178
184
 
185
+ ## Custom Attribute Definition Manifest
186
+
187
+ The v10 REST search backend filters and returns custom attributes by definition ID, while SDK configuration and query strings use keys. Because definition IDs are workspace/environment specific, use `customAttributeDefinitionManifest` to give the SDK a key-to-ID and ID-to-key mapping:
188
+
189
+ ```ts
190
+ const options = defineWebsiteSDKOptions({
191
+ customAttributeDefinitionManifest: {
192
+ byKey: {
193
+ region: { id: "def-1", key: "region", type: "OPTION", visibility: "PUBLIC" },
194
+ },
195
+ byId: {
196
+ "def-1": { id: "def-1", key: "region", type: "OPTION", visibility: "PUBLIC" },
197
+ },
198
+ },
199
+ });
200
+ ```
201
+
202
+ ```ts
203
+ type CustomAttributeDefinitionManifestEntry = {
204
+ id: string;
205
+ key: string;
206
+ type: "BOOLEAN" | "INT" | "STRING" | "OPTION";
207
+ visibility: "PUBLIC" | string | null;
208
+ options?: readonly { value: string; label?: Record<string, string> }[];
209
+ };
210
+
211
+ type CustomAttributeDefinitionManifest = {
212
+ byKey: Record<string, CustomAttributeDefinitionManifestEntry>;
213
+ byId: Record<string, CustomAttributeDefinitionManifestEntry>;
214
+ };
215
+ ```
216
+
217
+ - Generate the manifest at build time from your definitions source, and pass a separate manifest per workspace/environment because IDs are not portable.
218
+ - Custom-attribute keys that have no manifest entry are left in `unusedFilterKeys` instead of being applied as filters.
219
+ - Only definitions with `visibility` of `PUBLIC` (or `null`) are surfaced as v10 search highlights; others are ignored.
220
+ - The manifest is only used by v10 search. v9 and the non-search v10 endpoints ignore it.
221
+
179
222
  ## Translation Overrides
180
223
 
181
224
  Use `translationOverrides` to override SDK translation keys:
@@ -206,6 +249,7 @@ Example `website-sdk-config.v10.json`:
206
249
  {
207
250
  "backend": "v10",
208
251
  "apiEndpoint": "https://api.example.com/graphql",
252
+ "searchEndpoint": "https://search.example.com/search",
209
253
  "accessToken": "...",
210
254
  "imageBaseUrl": "https://images.example.com"
211
255
  }
@@ -91,6 +91,7 @@ Filter variants:
91
91
  {
92
92
  "backend": "v10",
93
93
  "apiEndpoint": "https://api.example.com/graphql",
94
+ "searchEndpoint": "https://search.example.com/search",
94
95
  "accessToken": "...",
95
96
  "imageBaseUrl": "https://images.example.com"
96
97
  }
@@ -155,4 +156,4 @@ website-sdk --backend v10 filters --locale de-DE --output pretty
155
156
  Environment variables:
156
157
 
157
158
  - `v9`: `HUB_GRAPHQL_URL`, `HUB_V1_API_BASE_URL`, optional `HUB_V0_API_BASE_URL`, `HUB_API_KEY`, `IMAGE_PROXY_BASE_URL`.
158
- - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
159
+ - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_SEARCH_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
@@ -344,4 +344,4 @@ The CLI only creates the initial quote. Additional service, cancellation policy,
344
344
  Environment variables:
345
345
 
346
346
  - `v9`: `HUB_GRAPHQL_URL`, `HUB_V1_API_BASE_URL`, optional `HUB_V0_API_BASE_URL`, `HUB_API_KEY`, `IMAGE_PROXY_BASE_URL`.
347
- - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
347
+ - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_SEARCH_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
@@ -137,6 +137,7 @@ For v10, public answers with the same form-response ID are combined into one rev
137
137
  {
138
138
  "backend": "v10",
139
139
  "apiEndpoint": "https://api.example.com/graphql",
140
+ "searchEndpoint": "https://search.example.com/search",
140
141
  "accessToken": "...",
141
142
  "imageBaseUrl": "https://images.example.com"
142
143
  }
@@ -179,4 +180,4 @@ website-sdk --backend v10 rentals --locale de-DE --output pretty
179
180
  Environment variables:
180
181
 
181
182
  - `v9`: `HUB_GRAPHQL_URL`, `HUB_V1_API_BASE_URL`, optional `HUB_V0_API_BASE_URL`, `HUB_API_KEY`, `IMAGE_PROXY_BASE_URL`.
182
- - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
183
+ - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_SEARCH_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
@@ -23,9 +23,38 @@ type RentalSearchInput = {
23
23
  voucher?: string;
24
24
  limit?: number;
25
25
  cursor?: string;
26
+ sort?: SearchSearchSort;
27
+ };
28
+
29
+ type SearchSearchSort =
30
+ | { by: "price"; direction: "ASC" | "DESC" }
31
+ | { by: "random" }
32
+ | { by: "rating" }
33
+ | { by: "field"; orderBy: SearchSearchFieldOrderBy };
34
+
35
+ type SearchSearchFieldOrderBy = {
36
+ label?: "ASC" | "DESC";
37
+ name?: "ASC" | "DESC";
38
+ roomSummary?: {
39
+ bathrooms?: "ASC" | "DESC";
40
+ bedrooms?: "ASC" | "DESC";
41
+ livingrooms?: "ASC" | "DESC";
42
+ maxAdults?: "ASC" | "DESC";
43
+ maxPersons?: "ASC" | "DESC";
44
+ rooms?: "ASC" | "DESC";
45
+ };
46
+ attributes?: {
47
+ squareMeters?: "ASC" | "DESC";
48
+ };
49
+ vicinity?: {
50
+ beachdistance?: "ASC" | "DESC";
51
+ citydistance?: "ASC" | "DESC";
52
+ };
26
53
  };
27
54
  ```
28
55
 
56
+ The v9 facade narrows `sort` to price, random, or rating. The closed field-sorting contract is v10-only. The SDK also exports the corresponding `SearchSearchSortSchema`, variant schemas, types, and `V9SearchSearchSort`.
57
+
29
58
  Sample:
30
59
 
31
60
  ```json
@@ -34,7 +63,11 @@ Sample:
34
63
  "query": "start=01-07-2026&end=08-07-2026&adults=2&children=1&wifi=true",
35
64
  "rentalIdsIn": ["123", "456"],
36
65
  "voucher": "SUMMER26",
37
- "limit": 20
66
+ "limit": 20,
67
+ "sort": {
68
+ "by": "price",
69
+ "direction": "ASC"
70
+ }
38
71
  }
39
72
  ```
40
73
 
@@ -130,6 +163,66 @@ For v10, `pets` is a mapped BooleanFilter exposed by `getFilters` and maps to on
130
163
 
131
164
  `limit` defaults to `20`. Treat `cursor` as opaque and pass back `pageInfo.nextCursor` unchanged.
132
165
 
166
+ ## Sorting
167
+
168
+ Sorting is optional. The discriminated `sort` union allows exactly one ordering mode per request.
169
+
170
+ Price, random, and rating use the same input in v9 and v10:
171
+
172
+ ```ts
173
+ await sdk.live.search.search({
174
+ locale: "de-DE",
175
+ query: "start=01-08-2026&end=08-08-2026&adults=2",
176
+ sort: { by: "price", direction: "ASC" },
177
+ });
178
+
179
+ await sdk.live.search.search({
180
+ locale: "de-DE",
181
+ query: "adults=2",
182
+ sort: { by: "random" },
183
+ });
184
+
185
+ await sdk.live.search.search({
186
+ locale: "de-DE",
187
+ query: "adults=2",
188
+ sort: { by: "rating" },
189
+ });
190
+ ```
191
+
192
+ Backend behavior:
193
+
194
+ - `price`: v9 maps to `price_asc` or `price_desc`. v10 orders priced alternatives by total and direction. v10 price sorting requires a fixed-period or flexible-date query with occupancy; the SDK rejects incomplete requests before transport.
195
+ - `random`: v9 requests the backend's random ordering. v10 currently keeps the default backend ordering.
196
+ - `rating`: v9 requests the backend's rating ordering. v10 currently keeps the default backend ordering until rating ordering is implemented.
197
+ - v9 may retain backend-promoted results ahead of the requested business order, and its random ordering may be deterministic.
198
+ - v10 price ordering follows the backend's boost-first, total-second behavior, so different boost groups are not globally ordered only by price.
199
+
200
+ v10 additionally supports a stable subset of rental-summary field ordering:
201
+
202
+ ```ts
203
+ await sdk.live.search.search({
204
+ locale: "de-DE",
205
+ query: "adults=2",
206
+ sort: {
207
+ by: "field",
208
+ orderBy: {
209
+ label: "ASC",
210
+ roomSummary: {
211
+ bedrooms: "DESC",
212
+ },
213
+ attributes: {
214
+ squareMeters: "DESC",
215
+ },
216
+ vicinity: {
217
+ beachdistance: "ASC",
218
+ },
219
+ },
220
+ },
221
+ });
222
+ ```
223
+
224
+ The supported fields are `label`, `name`, all six `roomSummary` counters, `attributes.squareMeters`, `vicinity.beachdistance`, and `vicinity.citydistance`. Unknown fields and nesting are not part of the public type and are rejected before transport by the SDK and CLI. The field variant is excluded from `V9SearchSearchSort` and rejected by the CLI when `--backend v9` is selected.
225
+
133
226
  ## Output
134
227
 
135
228
  Returns `Promise<RentalSearchOutput>`.
@@ -192,10 +285,22 @@ Sample:
192
285
 
193
286
  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`.
194
287
 
288
+ ## v10 Backend
289
+
290
+ v10 search runs against the dedicated REST search backend (`POST` to the configured `searchEndpoint`). Existing calls and the output type remain compatible, while the input additionally supports optional sorting. v10 results reflect the REST projection:
291
+
292
+ - At most five images per item, and no image `category`.
293
+ - `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.
294
+ - Custom-attribute search filters and highlights require a `customAttributeDefinitionManifest`; without it, custom-attribute query keys are left in `unusedFilterKeys` and no custom-attribute highlights are added.
295
+ - Fixed-period and flexible searches are priced by the REST backend and require occupancy.
296
+ - Pagination uses the backend `from`/`size` window behind the same opaque `cursor`, capped at 1,000 results.
297
+
195
298
  ## Configuration
196
299
 
197
300
  Use flat `WebsiteSDKConfig` files and optional `WebsiteSDKOptions`.
198
301
 
302
+ For v10, config requires `searchEndpoint` (the full REST search URL) as of 2.5.0. See `creation.md` for `searchEndpoint` and the `customAttributeDefinitionManifest` option.
303
+
199
304
  Custom filter definitions can extend accepted search query keys. Search requests are rate-limited to one backend request per second with a queue size of five.
200
305
 
201
306
  ## CLI Usage
@@ -220,6 +325,14 @@ website-sdk --backend v10 search --locale de-DE --query "adults=2" --rental-ids-
220
325
  website-sdk --backend v10 search --locale de-DE --query "adults=2" --voucher SUMMER26
221
326
  ```
222
327
 
328
+ Pass sorting as schema-validated JSON:
329
+
330
+ ```sh
331
+ website-sdk --backend v9 search --locale de-DE --query "adults=2" --sort '{"by":"random"}'
332
+ website-sdk --backend v10 search --locale de-DE --query "start=01-08-2026&end=08-08-2026&adults=2" --sort '{"by":"price","direction":"ASC"}'
333
+ website-sdk --backend v10 search --locale de-DE --query "adults=2" --sort '{"by":"field","orderBy":{"label":"ASC"}}'
334
+ ```
335
+
223
336
  Use files instead of environment variables:
224
337
 
225
338
  ```sh
@@ -235,4 +348,4 @@ website-sdk --backend v10 search --locale de-DE --query "adults=2" --output pret
235
348
  Environment variables:
236
349
 
237
350
  - `v9`: `HUB_GRAPHQL_URL`, `HUB_V1_API_BASE_URL`, optional `HUB_V0_API_BASE_URL`, `HUB_API_KEY`, `IMAGE_PROXY_BASE_URL`.
238
- - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
351
+ - `v10`: `VOFFICE_API_ENDPOINT`, `VOFFICE_SEARCH_ENDPOINT`, `VOFFICE_LOCAL_DEV_ACCESS_TOKEN`, `VOFFICE_IMAGE_BASE_URL`.
@@ -0,0 +1,43 @@
1
+ # Changelog: 2.5.0
2
+
3
+ Release date: 2026-07-21
4
+
5
+ This release moves v10 rental search onto the dedicated REST search backend, adds optional cross-backend search sorting, and updates static v10 rental loading. Existing public calls and output types remain compatible.
6
+
7
+ ## Added
8
+
9
+ - Added the required `searchEndpoint` field to v10 backend config for the REST search endpoint (for example `https://search.example.com/search`).
10
+ - Added the optional `customAttributeDefinitionManifest` SDK option that maps custom-attribute keys to backend definition IDs for v10 search.
11
+ - Added the `VOFFICE_SEARCH_ENDPOINT` environment variable and the `searchEndpoint` config-file field for the CLI.
12
+ - Added optional `SearchSearchInput.sort` support with Effect schemas and exported types for price, random, rating, and a closed v10 rental-summary field-ordering contract.
13
+ - Added the v9-narrowed `V9SearchSearchSort`, which supports price, random, and rating but excludes v10 field ordering.
14
+ - Added schema-validated CLI `search --sort '<JSON>'` support.
15
+
16
+ ## Changed
17
+
18
+ - v10 `sdk.live.search.search` now calls the REST search backend instead of GraphQL. Period, flexible, occupancy, voucher, filter, and cursor behavior is unchanged.
19
+ - v10 search cards now return at most five images and no image `category`.
20
+ - v10 search-result `property` is now the minimal `{ id, nameOrLabel }` shape; per-property `location`, `images`, and `address` are no longer returned on search cards.
21
+ - v10 custom-attribute search filters and highlights now resolve through `customAttributeDefinitionManifest` instead of a per-search backend lookup.
22
+ - v10 pagination now uses the backend `from`/`size` window directly; the opaque `cursor` and 1,000-result window are unchanged.
23
+ - Price sorting maps to `price_asc`/`price_desc` on v9 and `totalOrderBy` on v10. v10 validates that price sorting has a fixed or flexible pricing mode and occupancy before making a REST request.
24
+ - Supported field sorting maps to v10 `rentalSummaryOrderBy`. The stable subset covers names, room-summary counters, square meters, and beach/city distances. v10 random and rating variants intentionally retain default ordering; v9 forwards them to its backend.
25
+ - v10 `sdk.static.rentals.getRentals` now loads base records from `rentals_listRental` instead of `rentals_listRentalSummary`.
26
+ - v10 rental images are loaded in batches from `rentals_listRentalImage`; only uploaded images are included and existing image output/order is preserved.
27
+ - v10 rental room summaries and room-summary highlights are derived from room types and bed occupancy data, with validation for invalid bed kinds and amounts.
28
+ - v10 rental and rental-image traversal now uses serial keyset pagination instead of offsets. Cursor progress is validated, while the existing public rental and image ordering remains unchanged.
29
+ - The REST search request types retain the `RentalSummary` filter contract independently of static rental GraphQL loading.
30
+
31
+ ## Removed
32
+
33
+ - Removed the internal per-search GraphQL custom-attribute definition lookup and the temporary v10 search-result cache. Both were internal and have no public API surface.
34
+ - Removed the static-rental dependency on `rentals_listRentalSummary`, including its embedded rental images, room summary, and offset pagination.
35
+
36
+ ## Migration Impact
37
+
38
+ - v10 config now requires `searchEndpoint`; add it wherever a v10 `WebsiteSDKConfig` is constructed, and set `VOFFICE_SEARCH_ENDPOINT` for environment/CLI usage. See `versions/2.5.0/MIGRATION.md`.
39
+ - To keep custom-attribute search filters and highlights working on v10, provide `customAttributeDefinitionManifest`.
40
+ - v10 consumers that render `property.location`, `property.images`, or `property.address` from search results must hydrate them from `sdk.static.rentals.getRentals(...)` instead.
41
+ - Existing consumers do not need to add sorting because `sort` is optional. See `versions/2.5.0/MIGRATION.md` before adopting backend-specific sorting.
42
+ - Static rental consumers require no code changes, but custom v10 access tokens must permit both `rentals_listRental` and `rentals_listRentalImage`.
43
+ - v9 config and options are unchanged.