@v-office/website-sdk 2.7.0 → 2.9.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 (45) hide show
  1. package/README.md +28 -1
  2. package/dist/cli.mjs +25 -4
  3. package/dist/{client-45_ofP_d.mjs → client-CYK_5Vk7.mjs} +385 -187
  4. package/dist/index.d.mts +24 -4
  5. package/dist/index.mjs +3 -3
  6. package/dist/instructions/CHANGELOG.md +4 -1
  7. package/dist/instructions/MIGRATION.md +4 -1
  8. package/dist/instructions/README.md +9 -3
  9. package/dist/instructions/creation.md +82 -66
  10. package/dist/instructions/custom-attributes.md +560 -0
  11. package/dist/instructions/filter.md +62 -23
  12. package/dist/instructions/rentals.md +43 -2
  13. package/dist/instructions/search.md +29 -3
  14. package/dist/instructions/versions/2.5.0/MIGRATION.md +5 -0
  15. package/dist/instructions/versions/2.6.0/CHANGELOG.md +3 -25
  16. package/dist/instructions/versions/2.6.0/MIGRATION.md +4 -72
  17. package/dist/instructions/versions/2.7.0/CHANGELOG.md +44 -0
  18. package/dist/instructions/versions/2.7.0/MIGRATION.md +79 -0
  19. package/dist/instructions/versions/2.8.0/CHANGELOG.md +63 -0
  20. package/dist/instructions/versions/2.8.0/MIGRATION.md +252 -0
  21. package/dist/instructions/versions/2.9.0/CHANGELOG.md +37 -0
  22. package/dist/instructions/versions/2.9.0/MIGRATION.md +153 -0
  23. package/dist/{rentals-Lw1qUKIj.mjs → rentals-CFod9H4m.mjs} +21 -21
  24. package/dist/{search-wcoZw2rt.mjs → search-CO9ID9op.mjs} +16 -133
  25. package/dist/{to-rental-highlights-CxWlq76f.mjs → to-rental-highlights-B6a_fi0j.mjs} +33 -8
  26. package/dist/translations/v10/de-DE/core.json +2 -0
  27. package/dist/translations/v10/en-US/core.json +2 -0
  28. package/instructions/CHANGELOG.md +4 -1
  29. package/instructions/MIGRATION.md +4 -1
  30. package/instructions/README.md +9 -3
  31. package/instructions/creation.md +82 -66
  32. package/instructions/custom-attributes.md +560 -0
  33. package/instructions/filter.md +62 -23
  34. package/instructions/rentals.md +43 -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 +3 -25
  38. package/instructions/versions/2.6.0/MIGRATION.md +4 -72
  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/instructions/versions/2.9.0/CHANGELOG.md +37 -0
  44. package/instructions/versions/2.9.0/MIGRATION.md +153 -0
  45. package/package.json +5 -3
