@v-office/website-sdk 2.5.1 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +28 -1
  2. package/dist/cli.mjs +25 -4
  3. package/dist/{client-C5ojrNQA.mjs → client-BNbBfJtO.mjs} +468 -189
  4. package/dist/index.d.mts +5 -4
  5. package/dist/index.mjs +3 -3
  6. package/dist/instructions/CHANGELOG.md +3 -0
  7. package/dist/instructions/MIGRATION.md +3 -0
  8. package/dist/instructions/README.md +8 -2
  9. package/dist/instructions/booking.md +39 -3
  10. package/dist/instructions/creation.md +65 -64
  11. package/dist/instructions/custom-attributes.md +556 -0
  12. package/dist/instructions/filter.md +51 -23
  13. package/dist/instructions/rentals.md +26 -2
  14. package/dist/instructions/search.md +29 -3
  15. package/dist/instructions/versions/2.5.0/MIGRATION.md +5 -0
  16. package/dist/instructions/versions/2.6.0/CHANGELOG.md +6 -0
  17. package/dist/instructions/versions/2.6.0/MIGRATION.md +6 -0
  18. package/dist/instructions/versions/2.7.0/CHANGELOG.md +44 -0
  19. package/dist/instructions/versions/2.7.0/MIGRATION.md +79 -0
  20. package/dist/instructions/versions/2.8.0/CHANGELOG.md +63 -0
  21. package/dist/instructions/versions/2.8.0/MIGRATION.md +252 -0
  22. package/dist/{rentals-Lw1qUKIj.mjs → rentals-cCejb_2d.mjs} +21 -21
  23. package/dist/{search-9yzAqHCg.mjs → search-Dzzra6IW.mjs} +16 -133
  24. package/dist/{to-rental-highlights-CxWlq76f.mjs → to-rental-highlights-OvNe9ZQS.mjs} +8 -6
  25. package/dist/translations/v10/de-DE/core.json +2 -0
  26. package/dist/translations/v10/en-US/core.json +2 -0
  27. package/instructions/CHANGELOG.md +3 -0
  28. package/instructions/MIGRATION.md +3 -0
  29. package/instructions/README.md +8 -2
  30. package/instructions/booking.md +39 -3
  31. package/instructions/creation.md +65 -64
  32. package/instructions/custom-attributes.md +556 -0
  33. package/instructions/filter.md +51 -23
  34. package/instructions/rentals.md +26 -2
  35. package/instructions/search.md +29 -3
  36. package/instructions/versions/2.5.0/MIGRATION.md +5 -0
  37. package/instructions/versions/2.6.0/CHANGELOG.md +6 -0
  38. package/instructions/versions/2.6.0/MIGRATION.md +6 -0
  39. package/instructions/versions/2.7.0/CHANGELOG.md +44 -0
  40. package/instructions/versions/2.7.0/MIGRATION.md +79 -0
  41. package/instructions/versions/2.8.0/CHANGELOG.md +63 -0
  42. package/instructions/versions/2.8.0/MIGRATION.md +252 -0
  43. package/package.json +5 -3
@@ -147,14 +147,38 @@ Optional `WebsiteSDKOptions`:
147
147
 
148
148
  ```json
149
149
  {
150
- "rentalHighlightPrioritization": ["bedrooms", "bathrooms", "maxPersons", "wifi"],
150
+ "customAttributes": {
151
+ "catalog": {
152
+ "privateSauna": {
153
+ "id": "GQYKYgMVh28X7VLGursbkt",
154
+ "type": "BOOLEAN"
155
+ }
156
+ },
157
+ "select": {
158
+ "privateSauna": {
159
+ "label": { "de-DE": "Sauna", "en-US": "Sauna" }
160
+ }
161
+ }
162
+ },
163
+ "rentalHighlightPrioritization": ["bedrooms", "privateSauna", "wifi"],
151
164
  "rentalPropertyHighlightPrioritization": ["wifi", "parking"],
152
165
  "customAttributeFilterDefinitions": [],
153
166
  "translationOverrides": {}
154
167
  }
155
168
  ```
156
169
 
