lynkow 1.40.2 → 1.41.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/dist/index.d.mts CHANGED
@@ -5152,6 +5152,134 @@ interface CategoryResolveResponse {
5152
5152
  */
5153
5153
  type ResolveResponse = ContentResolveResponse | CategoryResolveResponse;
5154
5154
 
5155
+ /**
5156
+ * A published product on the storefront catalogue. Mirrors the API's public
5157
+ * whitelist: only buyer-facing fields are present, and `id` is a wire-encoded
5158
+ * prefixed id (never a raw database identifier).
5159
+ */
5160
+ interface Product {
5161
+ /** The product id as a prefixed wire id (e.g. `'prod_...'`). Stable; safe to store and link. */
5162
+ id: string;
5163
+ /** URL-friendly unique slug. Use it to build a product page URL or to address the product in `products.getBySlug()`. */
5164
+ slug: string;
5165
+ /** Product title in the requested locale. Always non-empty for a published product. */
5166
+ title: string;
5167
+ /** Long product description, or `null` when the merchant left it empty. */
5168
+ description: string | null;
5169
+ /** Price in the smallest currency unit (cents). Divide by 100 to display. */
5170
+ priceCents: number;
5171
+ /** ISO 4217 currency code (e.g. `'EUR'`). */
5172
+ currency: string;
5173
+ /** Optional strikethrough "was" price in cents, or `null` when there is no comparison price. */
5174
+ compareAtPriceCents: number | null;
5175
+ /** Ordered public image URLs, or an empty array when the product has no images. */
5176
+ images: string[];
5177
+ /** The primary image URL (mirror of `images[0]`), or `null` when there are no images. */
5178
+ thumbnail: string | null;
5179
+ /** `'standard'` for a normal product, `'bookable'` for a reservation product (route it to the slot UI and {@link https://www.lynkow.com/docs reservations}). */
5180
+ kind: 'standard' | 'bookable';
5181
+ /** SEO title override, or `null` when unset (fall back to `title`). */
5182
+ seoTitle: string | null;
5183
+ /** SEO meta description, or `null` when unset. */
5184
+ seoDescription: string | null;
5185
+ /** Catalogue SKU, or `null` when unset. */
5186
+ sku: string | null;
5187
+ /** Product variants. Reserved for a later release: always an empty array in this version. */
5188
+ variants: [];
5189
+ }
5190
+ /** Filters for a storefront product listing. All optional. */
5191
+ interface ProductsFilters {
5192
+ /** Page number (1-based). Defaults to 1. */
5193
+ page?: number;
5194
+ /** Items per page. Defaults to 20, max 100. */
5195
+ limit?: number;
5196
+ /** Full-text search across title and slug. */
5197
+ search?: string;
5198
+ /** Restrict to a product kind: `'standard'` or `'bookable'`. */
5199
+ kind?: 'standard' | 'bookable';
5200
+ /** Sort field: `'title'`, `'price_cents'`, or `'created_at'`. Defaults to `'created_at'`. */
5201
+ sortBy?: 'title' | 'price_cents' | 'created_at';
5202
+ /** Sort direction: `'asc'` or `'desc'`. Defaults to `'desc'`. */
5203
+ sortOrder?: 'asc' | 'desc';
5204
+ }
5205
+ /** Paginated product list response: the products on the page plus pagination metadata. */
5206
+ interface ProductsListResponse {
5207
+ /** The published products on this page. */
5208
+ data: Product[];
5209
+ /** Pagination info (total, currentPage, lastPage, perPage, hasMorePages). */
5210
+ meta: PaginationMeta;
5211
+ }
5212
+
5213
+ /** A single computed bookable slot for a reservation product. */
5214
+ interface AvailabilitySlot {
5215
+ /** Slot start as an ISO 8601 datetime (e.g. `'2026-07-10T18:00:00.000Z'`). */
5216
+ startsAt: string;
5217
+ /** Slot end as an ISO 8601 datetime. Derived from the resource slot duration. */
5218
+ endsAt: string;
5219
+ /** `true` when at least one seat is free for this slot. */
5220
+ available: boolean;
5221
+ /** Seats still free for this slot (capacity minus confirmed bookings). Non-negative: floored at 0. */
5222
+ seatsRemaining: number;
5223
+ }
5224
+ /** The effective date window the returned availability slots cover. */
5225
+ interface AvailabilityWindow {
5226
+ /** Window start as a calendar date `'YYYY-MM-DD'`, echoing the requested `from`. */
5227
+ from: string;
5228
+ /** Window end as a calendar date `'YYYY-MM-DD'`. May be earlier than the requested `to` when the server clamps an over-wide span. */
5229
+ to: string;
5230
+ }
5231
+ /** Filters for a reservation availability query. */
5232
+ interface AvailabilityFilters {
5233
+ /** Range start (inclusive) as a calendar date `'YYYY-MM-DD'`. Required. */
5234
+ from: string;
5235
+ /** Range end (inclusive) as a calendar date `'YYYY-MM-DD'`. Must not precede `from`. An over-wide span is clamped server-side. Required. */
5236
+ to: string;
5237
+ /** Optional party-size hint (1 to 50). Accepted for forward-compatibility; v1 does not filter slots by it (read each slot's `seatsRemaining` instead). */
5238
+ partySize?: number;
5239
+ }
5240
+ /** The availability read response for a bookable product. */
5241
+ interface AvailabilityResponse {
5242
+ /** The computed open slots across the effective window, in chronological order. */
5243
+ slots: AvailabilitySlot[];
5244
+ /** IANA timezone the slots are expressed in for display (e.g. `'Europe/Paris'`). */
5245
+ timezone: string;
5246
+ /** The effective window the slots cover. Its `to` may be earlier than requested when the span was clamped server-side. */
5247
+ window: AvailabilityWindow;
5248
+ }
5249
+ /** Guest contact plus the chosen slot, for creating a reservation. No account needed. */
5250
+ interface BookingCreateData {
5251
+ /** The chosen slot start, copied from an {@link AvailabilitySlot} `startsAt`. Full ISO 8601 datetime. */
5252
+ startsAt: string;
5253
+ /** Number of guests. Integer from 1 to 50; must fit the slot's `seatsRemaining`. */
5254
+ partySize: number;
5255
+ /** Guest full name. 1 to 200 chars. */
5256
+ guestName: string;
5257
+ /** Guest email. A valid address, max 320 chars. The confirmation echoes it. */
5258
+ guestEmail: string;
5259
+ /** Optional guest phone number. 3 to 40 chars when provided. */
5260
+ guestPhone?: string;
5261
+ }
5262
+ /** A confirmed reservation returned after a successful booking. */
5263
+ interface Booking {
5264
+ /** Guest-safe reservation reference (opaque `'bkg_...'` id) for the buyer's records. */
5265
+ reference: string;
5266
+ /**
5267
+ * Reservation status. Always `'confirmed'` in v1: a storefront booking is
5268
+ * confirmed immediately because payment is taken on-site, never charged online.
5269
+ */
5270
+ status: 'confirmed';
5271
+ /** The booked slot start as an ISO 8601 datetime. */
5272
+ startsAt: string;
5273
+ /** The booked slot end as an ISO 8601 datetime, derived from the resource slot duration. */
5274
+ endsAt: string;
5275
+ /** Number of guests on the reservation. */
5276
+ partySize: number;
5277
+ /** The guest name as submitted, echoed for the receipt. */
5278
+ guestName: string;
5279
+ /** The guest email as submitted, echoed for the receipt. */
5280
+ guestEmail: string;
5281
+ }
5282
+
5155
5283
  /**
5156
5284
  * Base request options available on every SDK method.
5157
5285
  * These override the defaults set in {@link LynkowConfig}.
@@ -6488,6 +6616,167 @@ declare class MediaHelperService {
6488
6616
  private parseImageUrl;
6489
6617
  }
6490
6618
 
6619
+ /**
6620
+ * Service for reading a site's published product catalogue.
6621
+ *
6622
+ * Accessible via `lynkow.products`. Returns only PUBLISHED products. Requires a
6623
+ * publishable key: pass `publishableKey` to `createClient(...)` so every request
6624
+ * carries it (commerce routes reject calls without a valid key). Responses are
6625
+ * cached in-memory for 5 minutes (SHORT TTL) when a cache adapter is configured
6626
+ * on the client.
6627
+ *
6628
+ * @example
6629
+ * ```typescript
6630
+ * const lynkow = createClient({ siteId: '...', publishableKey: 'lkw_pk_...' })
6631
+ *
6632
+ * // List published products
6633
+ * const { data, meta } = await lynkow.products.list({ limit: 12, kind: 'bookable' })
6634
+ *
6635
+ * // Read a single product by slug or `prod_` wire id
6636
+ * const product = await lynkow.products.getBySlug('sunset-dinner-cruise')
6637
+ * ```
6638
+ */
6639
+ declare class ProductsService extends BaseService {
6640
+ /**
6641
+ * Retrieves a paginated list of published products, sorted by creation date
6642
+ * (newest first by default). Cached for 5 minutes per unique filter combination.
6643
+ *
6644
+ * @param filters - Optional {@link ProductsFilters}: `page`/`limit`, `search`, `kind`, `sortBy`/`sortOrder`.
6645
+ * @param options - Base request options (locale override, custom fetch options).
6646
+ * @returns A {@link ProductsListResponse} with `data` (published {@link Product}[]) and `meta` (pagination info).
6647
+ * @throws {LynkowError} With code `'UNAUTHORIZED'` if no valid publishable key is set.
6648
+ *
6649
+ * @example
6650
+ * ```typescript
6651
+ * const { data, meta } = await lynkow.products.list({ page: 1, limit: 12, kind: 'bookable' })
6652
+ * ```
6653
+ */
6654
+ list(filters?: ProductsFilters, options?: BaseRequestOptions): Promise<ProductsListResponse>;
6655
+ /**
6656
+ * Retrieves a single published product by its `prod_...` wire id or its slug.
6657
+ * Cached for 5 minutes per id/slug.
6658
+ *
6659
+ * Named `getBySlug` (not `get`) to match the SDK convention: `BaseService`
6660
+ * reserves a protected `get()` that the shared caching path dispatches to, so a
6661
+ * public `get()` on a service would hijack it. Mirrors `contents.getBySlug` and
6662
+ * `reviews.getBySlug`, both of which also accept an id or a slug.
6663
+ *
6664
+ * @param idOrSlug - The product's `prod_...` wire id or its URL slug.
6665
+ * @param options - Base request options (locale override, custom fetch options).
6666
+ * @returns The {@link Product}.
6667
+ * @throws {LynkowError} With code `'NOT_FOUND'` if the product is missing, draft, or archived.
6668
+ *
6669
+ * @example
6670
+ * ```typescript
6671
+ * const product = await lynkow.products.getBySlug('sunset-dinner-cruise')
6672
+ * console.log(`${(product.priceCents / 100).toFixed(2)} ${product.currency}`)
6673
+ * ```
6674
+ */
6675
+ getBySlug(idOrSlug: string, options?: BaseRequestOptions): Promise<Product>;
6676
+ }
6677
+
6678
+ /**
6679
+ * Service for reading a bookable product's availability and creating guest
6680
+ * reservations. Accessible via `lynkow.reservations`.
6681
+ *
6682
+ * Requires a publishable key: pass `publishableKey` to `createClient(...)` so
6683
+ * every request carries it. Reservation routes reject calls without a valid key.
6684
+ * Payment is taken on-site: a successful booking is `confirmed` immediately,
6685
+ * never charged online. Anti-spam honeypot fields are injected automatically on
6686
+ * `bookings.create`; on reCAPTCHA-protected storefronts pass
6687
+ * `options.recaptchaToken`. Availability is not cached (it changes on every booking).
6688
+ *
6689
+ * @example
6690
+ * ```typescript
6691
+ * const lynkow = createClient({ siteId: '...', publishableKey: 'lkw_pk_...' })
6692
+ *
6693
+ * const { slots, timezone } = await lynkow.reservations.availability('sunset-dinner-cruise', {
6694
+ * from: '2026-07-10',
6695
+ * to: '2026-07-17',
6696
+ * })
6697
+ *
6698
+ * const booking = await lynkow.reservations.bookings.create('sunset-dinner-cruise', {
6699
+ * startsAt: slots[0].startsAt,
6700
+ * partySize: 2,
6701
+ * guestName: 'Alice Martin',
6702
+ * guestEmail: 'alice@example.com',
6703
+ * })
6704
+ * ```
6705
+ */
6706
+ declare class ReservationsService extends BaseService {
6707
+ /**
6708
+ * Client-creation timestamp anchoring the anti-spam timing window on
6709
+ * `bookings.create`. The server rejects a submission whose age (`Date.now()`
6710
+ * minus this value) is below its minimum fill time (too fast, likely a bot)
6711
+ * or above its maximum form lifetime (stale). Captured once at client
6712
+ * creation, so a very long-lived client eventually drifts past the maximum
6713
+ * window.
6714
+ */
6715
+ private sessionStartTime;
6716
+ constructor(config: InternalConfig);
6717
+ /** Nested booking-write surface: `lynkow.reservations.bookings.create(...)`. */
6718
+ readonly bookings: {
6719
+ create: (productIdOrSlug: string, data: BookingCreateData, options?: SubmitOptions & BaseRequestOptions) => Promise<Booking>;
6720
+ };
6721
+ /**
6722
+ * Retrieves the computed open slots for a bookable product across a date range.
6723
+ * Not cached: availability changes as other buyers book.
6724
+ *
6725
+ * @param productIdOrSlug - The bookable product's `prod_...` wire id or its slug.
6726
+ * @param filters - {@link AvailabilityFilters}: `from` and `to` (calendar dates `YYYY-MM-DD`, required, `to` not before `from`) and an optional `partySize`.
6727
+ * @returns An {@link AvailabilityResponse} with `slots` (chronological {@link AvailabilitySlot}[]), the display `timezone`, and the effective `window`.
6728
+ * @throws {LynkowError} With code `'NOT_FOUND'` if the product is missing or not bookable; `'UNAUTHORIZED'` if no valid publishable key is set.
6729
+ *
6730
+ * @example
6731
+ * ```typescript
6732
+ * const { slots, timezone } = await lynkow.reservations.availability('sunset-dinner-cruise', {
6733
+ * from: '2026-07-10',
6734
+ * to: '2026-07-17',
6735
+ * partySize: 2,
6736
+ * })
6737
+ * ```
6738
+ */
6739
+ availability(productIdOrSlug: string, filters: AvailabilityFilters): Promise<AvailabilityResponse>;
6740
+ /**
6741
+ * Creates a guest reservation for a chosen slot. No account required. Tuned
6742
+ * for the in-browser guest flow: the client is created around page load and
6743
+ * the buyer books moments later.
6744
+ *
6745
+ * Anti-spam honeypot + timestamp fields are injected automatically. The
6746
+ * honeypot is always empty, so the honeypot/content silent-acknowledgement
6747
+ * path (HTTP 200, no error) is unreachable through the SDK. The timestamp
6748
+ * check, however, is a real thrown-error window relative to client creation:
6749
+ * a booking sent sooner than the server's minimum fill time (default 3s)
6750
+ * after `createClient(...)` is rejected `TOO_MANY_REQUESTS` (HTTP 429), and
6751
+ * one sent later than the server's maximum form lifetime (default ~1h) is
6752
+ * rejected `BAD_REQUEST` (HTTP 400, "form expired"). Handle both when driving
6753
+ * this from a long-lived or non-browser client.
6754
+ *
6755
+ * If the storefront enforces reCAPTCHA (rather than the default honeypot),
6756
+ * pass `options.recaptchaToken`; without it the server rejects the booking
6757
+ * `BAD_REQUEST` (HTTP 400, "reCAPTCHA required"). Mirrors `reviews.submit`.
6758
+ *
6759
+ * @param productIdOrSlug - The bookable product's `prod_...` wire id or its slug.
6760
+ * @param data - {@link BookingCreateData}: chosen `startsAt`, `partySize`, and guest `guestName`/`guestEmail`/optional `guestPhone`.
6761
+ * @param options - Optional {@link SubmitOptions} + request options: `recaptchaToken` (required on reCAPTCHA-protected storefronts), a `locale` override, and `fetchOptions` (e.g. an `AbortSignal`).
6762
+ * @returns The created {@link Booking} (reference, status, slot instants, party size, echoed name/email).
6763
+ * @throws {LynkowError} With code `'VALIDATION_ERROR'` (HTTP 422) on bad input or a filled/unavailable slot; `'NOT_FOUND'` if not a bookable product; `'UNAUTHORIZED'` if no valid publishable key is set; `'TOO_MANY_REQUESTS'` (HTTP 429) if sent within the server's minimum fill time after client creation (anti-spam too-fast); `'BAD_REQUEST'` (HTTP 400) if sent past the server's maximum form lifetime after client creation (anti-spam expired) or if reCAPTCHA is enforced and no `recaptchaToken` is supplied.
6764
+ *
6765
+ * @example
6766
+ * ```typescript
6767
+ * const booking = await lynkow.reservations.bookings.create('sunset-dinner-cruise', {
6768
+ * startsAt: '2026-07-10T18:00:00.000Z',
6769
+ * partySize: 2,
6770
+ * guestName: 'Alice Martin',
6771
+ * guestEmail: 'alice@example.com',
6772
+ * guestPhone: '+33 6 12 34 56 78',
6773
+ * })
6774
+ * console.log(`Reservation ${booking.reference} is ${booking.status}. Pay on-site.`)
6775
+ * ```
6776
+ */
6777
+ private createBooking;
6778
+ }
6779
+
6491
6780
  /**
6492
6781
  * Lynkow SDK Client
6493
6782
  * Main entry point for the SDK
@@ -6598,6 +6887,18 @@ interface Client extends LynkowClient {
6598
6887
  * Lynkow Instant Search service
6599
6888
  */
6600
6889
  search: SearchService;
6890
+ /**
6891
+ * Storefront product catalogue service (commerce).
6892
+ * Provides `list()` and `getBySlug()` for published products.
6893
+ * Requires a `publishableKey` on the client.
6894
+ */
6895
+ products: ProductsService;
6896
+ /**
6897
+ * Storefront reservations service (commerce).
6898
+ * Provides `availability()` and the nested `bookings.create()` for bookable products.
6899
+ * Requires a `publishableKey` on the client.
6900
+ */
6901
+ reservations: ReservationsService;
6601
6902
  }
