@v-office/website-sdk 2.12.0 → 2.13.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.
@@ -77,6 +77,28 @@ Common stable query keys:
77
77
  - Occupancy: `adults`, `children`, `childrenAges`, `babies`, `pets`, `petsCount`.
78
78
  - Filters: use `searchParameterQueryKey` values from `sdk.static.filter.getFilters(...)`.
79
79
 
80
+ ### Static Backend Capabilities
81
+
82
+ Search capabilities that only depend on a backend name are available without
83
+ constructing an SDK:
84
+
85
+ ```ts
86
+ import {
87
+ getSupportedPeriodQueryKeys,
88
+ supportsFlexiblePeriodSearch,
89
+ } from "@v-office/website-sdk/capabilities/search";
90
+
91
+ supportsFlexiblePeriodSearch("v9"); // false
92
+ supportsFlexiblePeriodSearch("v10"); // true
93
+
94
+ getSupportedPeriodQueryKeys("v9").has("month"); // false
95
+ getSupportedPeriodQueryKeys("v10").has("month"); // true
96
+ ```
97
+
98
+ The returned read-only set contains the stable period query keys accepted by the
99
+ selected backend, including aliases such as `from` and `till`. Key support does
100
+ not replace validation of complete query combinations.
101
+
80
102
  ## Query Structure
81
103
 
82
104
  The `query` field is a URL query-string style value without a leading `?`.
