@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.
- package/README.md +28 -1
- package/dist/cli.mjs +25 -4
- package/dist/{client-C5ojrNQA.mjs → client-BNbBfJtO.mjs} +468 -189
- package/dist/index.d.mts +5 -4
- package/dist/index.mjs +3 -3
- package/dist/instructions/CHANGELOG.md +3 -0
- package/dist/instructions/MIGRATION.md +3 -0
- package/dist/instructions/README.md +8 -2
- package/dist/instructions/booking.md +39 -3
- package/dist/instructions/creation.md +65 -64
- package/dist/instructions/custom-attributes.md +556 -0
- package/dist/instructions/filter.md +51 -23
- package/dist/instructions/rentals.md +26 -2
- package/dist/instructions/search.md +29 -3
- package/dist/instructions/versions/2.5.0/MIGRATION.md +5 -0
- package/dist/instructions/versions/2.6.0/CHANGELOG.md +6 -0
- package/dist/instructions/versions/2.6.0/MIGRATION.md +6 -0
- package/dist/instructions/versions/2.7.0/CHANGELOG.md +44 -0
- package/dist/instructions/versions/2.7.0/MIGRATION.md +79 -0
- package/dist/instructions/versions/2.8.0/CHANGELOG.md +63 -0
- package/dist/instructions/versions/2.8.0/MIGRATION.md +252 -0
- package/dist/{rentals-Lw1qUKIj.mjs → rentals-cCejb_2d.mjs} +21 -21
- package/dist/{search-9yzAqHCg.mjs → search-Dzzra6IW.mjs} +16 -133
- package/dist/{to-rental-highlights-CxWlq76f.mjs → to-rental-highlights-OvNe9ZQS.mjs} +8 -6
- package/dist/translations/v10/de-DE/core.json +2 -0
- package/dist/translations/v10/en-US/core.json +2 -0
- package/instructions/CHANGELOG.md +3 -0
- package/instructions/MIGRATION.md +3 -0
- package/instructions/README.md +8 -2
- package/instructions/booking.md +39 -3
- package/instructions/creation.md +65 -64
- package/instructions/custom-attributes.md +556 -0
- package/instructions/filter.md +51 -23
- package/instructions/rentals.md +26 -2
- package/instructions/search.md +29 -3
- package/instructions/versions/2.5.0/MIGRATION.md +5 -0
- package/instructions/versions/2.6.0/CHANGELOG.md +6 -0
- package/instructions/versions/2.6.0/MIGRATION.md +6 -0
- package/instructions/versions/2.7.0/CHANGELOG.md +44 -0
- package/instructions/versions/2.7.0/MIGRATION.md +79 -0
- package/instructions/versions/2.8.0/CHANGELOG.md +63 -0
- package/instructions/versions/2.8.0/MIGRATION.md +252 -0
- package/package.json +5 -3
|
@@ -147,14 +147,38 @@ Optional `WebsiteSDKOptions`:
|
|
|
147
147
|
|
|
148
148
|
```json
|
|
149
149
|
{
|
|
150
|
-
"
|
|
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.
|
|
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": "
|
|
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
|
|
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 `
|
|
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,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.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as VofficeUnitDataFieldSchemas, d as VofficeUnitDataPropertyMetadata, f as parseVofficeFacilityData, i as toLocalizedString, l as VofficeUnitDataPropertyCategoryLabelKeys, m as parseVofficeUnitData, n as toImages, o as rentalsAllFeedbacksQuery, p as parseVofficeFeedbackData, r as toAddress, s as rentalsAllWithoutFeedbacksQuery, t as toRentalHighlights, u as VofficeUnitDataPropertyCategoryValues } from "./to-rental-highlights-
|
|
2
|
-
import { makeTranslate,
|
|
1
|
+
import { c as VofficeUnitDataFieldSchemas, d as VofficeUnitDataPropertyMetadata, f as parseVofficeFacilityData, i as toLocalizedString, l as VofficeUnitDataPropertyCategoryLabelKeys, m as parseVofficeUnitData, n as toImages, o as rentalsAllFeedbacksQuery, p as parseVofficeFeedbackData, r as toAddress, s as rentalsAllWithoutFeedbacksQuery, t as toRentalHighlights, u as VofficeUnitDataPropertyCategoryValues } from "./to-rental-highlights-OvNe9ZQS.mjs";
|
|
2
|
+
import { makeTranslate, renderLabeledAttributeValue, renderResolvedCustomAttribute, toCustomAttributeList, toResolvedCustomAttributeCategoryTranslationKey } from "@v-office/sdk-core";
|
|
3
3
|
import { Effect } from "effect";
|
|
4
4
|
//#region src/legacy-v9/parser/rentals/to-description.ts
|
|
5
5
|
const toDescription = (data, locale) => {
|
|
@@ -60,29 +60,30 @@ const PROPERTY_METADATA_ENTRIES = Object.entries(VofficeUnitDataPropertyMetadata
|
|
|
60
60
|
return (CATEGORY_ORDER.get(left.metadata.category.key) ?? Number.MAX_SAFE_INTEGER) - (CATEGORY_ORDER.get(right.metadata.category.key) ?? Number.MAX_SAFE_INTEGER) || left.index - right.index;
|
|
61
61
|
});
|
|
62
62
|
const canRenderLabeledAttributeValue$1 = (value) => value !== false && value !== 0 && value !== "false" && value !== "0" && value != null && value !== "";
|
|
63
|
-
const toRentalAttributes = ({ locale, translations, attributes,
|
|
63
|
+
const toRentalAttributes = ({ locale, translations, attributes, customAttributes }) => Effect.gen(function* () {
|
|
64
64
|
const result = [];
|
|
65
65
|
const categoriesByKey = /* @__PURE__ */ new Map();
|
|
66
66
|
const subCategoriesByKey = /* @__PURE__ */ new Map();
|
|
67
67
|
const knownAttributes = attributes.known;
|
|
68
68
|
const translate = makeTranslate(translations, locale);
|
|
69
|
-
const
|
|
70
|
-
|
|
69
|
+
const getCustomAttributeSubCategory = (categoryKey) => Effect.gen(function* () {
|
|
70
|
+
const labelKey = toResolvedCustomAttributeCategoryTranslationKey(categoryKey);
|
|
71
|
+
let category = categoriesByKey.get(categoryKey);
|
|
71
72
|
if (category == null) {
|
|
72
73
|
category = {
|
|
73
|
-
label: yield* translate(
|
|
74
|
+
label: yield* translate(labelKey, categoryKey),
|
|
74
75
|
subCategories: []
|
|
75
76
|
};
|
|
76
|
-
categoriesByKey.set(
|
|
77
|
+
categoriesByKey.set(categoryKey, category);
|
|
77
78
|
result.push(category);
|
|
78
79
|
}
|
|
79
|
-
let subCategory = subCategoriesByKey.get(
|
|
80
|
+
let subCategory = subCategoriesByKey.get(categoryKey);
|
|
80
81
|
if (subCategory == null) {
|
|
81
82
|
subCategory = {
|
|
82
83
|
label: category.label,
|
|
83
84
|
items: []
|
|
84
85
|
};
|
|
85
|
-
subCategoriesByKey.set(
|
|
86
|
+
subCategoriesByKey.set(categoryKey, subCategory);
|
|
86
87
|
category.subCategories.push(subCategory);
|
|
87
88
|
}
|
|
88
89
|
return subCategory;
|
|
@@ -118,18 +119,17 @@ const toRentalAttributes = ({ locale, translations, attributes, customAttributeF
|
|
|
118
119
|
}
|
|
119
120
|
subCategory.items.push(attribute);
|
|
120
121
|
}
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
key: definition.key,
|
|
122
|
+
for (const attribute of toCustomAttributeList(customAttributes)) {
|
|
123
|
+
const binding = attribute.v9;
|
|
124
|
+
if (binding === void 0) continue;
|
|
125
|
+
const rendered = renderResolvedCustomAttribute({
|
|
126
|
+
attribute,
|
|
127
127
|
locale,
|
|
128
|
-
value
|
|
128
|
+
value: knownAttributes[binding] ?? attributes.unknown[binding]
|
|
129
129
|
});
|
|
130
|
-
if (
|
|
130
|
+
if (rendered == null) continue;
|
|
131
|
+
(yield* getCustomAttributeSubCategory(attribute.category)).items.push(rendered);
|
|
131
132
|
}
|
|
132
|
-
if (customAttributeItems.length > 0) (yield* getGeneralSubCategory()).items.push(...customAttributeItems);
|
|
133
133
|
return result;
|
|
134
134
|
});
|
|
135
135
|
//#endregion
|
|
@@ -228,7 +228,7 @@ const toReviews = ({ locale, translations, rental }) => Effect.gen(function* ()
|
|
|
228
228
|
});
|
|
229
229
|
//#endregion
|
|
230
230
|
//#region src/legacy-v9/parser/rentals/to-rental-list-item.ts
|
|
231
|
-
const toRentalRentalsOutput = ({ rental, locale, translations, imageProxyBaseUrl, rentalHighlightPrioritization,
|
|
231
|
+
const toRentalRentalsOutput = ({ rental, locale, translations, imageProxyBaseUrl, rentalHighlightPrioritization, customAttributes }) => Effect.gen(function* () {
|
|
232
232
|
const data = parseVofficeUnitData(rental.data);
|
|
233
233
|
const rawRentalType = data.known.type?.trim();
|
|
234
234
|
const translatedRentalType = rawRentalType != null && rawRentalType.length > 0 ? yield* toRentalType({
|
|
@@ -244,7 +244,7 @@ const toRentalRentalsOutput = ({ rental, locale, translations, imageProxyBaseUrl
|
|
|
244
244
|
locale,
|
|
245
245
|
translations,
|
|
246
246
|
attributes: data,
|
|
247
|
-
|
|
247
|
+
customAttributes
|
|
248
248
|
});
|
|
249
249
|
const vicinity = yield* toRentalVicinity({
|
|
250
250
|
locale,
|
|
@@ -255,7 +255,7 @@ const toRentalRentalsOutput = ({ rental, locale, translations, imageProxyBaseUrl
|
|
|
255
255
|
locale,
|
|
256
256
|
translations,
|
|
257
257
|
highlightPrioritization: rentalHighlightPrioritization,
|
|
258
|
-
|
|
258
|
+
customAttributes,
|
|
259
259
|
attributes: data
|
|
260
260
|
});
|
|
261
261
|
const reviews = yield* toReviews({
|