6602
6903
  /**
6603
6904
  * Creates a Lynkow client instance (SDK v3)
package/dist/index.d.ts CHANGED
@@ -5152,6 +5152,134 @@ interface CategoryResolveResponse {
5152
5152
  */
5153
5153
  type ResolveResponse = ContentResolveResponse | CategoryResolveResponse;
5154
5154
 
5155
+ /**
5156
+ * A published product on the storefront catalogue. Mirrors the API's public
5157
+ * whitelist: only buyer-facing fields are present, and `id` is a wire-encoded
5158
+ * prefixed id (never a raw database identifier).
5159
+ */
5160
+ interface Product {
5161
+ /** The product id as a prefixed wire id (e.g. `'prod_...'`). Stable; safe to store and link. */
5162
+ id: string;
5163
+ /** URL-friendly unique slug. Use it to build a product page URL or to address the product in `products.getBySlug()`. */
5164
+ slug: string;
5165
+ /** Product title in the requested locale. Always non-empty for a published product. */
5166
+ title: string;
5167
+ /** Long product description, or `null` when the merchant left it empty. */
5168
+ description: string | null;
5169
+ /** Price in the smallest currency unit (cents). Divide by 100 to display. */
5170
+ priceCents: number;
5171
+ /** ISO 4217 currency code (e.g. `'EUR'`). */
5172
+ currency: string;
5173
+ /** Optional strikethrough "was" price in cents, or `null` when there is no comparison price. */
5174
+ compareAtPriceCents: number | null;
5175
+ /** Ordered public image URLs, or an empty array when the product has no images. */
5176
+ images: string[];
5177
+ /** The primary image URL (mirror of `images[0]`), or `null` when there are no images. */
5178
+ thumbnail: string | null;
5179
+ /** `'standard'` for a normal product, `'bookable'` for a reservation product (route it to the slot UI and {@link https://www.lynkow.com/docs reservations}). */
5180
+ kind: 'standard' | 'bookable';
5181
+ /** SEO title override, or `null` when unset (fall back to `title`). */
5182
+ seoTitle: string | null;
5183
+ /** SEO meta description, or `null` when unset. */
5184
+ seoDescription: string | null;
5185
+ /** Catalogue SKU, or `null` when unset. */
5186
+ sku: string | null;
5187
+ /** Product variants. Reserved for a later release: always an empty array in this version. */
5188
+ variants: [];
5189
+ }
5190
+ /** Filters for a storefront product listing. All optional. */
5191
+ interface ProductsFilters {
5192
+ /** Page number (1-based). Defaults to 1. */
5193
+ page?: number;
5194
+ /** Items per page. Defaults to 20, max 100. */
5195
+ limit?: number;
5196
+ /** Full-text search across title and slug. */
5197
+ search?: string;
5198
+ /** Restrict to a product kind: `'standard'` or `'bookable'`. */
5199
+ kind?: 'standard' | 'bookable';
5200
+ /** Sort field: `'title'`, `'price_cents'`, or `'created_at'`. Defaults to `'created_at'`. */
5201
+ sortBy?: 'title' | 'price_cents' | 'created_at';
5202
+ /** Sort direction: `'asc'` or `'desc'`. Defaults to `'desc'`. */
5203
+ sortOrder?: 'asc' | 'desc';
5204
+ }
5205
+ /** Paginated product list response: the products on the page plus pagination metadata. */
5206
+ interface ProductsListResponse {
5207
+ /** The published products on this page. */
5208
+ data: Product[];
5209
+ /** Pagination info (total, currentPage, lastPage, perPage, hasMorePages). */
5210
+ meta: PaginationMeta;
5211
+ }
5212
+
5213
+ /** A single computed bookable slot for a reservation product. */
5214
+ interface AvailabilitySlot {
5215
+ /** Slot start as an ISO 8601 datetime (e.g. `'2026-07-10T18:00:00.000Z'`). */
5216
+ startsAt: string;
5217
+ /** Slot end as an ISO 8601 datetime. Derived from the resource slot duration. */
5218
+ endsAt: string;
5219
+ /** `true` when at least one seat is free for this slot. */
5220
+ available: boolean;
5221
+ /** Seats still free for this slot (capacity minus confirmed bookings). Non-negative: floored at 0. */
5222
+ seatsRemaining: number;
5223
+ }
5224
+ /** The effective date window the returned availability slots cover. */
5225
+ interface AvailabilityWindow {
5226
+ /** Window start as a calendar date `'YYYY-MM-DD'`, echoing the requested `from`. */
5227
+ from: string;
5228
+ /** Window end as a calendar date `'YYYY-MM-DD'`. May be earlier than the requested `to` when the server clamps an over-wide span. */
5229
+ to: string;
5230
+ }
5231
+ /** Filters for a reservation availability query. */
5232
+ interface AvailabilityFilters {
5233
+ /** Range start (inclusive) as a calendar date `'YYYY-MM-DD'`. Required. */
5234
+ from: string;
5235
+ /** Range end (inclusive) as a calendar date `'YYYY-MM-DD'`. Must not precede `from`. An over-wide span is clamped server-side. Required. */
5236
+ to: string;
5237
+ /** Optional party-size hint (1 to 50). Accepted for forward-compatibility; v1 does not filter slots by it (read each slot's `seatsRemaining` instead). */
5238
+ partySize?: number;
5239
+ }
5240
+ /** The availability read response for a bookable product. */
5241
+ interface AvailabilityResponse {
5242
+ /** The computed open slots across the effective window, in chronological order. */
5243
+ slots: AvailabilitySlot[];
5244
+ /** IANA timezone the slots are expressed in for display (e.g. `'Europe/Paris'`). */
5245
+ timezone: string;
5246
+ /** The effective window the slots cover. Its `to` may be earlier than requested when the span was clamped server-side. */
5247
+ window: AvailabilityWindow;
5248
+ }
5249
+ /** Guest contact plus the chosen slot, for creating a reservation. No account needed. */
5250
+ interface BookingCreateData {
5251
+ /** The chosen slot start, copied from an {@link AvailabilitySlot} `startsAt`. Full ISO 8601 datetime. */
5252
+ startsAt: string;
5253
+ /** Number of guests. Integer from 1 to 50; must fit the slot's `seatsRemaining`. */
5254
+ partySize: number;
5255
+ /** Guest full name. 1 to 200 chars. */
5256
+ guestName: string;
5257
+ /** Guest email. A valid address, max 320 chars. The confirmation echoes it. */
5258
+ guestEmail: string;
5259
+ /** Optional guest phone number. 3 to 40 chars when provided. */
5260
+ guestPhone?: string;
5261
+ }
5262
+ /** A confirmed reservation returned after a successful booking. */
5263
+ interface Booking {
5264
+ /** Guest-safe reservation reference (opaque `'bkg_...'` id) for the buyer's records. */
5265
+ reference: string;
5266
+ /**
5267
+ * Reservation status. Always `'confirmed'` in v1: a storefront booking is
5268
+ * confirmed immediately because payment is taken on-site, never charged online.
5269
+ */
5270
+ status: 'confirmed';
5271
+ /** The booked slot start as an ISO 8601 datetime. */
5272
+ startsAt: string;
5273
+ /** The booked slot end as an ISO 8601 datetime, derived from the resource slot duration. */
5274
+ endsAt: string;
5275
+ /** Number of guests on the reservation. */
5276
+ partySize: number;
5277
+ /** The guest name as submitted, echoed for the receipt. */
5278
+ guestName: string;
5279
+ /** The guest email as submitted, echoed for the receipt. */
5280
+ guestEmail: string;
5281
+ }
5282
+
5155
5283
  /**
5156
5284
  * Base request options available on every SDK method.
5157
5285
  * These override the defaults set in {@link LynkowConfig}.
@@ -6488,6 +6616,167 @@ declare class MediaHelperService {
6488
6616
  private parseImageUrl;
6489
6617
  }
6490
6618
 
6619
+ /**
6620
+ * Service for reading a site's published product catalogue.
6621
+ *
6622
+ * Accessible via `lynkow.products`. Returns only PUBLISHED products. Requires a
6623
+ * publishable key: pass `publishableKey` to `createClient(...)` so every request
6624
+ * carries it (commerce routes reject calls without a valid key). Responses are
6625
+ * cached in-memory for 5 minutes (SHORT TTL) when a cache adapter is configured
6626
+ * on the client.
6627
+ *
6628
+ * @example
6629
+ * ```typescript
6630
+ * const lynkow = createClient({ siteId: '...', publishableKey: 'lkw_pk_...' })
6631
+ *
6632
+ * // List published products
6633
+ * const { data, meta } = await lynkow.products.list({ limit: 12, kind: 'bookable' })
6634
+ *
6635
+ * // Read a single product by slug or `prod_` wire id
6636
+ * const product = await lynkow.products.getBySlug('sunset-dinner-cruise')
6637
+ * ```
6638
+ */
6639
+ declare class ProductsService extends BaseService {
6640
+ /**
6641
+ * Retrieves a paginated list of published products, sorted by creation date
6642
+ * (newest first by default). Cached for 5 minutes per unique filter combination.
6643
+ *
6644
+ * @param filters - Optional {@link ProductsFilters}: `page`/`limit`, `search`, `kind`, `sortBy`/`sortOrder`.
6645
+ * @param options - Base request options (locale override, custom fetch options).
6646
+ * @returns A {@link ProductsListResponse} with `data` (published {@link Product}[]) and `meta` (pagination info).
6647
+ * @throws {LynkowError} With code `'UNAUTHORIZED'` if no valid publishable key is set.
6648
+ *
6649
+ * @example
6650
+ * ```typescript
6651
+ * const { data, meta } = await lynkow.products.list({ page: 1, limit: 12, kind: 'bookable' })
6652
+ * ```
6653
+ */
6654
+ list(filters?: ProductsFilters, options?: BaseRequestOptions): Promise<ProductsListResponse>;
6655
+ /**
6656
+ * Retrieves a single published product by its `prod_...` wire id or its slug.
6657
+ * Cached for 5 minutes per id/slug.
6658
+ *
6659
+ * Named `getBySlug` (not `get`) to match the SDK convention: `BaseService`
6660
+ * reserves a protected `get()` that the shared caching path dispatches to, so a
6661
+ * public `get()` on a service would hijack it. Mirrors `contents.getBySlug` and
6662
+ * `reviews.getBySlug`, both of which also accept an id or a slug.
6663
+ *
6664
+ * @param idOrSlug - The product's `prod_...` wire id or its URL slug.
6665
+ * @param options - Base request options (locale override, custom fetch options).
6666
+ * @returns The {@link Product}.
6667
+ * @throws {LynkowError} With code `'NOT_FOUND'` if the product is missing, draft, or archived.
6668
+ *
6669
+ * @example
6670
+ * ```typescript
6671
+ * const product = await lynkow.products.getBySlug('sunset-dinner-cruise')
6672
+ * console.log(`${(product.priceCents / 100).toFixed(2)} ${product.currency}`)
6673
+ * ```
6674
+ */
6675
+ getBySlug(idOrSlug: string, options?: BaseRequestOptions): Promise<Product>;
6676
+ }
6677
+
6678
+ /**
6679
+ * Service for reading a bookable product's availability and creating guest
6680
+ * reservations. Accessible via `lynkow.reservations`.
6681
+ *
6682
+ * Requires a publishable key: pass `publishableKey` to `createClient(...)` so
6683
+ * every request carries it. Reservation routes reject calls without a valid key.
6684
+ * Payment is taken on-site: a successful booking is `confirmed` immediately,
6685
+ * never charged online. Anti-spam honeypot fields are injected automatically on
6686
+ * `bookings.create`; on reCAPTCHA-protected storefronts pass
6687
+ * `options.recaptchaToken`. Availability is not cached (it changes on every booking).
6688
+ *
6689
+ * @example
6690
+ * ```typescript
6691
+ * const lynkow = createClient({ siteId: '...', publishableKey: 'lkw_pk_...' })
6692
+ *
6693
+ * const { slots, timezone } = await lynkow.reservations.availability('sunset-dinner-cruise', {
6694
+ * from: '2026-07-10',
6695
+ * to: '2026-07-17',
6696
+ * })
6697
+ *
6698
+ * const booking = await lynkow.reservations.bookings.create('sunset-dinner-cruise', {
6699
+ * startsAt: slots[0].startsAt,
6700
+ * partySize: 2,
6701
+ * guestName: 'Alice Martin',
6702
+ * guestEmail: 'alice@example.com',
6703
+ * })
6704
+ * ```
6705
+ */
6706
+ declare class ReservationsService extends BaseService {
6707
+ /**
6708
+ * Client-creation timestamp anchoring the anti-spam timing window on
6709
+ * `bookings.create`. The server rejects a submission whose age (`Date.now()`
6710
+ * minus this value) is below its minimum fill time (too fast, likely a bot)
6711
+ * or above its maximum form lifetime (stale). Captured once at client
6712
+ * creation, so a very long-lived client eventually drifts past the maximum
6713
+ * window.
6714
+ */
6715
+ private sessionStartTime;
6716
+ constructor(config: InternalConfig);
6717
+ /** Nested booking-write surface: `lynkow.reservations.bookings.create(...)`. */
6718
+ readonly bookings: {
6719
+ create: (productIdOrSlug: string, data: BookingCreateData, options?: SubmitOptions & BaseRequestOptions) => Promise<Booking>;
6720
+ };
6721
+ /**
6722
+ * Retrieves the computed open slots for a bookable product across a date range.
6723
+ * Not cached: availability changes as other buyers book.
6724
+ *
6725
+ * @param productIdOrSlug - The bookable product's `prod_...` wire id or its slug.
6726
+ * @param filters - {@link AvailabilityFilters}: `from` and `to` (calendar dates `YYYY-MM-DD`, required, `to` not before `from`) and an optional `partySize`.
6727
+ * @returns An {@link AvailabilityResponse} with `slots` (chronological {@link AvailabilitySlot}[]), the display `timezone`, and the effective `window`.
6728
+ * @throws {LynkowError} With code `'NOT_FOUND'` if the product is missing or not bookable; `'UNAUTHORIZED'` if no valid publishable key is set.
6729
+ *
6730
+ * @example
6731
+ * ```typescript
6732
+ * const { slots, timezone } = await lynkow.reservations.availability('sunset-dinner-cruise', {
6733
+ * from: '2026-07-10',
6734
+ * to: '2026-07-17',
6735
+ * partySize: 2,
6736
+ * })
6737
+ * ```
6738
+ */
6739
+ availability(productIdOrSlug: string, filters: AvailabilityFilters): Promise<AvailabilityResponse>;
6740
+ /**
6741
+ * Creates a guest reservation for a chosen slot. No account required. Tuned
6742
+ * for the in-browser guest flow: the client is created around page load and
6743
+ * the buyer books moments later.
6744
+ *
6745
+ * Anti-spam honeypot + timestamp fields are injected automatically. The
6746
+ * honeypot is always empty, so the honeypot/content silent-acknowledgement
6747
+ * path (HTTP 200, no error) is unreachable through the SDK. The timestamp
6748
+ * check, however, is a real thrown-error window relative to client creation:
6749
+ * a booking sent sooner than the server's minimum fill time (default 3s)
6750
+ * after `createClient(...)` is rejected `TOO_MANY_REQUESTS` (HTTP 429), and
6751
+ * one sent later than the server's maximum form lifetime (default ~1h) is
6752
+ * rejected `BAD_REQUEST` (HTTP 400, "form expired"). Handle both when driving
6753
+ * this from a long-lived or non-browser client.
6754
+ *
6755
+ * If the storefront enforces reCAPTCHA (rather than the default honeypot),
6756
+ * pass `options.recaptchaToken`; without it the server rejects the booking
6757
+ * `BAD_REQUEST` (HTTP 400, "reCAPTCHA required"). Mirrors `reviews.submit`.
6758
+ *
6759
+ * @param productIdOrSlug - The bookable product's `prod_...` wire id or its slug.
6760
+ * @param data - {@link BookingCreateData}: chosen `startsAt`, `partySize`, and guest `guestName`/`guestEmail`/optional `guestPhone`.
6761
+ * @param options - Optional {@link SubmitOptions} + request options: `recaptchaToken` (required on reCAPTCHA-protected storefronts), a `locale` override, and `fetchOptions` (e.g. an `AbortSignal`).
6762
+ * @returns The created {@link Booking} (reference, status, slot instants, party size, echoed name/email).
6763
+ * @throws {LynkowError} With code `'VALIDATION_ERROR'` (HTTP 422) on bad input or a filled/unavailable slot; `'NOT_FOUND'` if not a bookable product; `'UNAUTHORIZED'` if no valid publishable key is set; `'TOO_MANY_REQUESTS'` (HTTP 429) if sent within the server's minimum fill time after client creation (anti-spam too-fast); `'BAD_REQUEST'` (HTTP 400) if sent past the server's maximum form lifetime after client creation (anti-spam expired) or if reCAPTCHA is enforced and no `recaptchaToken` is supplied.
6764
+ *
6765
+ * @example
6766
+ * ```typescript
6767
+ * const booking = await lynkow.reservations.bookings.create('sunset-dinner-cruise', {
6768
+ * startsAt: '2026-07-10T18:00:00.000Z',
6769
+ * partySize: 2,
6770
+ * guestName: 'Alice Martin',
6771
+ * guestEmail: 'alice@example.com',
6772
+ * guestPhone: '+33 6 12 34 56 78',
6773
+ * })
6774
+ * console.log(`Reservation ${booking.reference} is ${booking.status}. Pay on-site.`)
6775
+ * ```
6776
+ */
6777
+ private createBooking;
6778
+ }
6779
+
6491
6780
  /**
6492
6781
  * Lynkow SDK Client
6493
6782
  * Main entry point for the SDK
@@ -6598,6 +6887,18 @@ interface Client extends LynkowClient {
6598
6887
  * Lynkow Instant Search service
6599
6888
  */
6600
6889
  search: SearchService;
6890
+ /**
6891
+ * Storefront product catalogue service (commerce).
6892
+ * Provides `list()` and `getBySlug()` for published products.
6893
+ * Requires a `publishableKey` on the client.
6894
+ */
6895
+ products: ProductsService;
6896
+ /**
6897
+ * Storefront reservations service (commerce).
6898
+ * Provides `availability()` and the nested `bookings.create()` for bookable products.
6899
+ * Requires a `publishableKey` on the client.
6900
+ */
6901
+ reservations: ReservationsService;
6601
6902
  }
6602
6903
  /**
6603
6904
  * Creates a Lynkow client instance (SDK v3)