@v-office/website-headless 0.1.0 → 0.1.1

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/dist/index.d.mts CHANGED
@@ -1101,9 +1101,10 @@ interface SearchResultItem {
1101
1101
  name: string;
1102
1102
  /** `address.city`, verbatim (empty when the feed omits it). */
1103
1103
  location: string;
1104
- /** Internal detail link, derived from the name (URL generation), with the
1105
- * user's booking context (dates + party size) appended as a query so the
1106
- * search selection carries into the rental page. */
1104
+ /** Internal detail link — `rentalsPath` (see `runLiveSearch`) + the slug
1105
+ * derived from the name (URL generation), with the user's booking context
1106
+ * (dates + party size) appended as a query so the search selection carries
1107
+ * into the rental page. */
1107
1108
  href: string;
1108
1109
  images: SearchImage[];
1109
1110
  /** Parsed out of the SDK highlights; 0 when the highlight is absent. */
@@ -1219,6 +1220,16 @@ interface SearchPayload {
1219
1220
  /** `pageInfo.hasNextPage`, verbatim. */
1220
1221
  hasNextPage: boolean;
1221
1222
  }
1223
+ interface LiveSearchOptions {
1224
+ /** Path of the site's rental detail pages, prefixed to every result `href`
1225
+ * before the slug (e.g. `/de/unterkuenfte`). A trailing slash is tolerated.
1226
+ * Default: `DEFAULT_RENTALS_PATH`. */
1227
+ rentalsPath?: string | undefined;
1228
+ }
1229
+ /** The rental detail pages' path when the caller names none — the site
1230
+ * starter's German route. A site whose pages live elsewhere (a locale prefix,
1231
+ * another segment) passes its own `rentalsPath` to `runLiveSearch`. */
1232
+ declare const DEFAULT_RENTALS_PATH = "/unterkuenfte";
1222
1233
  /**
1223
1234
  * Run a live search for the given URL query string (e.g.
1224
1235
  * `window.location.search`). Builds the SDK query from the picker params,
@@ -1229,8 +1240,14 @@ interface SearchPayload {
1229
1240
  * Pass `cursor` (the previous page's `pageInfo.nextCursor`, treated as
1230
1241
  * opaque) to fetch the next page. The returned `cursor`/`hasNextPage` are
1231
1242
  * the SDK's `pageInfo` straight through, so the caller can keep paging.
1243
+ *
1244
+ * `options.rentalsPath` is the path the site serves its rental detail pages
1245
+ * under — the part of every result `href` before the slug. Routing is the
1246
+ * site's decision (a locale prefix like `/de/unterkuenfte`, another segment),
1247
+ * so it arrives as an option the way `SearchBar.action` and `Quote.checkoutPath`
1248
+ * do; `locale` never implies it. Defaults to `DEFAULT_RENTALS_PATH`.
1232
1249
  */
1233
- declare function runLiveSearch(sdk: VofficeSdk, searchString: string, locale: Locale, cursor?: string | null): Promise<SearchPayload>;
1250
+ declare function runLiveSearch(sdk: VofficeSdk, searchString: string, locale: Locale, cursor?: string | null, options?: LiveSearchOptions): Promise<SearchPayload>;
1234
1251
  //#endregion
1235
1252
  //#region src/sort.d.ts
1236
1253
  /** URL param. A client-side scope like `property`/`region`, NOT an SDK query
@@ -1337,4 +1354,4 @@ declare function scopeToRegions<T extends {
1337
1354
  id: string;
1338
1355
  }>(items: readonly T[], active: readonly string[], regionsByRentalId: (id: string) => readonly string[] | undefined): T[];
1339
1356
  //#endregion
1340
- export { ActiveFilter, AlternativePeriod, BOOKING_SNAPSHOT_KEY, BUTTON_SOLUTION_PATTERN, BookingConfirmation, BookingContactForm, BookingSnapshot, BookingSnapshotGuests, CHECKOUT_CONTEXT_KEY, CHECKOUT_PARTS, CHECKOUT_RETURN_PATH, CHECKOUT_STRUCTURE, CheckoutContext, type CheckoutFlow, type CheckoutFlowActions, type CheckoutFlowApi, type CheckoutFlowMessages, type CheckoutFlowOptions, type CheckoutFlowState, type CheckoutIssue, type CheckoutPart, type CheckoutPhase, type CountryGroupsLike, DEFAULT_SORT, EndAvailability, FilterDef, FilterType, HUB_ENDPOINTS, InitialAvailability, type InsuranceDocsState, InsurancePaymentLink, Listener, type Locale, MULTI_RATE_CODES, NIGHT_RANGE_ENABLED, NIGHT_RANGE_KEYS, NO_INSURANCE_DOCS, NightRange, PETS_COUNT_PARAM, PETS_PARAM, PaymentLine, PaymentScheduleView, PolicyBranch, PriceQuote, QuoteAddonService, QuoteCancellationPolicy, QuoteInsurance, QuoteInsuranceOption, QuoteLine, QuoteOccupancy, QuotePolicyRule, QuoteResult, QuoteSelectionResult, QuoteUnavailableCode, QuoteView, QuoteVoucher, REGION_PARAM, SORT_OPTIONS, SORT_PARAM, STAGES, SdkConfig, SearchImage, SearchPayload, SearchResultItem, SnapshotImage, SortOption, SortValue, Stage, type Stay, Store, type StructureViolation, Unsubscribe, VALIDATED_FIELDS, VOFFICE_ENDPOINTS, type ValidationMessages, WebsiteSdk, WritableStore, activeFiltersFromQuery, activeRegions, activeSort, adaptGuestQuote, addQuoteService, assertCheckoutStructure, clearQuoteServices, createCheckoutFlow, createSdk, createStore, describeSdkError, detectCountry, emailError, fetchEndAvailability, fetchInitialAvailability, fetchQuote, fieldError, freeCancellationUntil, fullRefundRule, insuranceDocsPending, insuranceIdToReapply, insuranceProductKey, isBooleanFilterActive, isPricedQuery, isRateConfigurationFault, isSortAvailable, isSubmittableOption, isoDate, logSdkFailure, nightlyPrice, normalizePhone, occupancyOf, parseGermanParam, parseNightRange, parseParam, payWithOption, petsCountInQuery, phoneError, policyFreeCancellationUntil, postalcodeError, pricePolicyBranches, removeQuoteService, resolveSdkSort, runLiveSearch, saveBookingSnapshot, saveCheckoutContext, scopeToRegions, sdkConfigFor, selectQuoteInsurance, selectQuotePolicy, selectableInsuranceOptions, selectedInsuranceOption, shownInsuranceResources, stabilizeCardOrder, stayKeyOf, stayParams, streetWarning, submitBooking, tidyPrice };
1357
+ export { ActiveFilter, AlternativePeriod, BOOKING_SNAPSHOT_KEY, BUTTON_SOLUTION_PATTERN, BookingConfirmation, BookingContactForm, BookingSnapshot, BookingSnapshotGuests, CHECKOUT_CONTEXT_KEY, CHECKOUT_PARTS, CHECKOUT_RETURN_PATH, CHECKOUT_STRUCTURE, CheckoutContext, type CheckoutFlow, type CheckoutFlowActions, type CheckoutFlowApi, type CheckoutFlowMessages, type CheckoutFlowOptions, type CheckoutFlowState, type CheckoutIssue, type CheckoutPart, type CheckoutPhase, type CountryGroupsLike, DEFAULT_RENTALS_PATH, DEFAULT_SORT, EndAvailability, FilterDef, FilterType, HUB_ENDPOINTS, InitialAvailability, type InsuranceDocsState, InsurancePaymentLink, Listener, LiveSearchOptions, type Locale, MULTI_RATE_CODES, NIGHT_RANGE_ENABLED, NIGHT_RANGE_KEYS, NO_INSURANCE_DOCS, NightRange, PETS_COUNT_PARAM, PETS_PARAM, PaymentLine, PaymentScheduleView, PolicyBranch, PriceQuote, QuoteAddonService, QuoteCancellationPolicy, QuoteInsurance, QuoteInsuranceOption, QuoteLine, QuoteOccupancy, QuotePolicyRule, QuoteResult, QuoteSelectionResult, QuoteUnavailableCode, QuoteView, QuoteVoucher, REGION_PARAM, SORT_OPTIONS, SORT_PARAM, STAGES, SdkConfig, SearchImage, SearchPayload, SearchResultItem, SnapshotImage, SortOption, SortValue, Stage, type Stay, Store, type StructureViolation, Unsubscribe, VALIDATED_FIELDS, VOFFICE_ENDPOINTS, type ValidationMessages, WebsiteSdk, WritableStore, activeFiltersFromQuery, activeRegions, activeSort, adaptGuestQuote, addQuoteService, assertCheckoutStructure, clearQuoteServices, createCheckoutFlow, createSdk, createStore, describeSdkError, detectCountry, emailError, fetchEndAvailability, fetchInitialAvailability, fetchQuote, fieldError, freeCancellationUntil, fullRefundRule, insuranceDocsPending, insuranceIdToReapply, insuranceProductKey, isBooleanFilterActive, isPricedQuery, isRateConfigurationFault, isSortAvailable, isSubmittableOption, isoDate, logSdkFailure, nightlyPrice, normalizePhone, occupancyOf, parseGermanParam, parseNightRange, parseParam, payWithOption, petsCountInQuery, phoneError, policyFreeCancellationUntil, postalcodeError, pricePolicyBranches, removeQuoteService, resolveSdkSort, runLiveSearch, saveBookingSnapshot, saveCheckoutContext, scopeToRegions, sdkConfigFor, selectQuoteInsurance, selectQuotePolicy, selectableInsuranceOptions, selectedInsuranceOption, shownInsuranceResources, stabilizeCardOrder, stayKeyOf, stayParams, streetWarning, submitBooking, tidyPrice };
package/dist/index.mjs CHANGED
@@ -1889,14 +1889,18 @@ function buildHandover(params, dates) {
1889
1889
  const suffix = out.toString();
1890
1890
  return suffix ? `?${suffix}` : "";
1891
1891
  }
1892
- function mapBase(item) {
1892
+ /** The rental detail pages' path when the caller names none — the site
1893
+ * starter's German route. A site whose pages live elsewhere (a locale prefix,
1894
+ * another segment) passes its own `rentalsPath` to `runLiveSearch`. */
1895
+ const DEFAULT_RENTALS_PATH = "/unterkuenfte";
1896
+ function mapBase(item, rentalsPath) {
1893
1897
  const name = item.nameOrLabel.trim();
1894
1898
  const highlights = item.highlights ?? [];
1895
1899
  return {
1896
1900
  id: item.id,
1897
1901
  name,
1898
1902
  location: item.address?.city?.trim() ?? "",
1899
- href: `/unterkuenfte/${slugify(name)}`,
1903
+ href: `${rentalsPath.replace(/\/+$/, "")}/${slugify(name)}`,
1900
1904
  images: (item.images ?? []).map((img) => ({
1901
1905
  src: img.src,
1902
1906
  srcset: img.srcset?.trim() || void 0,
@@ -1946,11 +1950,11 @@ function mapDiscount(discount) {
1946
1950
  })
1947
1951
  };
1948
1952
  }
1949
- function mapItem(item, params, locale) {
1953
+ function mapItem(item, params, locale, rentalsPath) {
1950
1954
  const scopeType = typeof item.scope === "string" ? item.scope : item.scope?.type;
1951
1955
  const alternativePeriodLabel = formatPeriodLabel(item.alternativePeriod ?? (typeof item.scope === "object" ? item.scope.alternativePeriod : void 0), locale);
1952
1956
  const isAlternativePeriod = alternativePeriodLabel != null || scopeType === "alternativePeriod" || scopeType === "alternative-period";
1953
- const base = mapBase(item);
1957
+ const base = mapBase(item, rentalsPath);
1954
1958
  return {
1955
1959
  ...base,
1956
1960
  href: `${base.href}${buildHandover(params)}`,
@@ -1967,8 +1971,8 @@ function mapItem(item, params, locale) {
1967
1971
  * label come from the first candidate period (the SDK returns them best-first,
1968
1972
  * `boost`-ordered). Always flagged as an alternative so the card shows the
1969
1973
  * period pill instead of treating it as an exact total. */
1970
- function mapAlternativeEntry(entry, params, locale) {
1971
- const base = mapBase(entry.item);
1974
+ function mapAlternativeEntry(entry, params, locale, rentalsPath) {
1975
+ const base = mapBase(entry.item, rentalsPath);
1972
1976
  const periods = (entry.alternativePeriods ?? []).flatMap((candidate) => {
1973
1977
  const label = formatPeriodLabel({
1974
1978
  start: candidate.start,
@@ -2016,8 +2020,15 @@ function mapAlternativeEntry(entry, params, locale) {
2016
2020
  * Pass `cursor` (the previous page's `pageInfo.nextCursor`, treated as
2017
2021
  * opaque) to fetch the next page. The returned `cursor`/`hasNextPage` are
2018
2022
  * the SDK's `pageInfo` straight through, so the caller can keep paging.
2023
+ *
2024
+ * `options.rentalsPath` is the path the site serves its rental detail pages
2025
+ * under — the part of every result `href` before the slug. Routing is the
2026
+ * site's decision (a locale prefix like `/de/unterkuenfte`, another segment),
2027
+ * so it arrives as an option the way `SearchBar.action` and `Quote.checkoutPath`
2028
+ * do; `locale` never implies it. Defaults to `DEFAULT_RENTALS_PATH`.
2019
2029
  */
2020
- async function runLiveSearch(sdk, searchString, locale, cursor) {
2030
+ async function runLiveSearch(sdk, searchString, locale, cursor, options = {}) {
2031
+ const rentalsPath = options.rentalsPath ?? "/unterkuenfte";
2021
2032
  const params = new URLSearchParams(searchString);
2022
2033
  const nights = computeNights(params);
2023
2034
  const sort = resolveSdkSort(searchString);
@@ -2030,9 +2041,9 @@ async function runLiveSearch(sdk, searchString, locale, cursor) {
2030
2041
  ...sort ? { sort } : {},
2031
2042
  ...cursor ? { cursor } : {}
2032
2043
  });
2033
- const exact = result.items.map((item) => mapItem(item, params, locale));
2044
+ const exact = result.items.map((item) => mapItem(item, params, locale, rentalsPath));
2034
2045
  const exactIds = new Set(exact.map((item) => item.id));
2035
- const alternatives = (result.alternatives ?? []).filter((entry) => entry?.item?.id && !exactIds.has(entry.item.id)).map((entry) => mapAlternativeEntry(entry, params, locale));
2046
+ const alternatives = (result.alternatives ?? []).filter((entry) => entry?.item?.id && !exactIds.has(entry.item.id)).map((entry) => mapAlternativeEntry(entry, params, locale, rentalsPath));
2036
2047
  const items = exact.concat(alternatives);
2037
2048
  return {
2038
2049
  items,
@@ -2082,4 +2093,4 @@ function scopeToRegions(items, active, regionsByRentalId) {
2082
2093
  return items.filter((item) => regionsByRentalId(item.id)?.some((r) => active.includes(r)));
2083
2094
  }
2084
2095
  //#endregion
2085
- export { BOOKING_SNAPSHOT_KEY, BUTTON_SOLUTION_PATTERN, CHECKOUT_CONTEXT_KEY, CHECKOUT_PARTS, CHECKOUT_RETURN_PATH, CHECKOUT_STRUCTURE, DEFAULT_SORT, HUB_ENDPOINTS, MULTI_RATE_CODES, NIGHT_RANGE_ENABLED, NIGHT_RANGE_KEYS, NO_INSURANCE_DOCS, PETS_COUNT_PARAM, PETS_PARAM, REGION_PARAM, SORT_OPTIONS, SORT_PARAM, STAGES, VALIDATED_FIELDS, VOFFICE_ENDPOINTS, activeFiltersFromQuery, activeRegions, activeSort, adaptGuestQuote, addQuoteService, assertCheckoutStructure, clearQuoteServices, createCheckoutFlow, createSdk, createStore, describeSdkError, detectCountry, emailError, fetchEndAvailability, fetchInitialAvailability, fetchQuote, fieldError, freeCancellationUntil, fullRefundRule, insuranceDocsPending, insuranceIdToReapply, insuranceProductKey, isBooleanFilterActive, isPricedQuery, isRateConfigurationFault, isSortAvailable, isSubmittableOption, isoDate, logSdkFailure, nightlyPrice, normalizePhone, occupancyOf, parseGermanParam, parseNightRange, parseParam, payWithOption, petsCountInQuery, phoneError, policyFreeCancellationUntil, postalcodeError, pricePolicyBranches, removeQuoteService, resolveSdkSort, runLiveSearch, saveBookingSnapshot, saveCheckoutContext, scopeToRegions, sdkConfigFor, selectQuoteInsurance, selectQuotePolicy, selectableInsuranceOptions, selectedInsuranceOption, shownInsuranceResources, stabilizeCardOrder, stayKeyOf, stayParams, streetWarning, submitBooking, tidyPrice };
2096
+ export { BOOKING_SNAPSHOT_KEY, BUTTON_SOLUTION_PATTERN, CHECKOUT_CONTEXT_KEY, CHECKOUT_PARTS, CHECKOUT_RETURN_PATH, CHECKOUT_STRUCTURE, DEFAULT_RENTALS_PATH, DEFAULT_SORT, HUB_ENDPOINTS, MULTI_RATE_CODES, NIGHT_RANGE_ENABLED, NIGHT_RANGE_KEYS, NO_INSURANCE_DOCS, PETS_COUNT_PARAM, PETS_PARAM, REGION_PARAM, SORT_OPTIONS, SORT_PARAM, STAGES, VALIDATED_FIELDS, VOFFICE_ENDPOINTS, activeFiltersFromQuery, activeRegions, activeSort, adaptGuestQuote, addQuoteService, assertCheckoutStructure, clearQuoteServices, createCheckoutFlow, createSdk, createStore, describeSdkError, detectCountry, emailError, fetchEndAvailability, fetchInitialAvailability, fetchQuote, fieldError, freeCancellationUntil, fullRefundRule, insuranceDocsPending, insuranceIdToReapply, insuranceProductKey, isBooleanFilterActive, isPricedQuery, isRateConfigurationFault, isSortAvailable, isSubmittableOption, isoDate, logSdkFailure, nightlyPrice, normalizePhone, occupancyOf, parseGermanParam, parseNightRange, parseParam, payWithOption, petsCountInQuery, phoneError, policyFreeCancellationUntil, postalcodeError, pricePolicyBranches, removeQuoteService, resolveSdkSort, runLiveSearch, saveBookingSnapshot, saveCheckoutContext, scopeToRegions, sdkConfigFor, selectQuoteInsurance, selectQuotePolicy, selectableInsuranceOptions, selectedInsuranceOption, shownInsuranceResources, stabilizeCardOrder, stayKeyOf, stayParams, streetWarning, submitBooking, tidyPrice };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@v-office/website-headless",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Framework-free behavior layer for v-office websites, never UI: the checkout flow as a subscribable store (createCheckoutFlow), validation and insurance rules, the checkout's structural requirements, the live search, availability and quote runners over a caller-owned SDK, and progressive-enhancement engines for server-rendered markup",
5
5
  "files": [
6
6
  "dist",