157
- `rentalHighlightPrioritization` controls the order of rental `highlights`. `rentalPropertyHighlightPrioritization` controls property highlights for v10 property data. Custom attribute definitions can add custom values to rental output. Translation overrides affect localized labels.
170
+ `rentalHighlightPrioritization` controls the order of rental `highlights`. `rentalPropertyHighlightPrioritization` controls property highlights for v10 property data. Translation overrides affect localized labels.
171
+
172
+ In CLI JSON, `customAttributes` contains catalog and selection inputs; the CLI builds
173
+ the validated registry. Typed applications normally call `defineCustomAttributes`
174
+ and pass its result instead.
175
+
176
+ Custom attributes configured through `customAttributes` add values to rental output on
177
+ both backends. A value appears in `highlights` only when its key is listed in
178
+ `rentalHighlightPrioritization`, and in `attributes` under the group named by its
179
+ authored `category` — alongside built-in attributes of that category, not in a separate
180
+ bucket. Category and attribute `label`s in the output are localized strings, never
181
+ stable keys. See `custom-attributes.md`.
158
182
 
159
183
  ## CLI Usage
160
184
 
@@ -272,7 +272,12 @@ Sample:
272
272
  "appliedFilters": [
273
273
  {
274
274
  "key": "wifi",
275
- "label": "WiFi"
275
+ "label": "WLAN"
276
+ },
277
+ {
278
+ "key": "region",
279
+ "label": "Region: Norden",
280
+ "value": "north"
276
281
  }
277
282
  ],
278
283
  "unusedFilterKeys": [],
@@ -285,13 +290,34 @@ Sample:
285
290
 
286
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`.
287
292
 
293
+ `appliedFilters` reports what the backend actually applied, and is what a "remove
294
+ this filter" chip should be built from. `label` is localized presentation and can
295
+ repeat, so it cannot identify a filter; `key` plus `value` can. `value` is the
296
+ canonical applied value and is present only for filters that carry one — on/off
297
+ filters are identified by `key` alone. A key you sent that is **not** listed here
298
+ appears in `unusedFilterKeys` and had no effect on the result set. A scalar key may
299
+ appear in both arrays when its first value was applied but additional values were
300
+ rejected.
301
+
302
+ Composition filters are atomic in both metadata and the backend payload. The SDK
303
+ validates all configured leaves against the active backend before committing any
304
+ generated GraphQL or REST input. If one leaf is unsupported or malformed, no
305
+ composition-generated leaf restricts the result, and only the composition key is
306
+ reported unused. Direct filters are tracked independently and remain applied even
307
+ when a failed composition references the same key.
308
+
309
+ When every leaf succeeds, `appliedFilters` contains both the composition entry and
310
+ the expanded leaf entries. A UI may collapse those leaves under the composition for
311
+ display, but should keep the returned keys and canonical values when removing direct
312
+ filters.
313
+
288
314
  ## v10 Backend
289
315
 
290
316
  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
317
 
292
318
  - At most five images per item, and no image `category`.
293
319
  - `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.