@@ -0,0 +1,87 @@
1
+ # Changelog: 2.13.0
2
+
3
+ This release adds static backend search capability discovery and replaces the
4
+ ambiguous flat booking payment schedule with a shared, presentation-ready payment
5
+ model for v9 and v10. It preserves every known remaining payment step, separates
6
+ contractual steps from full-payment alternatives, and keeps backend credentials
7
+ out of the public booking output.
8
+
9
+ ## Added
10
+
11
+ - `@v-office/website-sdk/capabilities/search` exposes pure, instance-independent
12
+ helpers for checking flexible-period support and the supported period query keys
13
+ for a backend.
14
+ - `BookingOutput.payment.schedule` contains the remaining contractual payment
15
+ steps known after booking.
16
+ - `BookingOutput.payment.alternatives` contains optional ways to settle the
17
+ complete outstanding balance.
18
+ - Schedule entries have a stable `kind`: `prepayment`, `remaining_payment`,
19
+ `installment`, or `deposit`.
20
+ - Full-payment alternatives use `kind: "full_amount"`.
21
+ - v10 booking output includes all remaining online, on-site, and external payment
22
+ steps instead of exposing only the next online step.
23
+ - v10 schedule entries can include translated `paymentAt` text derived from the
24
+ backend payment location and recipient.
25
+ - Legacy v9 now preserves its independently supplied remaining-payment amount and
26
+ deadline.
27
+
28
+ ## Changed
29
+
30
+ - `dueOn` is now a complete translated, long-form display string such as
31
+ `Zahlbar bis zum 6. Februar 2027`.
32
+ - Schedule and alternative amounts use the `amount` field and remain
33
+ locale-formatted display strings.
34
+ - `paymentOptions` is present on a schedule entry only when the SDK can currently
35
+ perform that payment. Informational future, on-site, and external steps remain
36
+ visible without payment options.
37
+ - A synthesized v9 full-payment alternative no longer copies the prepayment
38
+ deadline. An explicit backend total deadline can still be retained.
39
+ - v10 initializes Adyen only for the next payable online step and the
40
+ full-outstanding alternative.
41
+ - v9 initializes Stripe only for currently payable choices.
42
+ - Post-booking insurance now receives the opaque booking result:
43
+
44
+ ```ts
45
+ await sdk.live.quote.bookInsurance({ quote, booking });
46
+ ```
47
+
48
+ ## Removed
49
+
50
+ - `BookingOutput.paymentSchedules`
51
+ - Public `BookingOutput.guestToken`
52
+ - ISO-like or locale-short date assumptions for booking payment output
53
+
54
+ The private v9 guest token remains attached to the live opaque booking object and
55
+ is used internally when completing insurance. It is not enumerable or
56
+ serializable.
57
+
58
+ ## Backend Mapping
59
+
60
+ - v9 `prepayment` becomes `kind: "prepayment"`.
61
+ - v9 `rest` becomes `kind: "remaining_payment"`.
62
+ - v9 `total` becomes a `full_amount` alternative.
63
+ - v10 `INSTALLMENT` becomes `kind: "installment"`.
64
+ - v10 `DEPOSIT` becomes `kind: "deposit"`.
65
+ - v10 `financials.outstanding` becomes a `full_amount` alternative when it is a
66
+ distinct payable choice.
67
+
68
+ ## Migration Impact
69
+
70
+ This is a breaking output and insurance-input change. Consumers must:
71
+
72
+ 1. Replace reads of `paymentSchedules` with `payment.schedule` and
73
+ `payment.alternatives`.
74
+ 2. Read `amount` instead of the former schedule `total`.
75
+ 3. Treat schedule `paymentOptions` as optional.
76
+ 4. Render `dueOn`, `paymentAt`, labels, amounts, and line amounts directly without
77
+ reparsing or reformatting them.
78
+ 5. Pass the live `booking` object to `bookInsurance` instead of passing
79
+ `bookingNumber` and `guestToken`.
80
+ 6. Keep the booking object in memory until optional v9 insurance booking is
81
+ complete; private credentials do not survive JSON serialization.
82
+
83
+ The search capability API is additive. Consumers with hardcoded backend period-key
84
+ tables can replace them with the new helpers.
85
+
86
+ See `versions/2.13.0/MIGRATION.md`, `../../search.md`, `../../booking.md`, and
87
+ `../../quote.md`.
@@ -0,0 +1,315 @@
1
+ # Migration: 2.12.0 to 2.13.0
2
+
3
+ 2.13.0 introduces a breaking, shared booking-payment output for v9 and v10. The
4
+ new model is intentionally presentation-oriented: labels, amounts, deadlines,
5
+ payment locations, and breakdown lines are already translated and formatted for
6
+ the booking locale.
7
+
8
+ ## 1. Replace the Flat Payment Schedule
9
+
10
+ Before 2.13.0:
11
+
12
+ ```ts
13
+ booking.paymentSchedules;
14
+ ```
15
+
16
+ From 2.13.0:
17
+
18
+ ```ts
19
+ booking.payment.schedule;
20
+ booking.payment.alternatives;
21
+ ```
22
+
23
+ `payment.schedule` contains contractual payment steps. `payment.alternatives`
24
+ contains distinct alternatives such as paying the complete outstanding balance.
25
+
26
+ Example:
27
+
28
+ ```json
29
+ {
30
+ "bookingNumber": "B-2026-0001",
31
+ "payment": {
32
+ "schedule": [
33
+ {
34
+ "kind": "prepayment",
35
+ "label": "Anzahlung",
36
+ "amount": "76,00 €",
37
+ "dueOn": "Zahlbar bis zum 19. August 2026",
38
+ "paymentOptions": [
39
+ {
40
+ "kind": "bank_transfer",
41
+ "label": "Überweisung",
42
+ "holder": "Ferienvermietung Muster GmbH",
43
+ "iban": "DE02 1203 0000 0000 2020 51",
44
+ "remittanceText": "Buchungsnummer: B-2026-0001"
45
+ }
46
+ ]
47
+ },
48
+ {
49
+ "kind": "remaining_payment",
50
+ "label": "Restzahlung",
51
+ "amount": "304,00 €",
52
+ "dueOn": "Zahlbar bis zum 6. Februar 2027"
53
+ }
54
+ ],
55
+ "alternatives": [
56
+ {
57
+ "kind": "full_amount",
58
+ "label": "Gesamtzahlung",
59
+ "amount": "380,00 €",
60
+ "paymentOptions": [
61
+ {
62
+ "kind": "bank_transfer",
63
+ "label": "Überweisung",
64
+ "holder": "Ferienvermietung Muster GmbH",
65
+ "iban": "DE02 1203 0000 0000 2020 51",
66
+ "remittanceText": "Buchungsnummer: B-2026-0001"
67
+ }
68
+ ]
69
+ }
70
+ ]
71
+ }
72
+ }
73
+ ```
74
+
75
+ ## 2. Read `amount` Instead of `total`
76
+
77
+ The old schedule-level `total` field has been renamed to `amount`:
78
+
79
+ ```ts
80
+ for (const entry of booking.payment.schedule) {
81
+ renderAmount(entry.amount);
82
+ }
83
+ ```
84
+
85
+ The value remains a localized display string. Do not parse it for arithmetic or
86
+ payment initiation.
87
+
88
+ Optional `lines` continue to contain translated labels and formatted amounts:
89
+
90
+ ```ts
91
+ for (const line of entry.lines ?? []) {
92
+ renderBreakdownLine(line.label, line.amount);
93
+ }
94
+ ```
95
+
96
+ ## 3. Render Schedule and Alternative Entries
97
+
98
+ To render every payment entry:
99
+
100
+ ```ts
101
+ const paymentEntries = [...booking.payment.schedule, ...booking.payment.alternatives];
102
+
103
+ for (const entry of paymentEntries) {
104
+ renderPaymentEntry(entry);
105
+ }
106
+ ```
107
+
108
+ Use the stable `kind` only for programmatic behavior. Use `label` for visible
109
+ text.
110
+
111
+ Schedule kinds:
112
+
113
+ - `prepayment`: a named v9 down payment.
114
+ - `remaining_payment`: a named v9 remaining payment.
115
+ - `installment`: a v10 installment step.
116
+ - `deposit`: a v10 deposit step.
117
+
118
+ Alternative kinds:
119
+
120
+ - `full_amount`: settle the complete currently outstanding balance.
121
+
122
+ Do not infer v9 semantics from v10 step order. A v10 installment is not
123
+ automatically a prepayment or remaining payment.
124
+
125
+ ## 4. Treat `paymentOptions` as Capability Data
126
+
127
+ `paymentOptions` is optional on scheduled steps. Its absence means the entry is
128
+ informational and is not currently payable through the SDK.
129
+
130
+ ```ts
131
+ for (const option of entry.paymentOptions ?? []) {
132
+ if (option.kind === "bank_transfer") {
133
+ renderBankTransfer(option);
134
+ } else {
135
+ renderSubmitButton(() => sdk.live.booking.submitPaymentOption(option));
136
+ }
137
+ }
138
+ ```
139
+
140
+ Do not attach payment buttons to future, on-site, or external entries merely
141
+ because they appear in `payment.schedule`.
142
+
143
+ `full_amount` alternatives always contain a `paymentOptions` array. The array can
144
+ be empty when the backend supplies no executable method.
145
+
146
+ ## 5. Render Dates and Payment Locations Directly
147
+
148
+ Before 2.13.0, `dueOn` was locale-short text even though older documentation
149
+ showed an ISO value. Consumers sometimes attempted to parse it as
150
+ `YYYY-MM-DD`.
151
+
152
+ From 2.13.0, `dueOn` is a complete localized phrase:
153
+
154
+ ```text
155
+ Zahlbar bis zum 6. Februar 2027
156
+ Payable until February 6, 2027
157
+ ```
158
+
159
+ Render it directly:
160
+
161
+ ```ts
162
+ if (entry.dueOn) renderSupportingText(entry.dueOn);
163
+ if (entry.paymentAt) renderSupportingText(entry.paymentAt);
164
+ ```
165
+
166
+ Do not prepend another due-date label and do not parse or reformat these fields.
167
+ `paymentAt` is currently populated by v10 when payment-step location information
168
+ is available.
169
+
170
+ ## 6. Account for the Corrected v9 Schedule
171
+
172
+ Legacy v9 now emits both authoritative contractual steps:
173
+
174
+ - `prepayment` with its own amount and deadline.
175
+ - `remaining_payment` with its own amount and deadline.
176
+
177
+ The `full_amount` alternative is separate. When the SDK synthesizes it from
178
+ prepayment plus remaining payment, it has no deadline. The SDK no longer copies
179
+ the prepayment deadline onto that alternative.
180
+
181
+ Consequently, code must not derive a remaining-payment deadline from
182
+ `payment.alternatives`.
183
+
184
+ ## 7. Account for the Expanded v10 Schedule
185
+
186
+ v10 now preserves all remaining backend payment steps in
187
+ `payment.schedule`, including:
188
+
189
+ - `ONLINE`
190
+ - `ON_SITE`
191
+ - `EXTERN`
192
+
193
+ Only the next eligible online step receives an initialized Adyen option. Later
194
+ steps remain available as informational entries. The complete outstanding amount
195
+ can appear separately under `payment.alternatives`.
196
+
197
+ The alternative amount is the current outstanding balance, not necessarily the
198
+ original booking total.
199
+
200
+ ## 8. Migrate Post-Booking Insurance
201
+
202
+ Before 2.13.0:
203
+
204
+ ```ts
205
+ await sdk.live.quote.bookInsurance({
206
+ quote,
207
+ bookingNumber: booking.bookingNumber,
208
+ guestToken: booking.guestToken,
209
+ });
210
+ ```
211
+
212
+ From 2.13.0:
213
+
214
+ ```ts
215
+ await sdk.live.quote.bookInsurance({
216
+ quote,
217
+ booking,
218
+ });
219
+ ```
220
+
221
+ `guestToken` is no longer public. For v9, it is stored as private state on the
222
+ opaque booking object and consumed internally by the SDK.
223
+
224
+ Keep the same live booking object until insurance booking is complete:
225
+
226
+ ```ts
227
+ const booking = await sdk.live.booking.book(input);
228
+
229
+ // Do not JSON round-trip `booking` before this call.
230
+ const insurance = await sdk.live.quote.bookInsurance({ quote, booking });
231
+ ```
232
+
233
+ Spreading, serializing, reconstructing, or transferring the booking object loses
234
+ its private backend context. If the application must cross a page reload or
235
+ process boundary, complete insurance before that boundary.
236
+
237
+ ## 9. Update Payment-Option Selection
238
+
239
+ Before 2.13.0:
240
+
241
+ ```ts
242
+ const option = booking.paymentSchedules[0]?.paymentOptions.find(
243
+ (candidate) => candidate.kind !== "bank_transfer",
244
+ );
245
+ ```
246
+
247
+ From 2.13.0:
248
+
249
+ ```ts
250
+ const option = [...booking.payment.schedule, ...booking.payment.alternatives]
251
+ .flatMap((entry) => entry.paymentOptions ?? [])
252
+ .find((candidate) => candidate.kind !== "bank_transfer");
253
+ ```
254
+
255
+ Continue passing the selected structured option unchanged to
256
+ `submitPaymentOption`.
257
+
258
+ ## 10. Handle Optional Insurance Output
259
+
260
+ `insurancePaymentOptions` is omitted when no post-booking insurance payment is
261
+ available:
262
+
263
+ ```ts
264
+ for (const option of booking.insurancePaymentOptions ?? []) {
265
+ renderInsurancePaymentOption(option);
266
+ }
267
+ ```
268
+
269
+ This keeps v10 and bookings without selected insurance minimal.
270
+
271
+ ## 11. Replace Hardcoded Search Capability Tables
272
+
273
+ This migration is optional and additive. Search UI that needs to decide which
274
+ period controls to render can query backend support without constructing an SDK:
275
+
276
+ ```ts
277
+ import {
278
+ getSupportedPeriodQueryKeys,
279
+ supportsFlexiblePeriodSearch,
280
+ type BackendKind,
281
+ } from "@v-office/website-sdk/capabilities/search";
282
+
283
+ const shouldRenderFlexiblePeriod = (backend: BackendKind) => supportsFlexiblePeriodSearch(backend);
284
+
285
+ const supportedPeriodKeys = getSupportedPeriodQueryKeys("v9");
286
+ supportedPeriodKeys.has("month"); // false
287
+ ```
288
+
289
+ Remove local v9/v10 period-key tables in favor of these helpers. Both helpers are
290
+ derived from the same core definitions used by SDK search parsing, so backend
291
+ support changes do not require consumers to update a copied matrix.
292
+
293
+ The returned `ReadonlySet` includes supported aliases such as `from`, `till`,
294
+ `nights_min`, and `nights_max`. It describes individual key support; normal
295
+ search validation still determines whether a complete combination of keys and
296
+ values is executable.
297
+
298
+ ## Recommended Verification
299
+
300
+ 1. Book a v9 reservation with distinct prepayment and remaining-payment dates.
301
+ 2. Confirm both entries retain their own translated long-form deadline.
302
+ 3. Confirm a synthesized v9 `full_amount` alternative has no deadline.
303
+ 4. Confirm future v9 remaining payment has no payment button unless the SDK
304
+ supplies a payment option.
305
+ 5. Book a v10 reservation with multiple online and on-site/external payment steps.
306
+ 6. Confirm every remaining v10 step is rendered in backend order.
307
+ 7. Confirm only the next payable online step has an Adyen option.
308
+ 8. Confirm the full-payment alternative displays the outstanding balance without
309
+ an inferred deadline.
310
+ 9. Render both supported locales and verify all amounts, dates, locations, labels,
311
+ and breakdown lines are presentation-ready.
312
+ 10. Complete v9 insurance with the live booking object and verify the private
313
+ credential is not present in serialized output.
314
+ 11. If replacing a local search capability table, confirm flexible-period controls
315
+ remain hidden for v9 and visible for v10.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@v-office/website-sdk",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
4
4
  "description": "Website-facing SDK facade backed by @v-office/sdk-core",
5
5
  "bin": {
6
6
  "website-sdk": "./dist/cli.mjs"
@@ -33,6 +33,7 @@
33
33
  },
34
34
  "exports": {
35
35
  ".": "./dist/index.mjs",
36
+ "./capabilities/*": "./dist/capabilities/*.mjs",
36
37
  "./cli": "./dist/cli.mjs",
37
38
  "./package.json": "./package.json"
38
39
  },
@@ -41,7 +42,7 @@
41
42
  },
42
43
  "dependencies": {
43
44
  "@graphql-typed-document-node/core": "3.2.0",
44
- "@v-office/sdk-core": "^1.12.0",
45
+ "@v-office/sdk-core": "^1.13.0",
45
46
  "effect": "4.0.0-beta.85",
46
47
  "graphql": "17.0.2",
47
48
  "yaml": "^2.9.0"