@@ -36,14 +36,14 @@ Sample:
36
36
  [
37
37
  {
38
38
  "searchParameterQueryKey": "wifi",
39
- "label": "WiFi",
40
- "category": "ESSENTIALS",
39
+ "label": "WLAN",
40
+ "category": "Grundlagen",
41
41
  "type": "BooleanFilter"
42
42
  },
43
43
  {
44
44
  "searchParameterQueryKey": "bedrooms",
45
- "label": "Bedrooms",
46
- "category": "ROOMS",
45
+ "label": "Schlafzimmer",
46
+ "category": "Wohn- und Schlafbereiche",
47
47
  "type": "IntFilter",
48
48
  "numericBounds": {
49
49
  "min": 1,
@@ -53,22 +53,30 @@ Sample:
53
53
  {
54
54
  "searchParameterQueryKey": "region",
55
55
  "label": "Region",
56
- "category": "LOCATION",
56
+ "category": "Andere",
57
57
  "type": "OptionFilter",
58
58
  "options": [
59
59
  {
60
60
  "value": "north",
61
- "label": "North"
61
+ "label": "Norden"
62
62
  }
63
63
  ]
64
64
  }
65
65
  ]
66
66
  ```
67
67
 
68
+ `searchParameterQueryKey` and each option `value` are **stable identifiers**: they are
69
+ what you put in a URL, and they never change with locale. `label` and `category` are
70
+ **localized display strings** for the requested locale, not keys — do not group or
71
+ match on them programmatically. This holds for custom attributes too: an attribute
72
+ authored with `category: "ESSENTIALS"` is advertised with `"category": "Grundlagen"`
73
+ in `de-DE`, exactly like a built-in filter.
74
+
68
75
  Filter variants:
69
76
 
70
77
  - `BooleanFilter`: on/off query parameter.
71
78
  - `IntFilter`: numeric query parameter, optionally with `numericBounds`.
79
+ - `StringFilter`: non-empty exact-match query parameter.
72
80
  - `OptionFilter`: query parameter with localized selectable `options`.
73
81
 
74
82
  ## Configuration
@@ -85,6 +93,14 @@ Filter variants:
85
93
  }
86
94
  ```
87
95
 
96
+ v9 has a fixed built-in filter set. These filters are always advertised, parsed,
97
+ and usable as composition leaves; do not repeat them as `backendFilter` definitions.
98
+
99
+ - Numeric: `bedrooms`, `bathrooms`.
100
+ - Boolean: `pool`, `wifi`, `pets`, `privateparking`, `ac`, `washer`, `dishwasher`,
101
+ `beachfront`, `seaview`, `balcony`, `terrace`, `garden`, `bbq`, `sauna`,
102
+ `fireplace`, `tv`, `childrenWelcome`, `nonsmoking`, `kitchen`.
103
+
88
104
  `v10` config:
89
105
 
90
106
  ```json
@@ -97,29 +113,29 @@ Filter variants:
97
113
  }
98
114
  ```
99
115
 
100
- Optional `WebsiteSDKOptions` can add public custom filters:
116
+ Optional `WebsiteSDKOptions` add two further sources of filters.
117
+
118
+ Custom attributes come from `customAttributes`, and a definition is advertised only
119
+ when it has a public filter and the selected backend can execute it. v9 has no
120
+ custom-attribute search path, so v9 never advertises one; see `custom-attributes.md`.
121
+
122
+ Backend filters and compositions come from `customAttributeFilterDefinitions`.
123
+ SDK configuration cannot create a Hub filter: for another v9 key, first ask someone
124
+ at be-on! with Hub access to add or confirm it, then configure that key as a
125
+ `backendFilter`.
101
126
 
102
127
  ```json
103
128
  {
104
129
  "customAttributeFilterDefinitions": [
105
130
  {
106
- "key": "region",
107
- "source": "customAttribute",
108
- "category": "ESSENTIALS",
131
+ "key": "atLeastTwoBedrooms",
132
+ "source": "backendFilter",
133
+ "category": "LIVING_SLEEPING",
109
134
  "label": {
110
- "de-DE": "Region",
111
- "en-US": "Region"
135
+ "de-DE": "Mind. zwei Schlafzimmer",
136
+ "en-US": "At least two bedrooms"
112
137
  },
113
- "type": "option",
114
- "options": [
115
- {
116
- "value": "north",
117
- "label": {
118
- "de-DE": "Norden",
119
- "en-US": "North"
120
- }
121
- }
122
- ],
138
+ "type": "boolean",
123
139
  "searchable": true,
124
140
  "internal": false
125
141
  }
@@ -128,7 +144,30 @@ Optional `WebsiteSDKOptions` can add public custom filters:
128
144
  }
129
145
  ```
130
146
 
131
- Only custom definitions with `searchable: true` and `internal: false` are exposed by `getFilters`.
147
+ Only definitions with `searchable: true` and `internal: false` are exposed by
148
+ `getFilters`. `backendFilter` entries are advertised by v9 only, because they have no
149
+ v10 execution path. Each query key has one owner: period and occupancy collisions
150
+ fail during option normalization, v9/v10 built-in filter collisions fail in the
151
+ corresponding backend configuration path, and a custom attribute cannot share a key
152
+ with a configured custom filter. Repeated keys within
153
+ `customAttributeFilterDefinitions` also fail during option normalization.
154
+ `getFilters` keeps a final uniqueness assertion so parse order never silently
155
+ decides ownership.
156
+
157
+ Compositions are additionally backend-aware: `getFilters` advertises one only when
158
+ every leaf exists on the active backend and its configured value is valid for that
159
+ leaf. Executable internal leaves may participate without being exposed separately.
160
+ Unknown, unsupported, or backend-specific leaves omit the composition. Nested
161
+ compositions are rejected during option normalization while recursive expansion is
162
+ unsupported.
163
+
164
+ During search, a successful composition and its expanded leaves are all returned in
165
+ the search output's `appliedFilters`; `getFilters` itself returns only discovery
166
+ metadata. See `search.md` for filter-chip guidance.
167
+
168
+ Configured category values remain stable keys such as `OUTDOORS`. The output
169
+ translates them through `RentalAttributesCategory.<KEY>.label`, honors
170
+ `translationOverrides`, and returns only the localized display label.
132
171
 
133
172
  For v10, `getFilters` also exposes the mapped BooleanFilter `pets`, labeled `Dogs welcome` / `Hunde willkommen`. It maps to one pet in search occupancy; use `petsCount` when the UI needs an exact pet count instead.
134
173
 
@@ -147,14 +147,55 @@ 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` selects which facts become rental `highlights` and
171
+ sets their order. It is an ordered allowlist, not a sort over every available fact.
172
+ A key that is not listed is not emitted even when the source contains a value.
173
+ `rentalPropertyHighlightPrioritization` has the same semantics for v10 property
174
+ highlights. Both options affect `highlights` only, not `attributes` or `vicinity`.
175
+
176
+ For either option, `undefined` uses the SDK default and `[]` emits no highlights.
177
+ Duplicate keys are emitted once; unknown, unsupported, or unresolved keys are
178
+ ignored. When several configured rental view facts have values, only the first one
179
+ in the ordered allowlist is emitted. View-type descriptors qualify a view and are
180
+ not part of this strongest-view selection. Translation overrides affect localized
181
+ labels.
182
+
183
+ The active defaults are exported as
184
+ `DEFAULT_RENTAL_HIGHLIGHT_PRIORITIZATION` and
185
+ `DEFAULT_RENTAL_PROPERTY_HIGHLIGHT_PRIORITIZATION` from
186
+ `@v-office/sdk-core`. See `versions/2.9.0/CHANGELOG.md` for the release notes and
187
+ `versions/2.9.0/MIGRATION.md` for the complete default lists and upgrade checks.
188
+
189
+ In CLI JSON, `customAttributes` contains catalog and selection inputs; the CLI builds
190
+ the validated registry. Typed applications normally call `defineCustomAttributes`
191
+ and pass its result instead.
192
+
193
+ Custom attributes configured through `customAttributes` add values to rental output on
194
+ both backends. A value appears in `highlights` only when its key is listed in
195
+ `rentalHighlightPrioritization`, and in `attributes` under the group named by its
196
+ authored `category` — alongside built-in attributes of that category, not in a separate
197
+ bucket. Category and attribute `label`s in the output are localized strings, never
198
+ stable keys. See `custom-attributes.md`.
158
199
 
159
200
  ## CLI Usage
160
201
 
@@ -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.
@@ -1,28 +1,6 @@
1
1
  # Changelog: 2.6.0
2
2
 
3
- Release date: 2026-07-27
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.
4
5
 
5
- This release makes v9 `stripe_checkout` payment options submittable. The vOffice `initStripePayment` action returns only session metadata, so `submitPaymentOption` now opens the Checkout Session with Stripe.js when the backend omits the session URL. Config, service calls, and output types are unchanged.
6
-
7
- ## Added
8
-
9
- - `submitPaymentOption` and `submitPaymentOptionEffect` now complete `stripe_checkout` options that carry only `sessionId` and `accountId`. Previously these options failed with "Stripe Checkout requires a checkout session URL".
10
- - Stripe.js is loaded from `https://js.stripe.com/v3/` on first use and reused for later submissions. A failed load is not kept, so the next submission retries it. An existing `window.Stripe` instance is used when the page already provides one, so no second script tag is added.
11
- - The vOffice Stripe platform publishable keys are embedded in the SDK. Stripe Checkout requires no consumer configuration.
12
-
13
- ## Changed
14
-
15
- - `stripe_checkout` submission prefers the Checkout Session `url` and only falls back to Stripe.js when it is absent. Once vOffice returns the URL, the SDK uses it without a further release.
16
- - The publishable key is selected from the session id, so tenants in Stripe test mode (`cs_test_`) and live mode (`cs_live_`) both work without configuration or environment detection.
17
- - Stripe sessions are created on connected accounts, so the option's `accountId` is passed to Stripe.js as `stripeAccount`.
18
- - The failure raised when a `stripe_checkout` option carries neither a URL nor a session id now names both.
19
- - Browser access helpers used by payment submission moved into an internal module shared by redirect, form-post, and Stripe submission. This is internal only and does not change the public API.
20
-
21
- ## Migration Impact
22
-
23
- - Consumers that hid Stripe payment options because `url` was missing can render them again. Gate the button on the option being present rather than on `option.url`. See `versions/2.6.0/MIGRATION.md`.
24
- - Sites with a Content-Security-Policy must allow `script-src https://js.stripe.com` and `frame-src https://js.stripe.com https://hooks.stripe.com`.
25
- - Payment submission remains browser-only and still fails outside a browser environment.
26
- - Stripe.js is fetched at submission time, so payment submission can now fail from a blocked or unavailable third-party script. Treat that as a payment failure, never as a booking failure: the reservation already exists when payment options are shown.
27
- - No config, option, or output type changes. v10 Adyen `redirect` flows and all `bank_transfer` and `form_post` flows are unaffected.
28
- - Stripe removed `redirectToCheckout` from its versioned Stripe.js release trains (`clover`, 2025-09-30, and later) and from the published `stripe-js` types. The method is still implemented in the unversioned `https://js.stripe.com/v3/` bundle that the SDK loads, which is why this fallback works. It is a bridge until vOffice returns the session URL and is expected to be removed afterwards. Should a future Stripe.js build drop the method entirely, submission fails with a message naming the missing session URL.
6
+ Use `../2.7.0/CHANGELOG.md` as the authoritative release record.
@@ -1,74 +1,6 @@
1
- # Migration: 2.5.x to 2.6.0
1
+ # Migration: 2.6.0
2
2
 
3
- This guide covers upgrading `@v-office/website-sdk` from 2.5.0 or 2.5.1 to 2.6.0.
3
+ `@v-office/website-sdk` 2.6.0 was never published. The planned Stripe Checkout
4
+ change shipped in 2.7.0.
4
5
 
5
- 2.6.0 changes no config, no service call, and no output type. The only change is that `stripe_checkout` payment options can now be submitted on the v9 backend. If your site does not offer Stripe, upgrading requires no work at all.
6
-
7
- ## What Changed
8
-
9
- vOffice's `initStripePayment` action returns only `sessionId` and `accountId`, never the Checkout Session URL. Because `submitPaymentOption` redirected exclusively to a session URL, Stripe payment options could never be completed and failed with "Stripe Checkout requires a checkout session URL".
10
-
11
- 2.6.0 keeps the URL redirect as the preferred path and adds a fallback: when a `stripe_checkout` option has a `sessionId` but no `url`, the SDK loads Stripe.js and opens the Checkout Session with it. This is the same mechanism the classic non-SDK vOffice websites use.
12
-
13
- The fallback is self-retiring. When vOffice starts returning the session URL, the option gains a `url`, the URL redirect wins, and Stripe.js is never loaded. No SDK release is needed for that transition.
14
-
15
- ## Remove Stripe Workarounds
16
-
17
- Sites that hid the Stripe button because no URL was present should now render it. Gate on the option existing rather than on `option.url`:
18
-
19
- ```ts
20
- // Before: Stripe options were unusable, so they had to be hidden
21
- const payable = option.kind !== "stripe_checkout" || option.url !== undefined;
22
-
23
- // After: every submittable option can be submitted
24
- const payable = true;
25
- ```
26
-
27
- Sites that implemented their own Stripe.js bridge with a publishable key can delete it, along with the key configuration. The SDK carries the vOffice platform keys and selects between test and live based on the session id, so a tenant in Stripe test mode and a tenant in live mode both work from the same build.
28
-
29
- ## Content-Security-Policy
30
-
31
- Stripe.js is fetched from Stripe at submission time. If your site sets a CSP, allow:
32
-
33
- ```
34
- script-src https://js.stripe.com
35
- frame-src https://js.stripe.com https://hooks.stripe.com
36
- ```
37
-
38
- Without these directives the script is blocked and Stripe submission fails. Other payment kinds are unaffected.
39
-
40
- ## Error Handling
41
-
42
- Payment submission can now fail for new reasons: Stripe.js could not be loaded, the loaded Stripe.js build does not provide the Checkout redirect, or Stripe rejected the redirect. All surface as a `CoreSDKError` with `operation: "paymentSubmission"`, the same as existing submission failures.
43
-
44
- Offering a retry is worthwhile for these failures. A failed Stripe.js load is not remembered, so the next submission fetches the script again and can succeed without a page reload.
45
-
46
- The booking already exists by the time payment options are rendered, so a submission failure must never be presented as a failed booking:
47
-
48
- ```ts
49
- try {
50
- await sdk.live.booking.submitPaymentOption(option);
51
- } catch (error) {
52
- // The reservation is created. Show the booking number and offer bank transfer.
53
- showPaymentFailure({ bookingNumber: booking.bookingNumber, error });
54
- }
55
- ```
56
-
57
- Submission is still browser-only and fails outside a browser environment, unchanged from earlier versions.
58
-
59
- ## Payment Return
60
-
61
- Unchanged from earlier versions, but worth confirming while testing Stripe end to end. The SDK derives the Stripe success and cancel URLs from the `relativeRedirectUrl` passed to `sdk.live.booking.book(...)` and appends `payment=stripe&success=true` or `payment=stripe&cancel=true`. That path must exist in your site and should read those query parameters.
62
-
63
- Note that `relativeRedirectUrl` is supplied before the reservation exists, so the return URL cannot contain the booking number or guest token. Persist anything the return page needs, for example in `sessionStorage`, before submitting the payment option.
64
-
65
- A `success=true` return means Stripe sent the browser back, not that payment has settled. Payment confirmation reaches vOffice through Stripe's webhook.
66
-
67
- ## Recommended Steps
68
-
69
- 1. Upgrade to `@v-office/website-sdk` 2.6.0.
70
- 2. Remove any conditional that hides Stripe payment options when `option.url` is missing.
71
- 3. Remove a site-level Stripe.js bridge and its publishable key configuration if you added one.
72
- 4. Add the Stripe CSP directives if your site sets a Content-Security-Policy.
73
- 5. Confirm payment submission errors are presented as payment failures with the booking number, not as booking failures.
74
- 6. Smoke-test one booking against a Stripe test tenant and one against a live tenant, checking that Checkout opens and that the configured return path handles both `success=true` and `cancel=true`.
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`.