320
+ - 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`.
295
321
  - Fixed-period and flexible searches are priced by the REST backend and require occupancy.
296
322
  - Pagination uses the backend `from`/`size` window behind the same opaque `cursor`, capped at 1,000 results.
297
323
 
@@ -299,7 +325,7 @@ v10 search runs against the dedicated REST search backend (`POST` to the configu
299
325
 
300
326
  Use flat `WebsiteSDKConfig` files and optional `WebsiteSDKOptions`.
301
327
 
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.
328
+ For v10, config requires `searchEndpoint` (the full REST search URL) as of 2.5.0. See `creation.md` for `searchEndpoint` and the `customAttributes` option.
303
329
 
304
330
  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.
305
331
 
@@ -1,5 +1,10 @@
1
1
  # Migration: 2.4.3 to 2.5.0
2
2
 
3
+ > Custom-attribute manifest guidance below is historically correct for 2.5.x but is
4
+ > superseded in 2.8.0. When upgrading current packages, follow
5
+ > `../2.8.0/MIGRATION.md` to replace `customAttributeDefinitionManifest` with
6
+ > `defineCustomAttributes`.
7
+
3
8
  This guide covers upgrading `@v-office/website-sdk` from 2.4.3 to 2.5.0.
4
9
 
5
10
  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.
@@ -0,0 +1,6 @@
1
+ # Changelog: 2.6.0
2
+
3
+ `@v-office/website-sdk` 2.6.0 was never published. The Stripe Checkout work
4
+ documented under this version during development shipped as 2.7.0 on 2026-07-27.
5
+
6
+ Use `../2.7.0/CHANGELOG.md` as the authoritative release record.
@@ -0,0 +1,6 @@
1
+ # Migration: 2.6.0
2
+
3
+ `@v-office/website-sdk` 2.6.0 was never published. The planned Stripe Checkout
4
+ change shipped in 2.7.0.
5
+
6
+ Consumers upgrading from 2.5.x should follow `../2.7.0/MIGRATION.md`.
@@ -0,0 +1,44 @@
1
+ # Changelog: 2.7.0
2
+
3
+ Release date: 2026-07-27
4
+
5
+ This release makes v9 `stripe_checkout` payment options submittable. The vOffice
6
+ `initStripePayment` action returns only session metadata, so `submitPaymentOption`
7
+ now opens the Checkout Session with Stripe.js when the backend omits the session
8
+ URL. Config, service calls, and output types are unchanged.
9
+
10
+ ## Added
11
+
12
+ - `submitPaymentOption` and `submitPaymentOptionEffect` now complete
13
+ `stripe_checkout` options that carry only `sessionId` and `accountId`.
14
+ - Stripe.js is loaded from `https://js.stripe.com/v3/` on first use and reused for
15
+ later submissions. Failed loads are not cached, and an existing `window.Stripe`
16
+ is reused.
17
+ - The SDK includes the vOffice Stripe platform publishable keys, so Stripe Checkout
18
+ needs no consumer key configuration.
19
+
20
+ ## Changed
21
+
22
+ - `stripe_checkout` prefers a Checkout Session `url` and falls back to Stripe.js
23
+ only when the URL is absent.
24
+ - Test (`cs_test_`) and live (`cs_live_`) sessions select the corresponding
25
+ publishable key automatically.
26
+ - Connected-account sessions pass `accountId` to Stripe.js as `stripeAccount`.
27
+ - Missing-session failures now name both the absent URL and session ID.
28
+
29
+ ## Migration Impact
30
+
31
+ - Sites that hid Stripe options because `url` was absent can render them again.
32
+ Gate the button on the payment option being present rather than on `option.url`.
33
+ - Content-Security-Policy must allow `script-src https://js.stripe.com` and
34
+ `frame-src https://js.stripe.com https://hooks.stripe.com`.
35
+ - Payment submission remains browser-only. A Stripe script or redirect failure is
36
+ a payment failure after the booking exists, not a booking failure.
37
+ - No config, service-call, or output migration is required. See
38
+ `versions/2.7.0/MIGRATION.md`.
39
+
40
+ ## Versioning Note
41
+
42
+ The implementation was documented during development under a planned 2.6.0
43
+ directory, but 2.6.0 was never published. The package was released as 2.7.0; this
44
+ directory is the authoritative release record.
@@ -0,0 +1,79 @@
1
+ # Migration: 2.5.x to 2.7.0
2
+
3
+ This guide covers upgrading `@v-office/website-sdk` from 2.5.0 or 2.5.1 to 2.7.0.
4
+ Version 2.6.0 was not published.
5
+
6
+ 2.7.0 changes no config, service call, or output type. The runtime change is that
7
+ v9 `stripe_checkout` payment options can now be submitted. Sites without Stripe
8
+ need no migration work.
9
+
10
+ ## Remove Stripe Workarounds
11
+
12
+ vOffice's `initStripePayment` action can return `sessionId` and `accountId` without
13
+ the Checkout Session URL. The SDK now keeps URL redirects as the preferred path and
14
+ uses Stripe.js when only session metadata is available.
15
+
16
+ Sites that hid Stripe options without a URL should render them:
17
+
18
+ ```ts
19
+ // Before
20
+ const payable = option.kind !== "stripe_checkout" || option.url !== undefined;
21
+
22
+ // 2.7.0
23
+ const payable = true;
24
+ ```
25
+
26
+ Delete site-level Stripe.js bridges and publishable-key configuration added only to
27
+ work around the missing URL. The SDK selects the vOffice platform test or live key
28
+ from the session ID and passes connected-account context automatically.
29
+
30
+ ## Content-Security-Policy
31
+
32
+ If the site sets a CSP, allow:
33
+
34
+ ```text
35
+ script-src https://js.stripe.com
36
+ frame-src https://js.stripe.com https://hooks.stripe.com
37
+ ```
38
+
39
+ Without these directives, Stripe submission fails. Other payment kinds are
40
+ unaffected.
41
+
42
+ ## Error Handling
43
+
44
+ Stripe.js loading or redirecting can fail. These failures surface as
45
+ `CoreSDKError` with `operation: "paymentSubmission"`. A failed script load is not
46
+ cached, so retrying can succeed.
47
+
48
+ The booking already exists when payment options are rendered. Present a submission
49
+ failure as a payment problem with the booking number, never as a failed booking:
50
+
51
+ ```ts
52
+ try {
53
+ await sdk.live.booking.submitPaymentOption(option);
54
+ } catch (error) {
55
+ showPaymentFailure({ bookingNumber: booking.bookingNumber, error });
56
+ }
57
+ ```
58
+
59
+ Submission remains browser-only.
60
+
61
+ ## Payment Return
62
+
63
+ The SDK derives Stripe success and cancel URLs from the `relativeRedirectUrl`
64
+ passed to `sdk.live.booking.book(...)`, appending
65
+ `payment=stripe&success=true` or `payment=stripe&cancel=true`. Persist anything the
66
+ return page needs before submitting the payment option because the redirect URL is
67
+ configured before the booking number exists.
68
+
69
+ A `success=true` return means the browser returned from Stripe, not that payment
70
+ settled. Stripe's webhook confirms payment to vOffice.
71
+
72
+ ## Recommended Steps
73
+
74
+ 1. Upgrade to `@v-office/website-sdk` 2.7.0.
75
+ 2. Remove checks that hide Stripe options when `option.url` is missing.
76
+ 3. Remove any site-owned Stripe.js bridge and publishable key used for this flow.
77
+ 4. Add the Stripe CSP directives when applicable.
78
+ 5. Present submission failures as post-booking payment failures.
79
+ 6. Smoke-test test-mode and live-mode tenants, including success and cancel returns.
@@ -0,0 +1,63 @@
1
+ # Changelog: 2.8.0
2
+
3
+ This release replaces the loose custom-attribute manifest/configuration split with a
4
+ validated catalog-backed registry shared by rental display, highlights, filter
5
+ discovery, and search.
6
+
7
+ ## Added
8
+
9
+ - `fetchCustomAttributeCatalog({ config })` reads public v10 custom-attribute
10
+ definition IDs, keys, types, and option identities at build time.
11
+ - `defineCustomAttributes(...)` joins that catalog with authored labels, exposure,
12
+ display, category, v9 bindings, and option labels.
13
+ - `defineCustomAttributesFromUnknown(...)`, `parseCustomAttributeCatalog`, and
14
+ `CustomAttributeCatalogSchema` support CLI/JSON and other untyped inputs.
15
+ - The website package exports the catalog, selection, registry, resolved-attribute,
16
+ category, and override types needed to author typed configuration.
17
+ - v10 reads public custom-attribute values for rentals and search output. v9 can
18
+ render the same registry through explicit `p_*` rental-data bindings and `v9Only`
19
+ entries.
20
+ - Applied value-bearing filters include a canonical `value`, allowing consumers to
21
+ remove one exact filter value without relying on a localized label.
22
+
23
+ ## Changed
24
+
25
+ - `WebsiteSDKOptions.customAttributes` now receives the validated registry returned
26
+ by `defineCustomAttributes`.
27
+ - `customAttributeFilterDefinitions` now contains only `backendFilter` and
28
+ `composition` definitions. Catalog-backed custom attributes get their filter
29
+ policy from the registry selection.
30
+ - v10 custom-attribute filters are advertised only when filtering is enabled and a
31
+ backend definition ID exists. v9 does not advertise or execute catalog custom
32
+ attributes.
33
+ - Public/internal filter exposure and display are independent. Internal filters are
34
+ queryable and usable by compositions but absent from `getFilters`.
35
+ - Custom-attribute categories, backend-filter categories, and composition
36
+ categories are returned as localized display labels. Configuration continues to
37
+ store stable category keys.
38
+ - Composition discovery is backend-aware. Every configured leaf and value must be
39
+ executable on the active backend.
40
+ - Composition execution is atomic at the GraphQL/REST payload level. A failed
41
+ composition contributes no generated leaf and reports only its parent key unused.
42
+ - Nested compositions are rejected while recursive expansion remains unsupported.
43
+ - Query-key ownership is validated against period, occupancy, active-backend
44
+ built-ins, overlapping custom definitions, and repeated configured filter keys.
45
+ - Rental highlight prioritization remains an explicit ordered list. Custom
46
+ attributes render only when their resolved key is listed; registry contents do
47
+ not reorder built-in highlights.
48
+
49
+ ## Removed
50
+
51
+ - `customAttributeDefinitionManifest`,
52
+ `CustomAttributeDefinitionManifest`,
53
+ `CustomAttributeDefinitionManifestEntry`, and related manifest helpers.
54
+ - `source: "customAttribute"` entries in `customAttributeFilterDefinitions`.
55
+ - Unsupported composition expression forms `any`, `gte`, and `lte`.
56
+ - `renderCustomAttributeHighlight`; use registry-backed rental/search output, or
57
+ `renderResolvedCustomAttribute` from `@v-office/sdk-core`.
58
+
59
+ ## Migration Impact
60
+
61
+ This is a configuration and public-type migration for consumers using custom
62
+ attributes. Consumers that do not configure custom attributes keep the same SDK
63
+ construction and service calls. Follow `versions/2.8.0/MIGRATION.md`.
@@ -0,0 +1,252 @@
1
+ # Migration: 2.7.0 to 2.8.0
2
+
3
+ 2.8.0 replaces `customAttributeDefinitionManifest` and
4
+ `source: "customAttribute"` filter definitions with one validated custom-attribute
5
+ registry. SDK construction and service method names are unchanged.
6
+
7
+ Consumers without custom attributes can upgrade without configuration changes.
8
+
9
+ ## 1. Replace the Definition Manifest
10
+
11
+ Before:
12
+
13
+ ```ts
14
+ const options = defineWebsiteSDKOptions({
15
+ customAttributeDefinitionManifest: {
16
+ byKey: {
17
+ region: {
18
+ id: "GQYKYgMVh28X7VLGursbkt",
19
+ key: "region",
20
+ type: "OPTION",
21
+ visibility: "PUBLIC",
22
+ },
23
+ },
24
+ byId: {
25
+ GQYKYgMVh28X7VLGursbkt: {
26
+ id: "GQYKYgMVh28X7VLGursbkt",
27
+ key: "region",
28
+ type: "OPTION",
29
+ visibility: "PUBLIC",
30
+ },
31
+ },
32
+ },
33
+ });
34
+ ```
35
+
36
+ After:
37
+
38
+ ```ts
39
+ import {
40
+ defineCustomAttributes,
41
+ defineWebsiteSDKOptions,
42
+ fetchCustomAttributeCatalog,
43
+ } from "@v-office/website-sdk";
44
+
45
+ const catalog = await fetchCustomAttributeCatalog({ config: v10Config });
46
+
47
+ const customAttributes = defineCustomAttributes({
48
+ catalog,
49
+ select: {
50
+ region: {
51
+ label: { "de-DE": "Region", "en-US": "Region" },
52
+ category: "OTHER",
53
+ filter: true,
54
+ optionLabels: {
55
+ north: { "de-DE": "Norden", "en-US": "North" },
56
+ south: { "de-DE": "Süden", "en-US": "South" },
57
+ },
58
+ },
59
+ },
60
+ });
61
+
62
+ const options = defineWebsiteSDKOptions({ customAttributes });
63
+ ```
64
+
65
+ `fetchCustomAttributeCatalog` is v10-only, requires a token authorized for the
66
+ public-definition operation, and returns no localized labels. Fetch it in an
67
+ authorized build environment or pin an equivalent literal catalog.
68
+ `defineCustomAttributes` validates the complete catalog/selection join and reports
69
+ all configuration errors together.
70
+
71
+ ## 2. Move Custom-Attribute Filter Policy
72
+
73
+ Remove every `source: "customAttribute"` entry from
74
+ `customAttributeFilterDefinitions`. Put its behavior in the matching `select`
75
+ entry:
76
+
77
+ ```ts
78
+ select: {
79
+ occupancyScore: {
80
+ label: { "de-DE": "Belegung", "en-US": "Occupancy" },
81
+ category: "ESSENTIALS",
82
+ filter: {
83
+ exposure: "public",
84
+ numericBounds: { min: 1, max: 12 },
85
+ },
86
+ },
87
+ }
88
+ ```
89
+
90
+ Use `filter: "internal"` or `filter: { exposure: "internal" }` for a queryable filter
91
+ that must not appear in `getFilters`. Omit `filter` for display only.
92
+
93
+ `customAttributeFilterDefinitions` remains the home of:
94
+
95
+ - `backendFilter`: v9 backend-native filters;
96
+ - `composition`: virtual Boolean filters composed from executable leaves.
97
+
98
+ ## 3. Configure Display and v9 Bindings
99
+
100
+ Display is independent of filter exposure and defaults to `true`. A selected
101
+ catalog attribute can add a v9 rental-data binding:
102
+
103
+ ```ts
104
+ select: {
105
+ privateSauna: {
106
+ label: { "de-DE": "Sauna", "en-US": "Sauna" },
107
+ display: true,
108
+ filter: true,
109
+ v9: "p_14418",
110
+ },
111
+ }
112
+ ```
113
+
114
+ Use `v9Only` for attributes that have no v10 catalog definition:
115
+
116
+ ```ts
117
+ v9Only: {
118
+ thatchedRoof: {
119
+ v9: "p_14420",
120
+ type: "boolean",
121
+ label: { "de-DE": "Reetdach", "en-US": "Thatched roof" },
122
+ },
123
+ }
124
+ ```
125
+
126
+ v9 renders bound values but does not advertise or execute catalog custom-attribute
127
+ filters. v10 filtering requires an enabled filter and a catalog ID.
128
+
129
+ ## 4. Update Composition Expressions
130
+
131
+ Expressions now support equality leaves joined by `all`:
132
+
133
+ ```ts
134
+ expression: {
135
+ all: [
136
+ { filter: "privateSauna", value: true },
137
+ { filter: "maxPersons", value: 4 },
138
+ ],
139
+ }
140
+ ```
141
+
142
+ Remove `operator`, `gte`, `lte`, and `any`; they never had correct runtime
143
+ semantics. Nested composition references are rejected.
144
+
145
+ A composition is advertised only if every leaf can execute on the active backend.
146
+ Execution is atomic: if one configured leaf is unknown, unsupported, malformed, or
147
+ conflicts with a direct value, no generated composition leaf enters the backend
148
+ payload and only the composition key is unused.
149
+
150
+ Successful compositions return the parent and expanded leaves in `appliedFilters`.
151
+
152
+ ## 5. Rename Colliding Query Keys
153
+
154
+ Every query key must have one owner. Configuration rejects:
155
+
156
+ - period/occupancy keys such as `start`, `adults`, and `pets`;
157
+ - filterable custom attributes or compositions that reuse v10 built-in filter keys;
158
+ - configured v9 filters that reuse v9 stable filter keys;
159
+ - a custom attribute and custom filter definition with the same key.
160
+ - repeated keys within `customAttributeFilterDefinitions`.
161
+
162
+ Use the selection's `key` override when a workspace definition collides:
163
+
164
+ ```ts
165
+ select: {
166
+ sauna: {
167
+ key: "privateSauna",
168
+ label: { "de-DE": "Sauna", "en-US": "Sauna" },
169
+ filter: true,
170
+ },
171
+ }
172
+ ```
173
+
174
+ Update query URLs and `rentalHighlightPrioritization` to the resolved key.
175
+
176
+ ## 6. Treat Categories as Display Labels
177
+
178
+ Configuration keeps stable keys such as `OUTDOORS`. `getFilters` and rental
179
+ attribute groups return localized labels such as `Außenbereich` or `Outdoor Area`.
180
+ Do not compare output categories to stable keys. Customize wording with
181
+ locale-nested overrides:
182
+
183
+ ```ts
184
+ translationOverrides: {
185
+ "de-DE": {
186
+ "RentalAttributesCategory.OUTDOORS.label": "Draußen",
187
+ },
188
+ }
189
+ ```
190
+
191
+ ## 7. Update Highlight Configuration
192
+
193
+ Custom attributes appear in rental/search `highlights` only when their resolved key
194
+ is listed in `rentalHighlightPrioritization`:
195
+
196
+ ```ts
197
+ rentalHighlightPrioritization: ["bedrooms", customAttributes.keys.region, "bathrooms"];
198
+ ```
199
+
200
+ The list remains authoritative for order. Registry contents do not reorder
201
+ built-ins, duplicate keys render once, and a built-in metadata key shadows a
202
+ same-named display-only custom attribute.
203
+
204
+ ## 8. Update Applied-Filter Handling
205
+
206
+ Value-bearing applied filters now include canonical `value`:
207
+
208
+ ```ts
209
+ { key: "region", label: "Region: North", value: "north" }
210
+ ```
211
+
212
+ Use `key` plus `value` to remove an exact filter. Labels remain localized
213
+ presentation and are not identifiers. A scalar key may appear in both
214
+ `appliedFilters` and `unusedFilterKeys` when one value applied and another was
215
+ rejected.
216
+
217
+ ## 9. CLI and Untyped Options
218
+
219
+ CLI JSON supplies catalog and selection **inputs**, not a finished registry:
220
+
221
+ ```json
222
+ {
223
+ "customAttributes": {
224
+ "catalog": {
225
+ "privateSauna": {
226
+ "id": "GQYKYgMVh28X7VLGursbkt",
227
+ "type": "BOOLEAN"
228
+ }
229
+ },
230
+ "select": {
231
+ "privateSauna": {
232
+ "label": { "de-DE": "Sauna", "en-US": "Sauna" },
233
+ "filter": true
234
+ }
235
+ }
236
+ }
237
+ }
238
+ ```
239
+
240
+ The CLI uses `defineCustomAttributesFromUnknown` and applies the same runtime
241
+ validation as typed configuration.
242
+
243
+ ## Recommended Verification
244
+
245
+ 1. Run `getFilters` for v9 and v10 in both locales.
246
+ 2. Confirm internal filters are absent while public compositions using them remain
247
+ executable.
248
+ 3. Inspect v9 GraphQL and v10 REST variables for one successful and one failed
249
+ composition.
250
+ 4. Verify renamed custom attributes render in rentals, search highlights, URLs, and
251
+ applied-filter chips.
252
+ 5. Verify `rentalHighlightPrioritization` order with and without custom attributes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@v-office/website-sdk",
3
- "version": "2.5.1",
3
+ "version": "2.8.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.6.1",
44
+ "@v-office/sdk-core": "^1.8.0",
45
45
  "effect": "4.0.0-beta.85",
46
46
  "graphql": "16.14.2",
47
47
  "yaml": "^2.9.0"
@@ -72,6 +72,8 @@
72
72
  "lint:fix": "oxlint --fix .",
73
73
  "fmt": "oxfmt",
74
74
  "fmt:check": "oxfmt --check",
75
- "check": "pnpm run typecheck && pnpm run lint"
75
+ "check": "pnpm run typecheck && pnpm run lint",
76
+ "test": "pnpm run build && node --test test/*.test.mjs",
77
+ "playground:custom-attributes": "pnpm run build && node --env-file=.env playground/custom-attributes.ts"
76
78
  }
77
79
  }