@behio/storefront-sdk 0.42.0 → 1.1.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.
@@ -566,8 +566,7 @@ var CatalogModule = class {
566
566
  if (query.inStock !== void 0) q.inStock = query.inStock;
567
567
  if (query.ratingMin !== void 0) q.ratingMin = query.ratingMin;
568
568
  if (query.search) q.search = query.search;
569
- if (query.customFields)
570
- q.customFields = JSON.stringify(query.customFields);
569
+ if (query.parameters) q.parameters = JSON.stringify(query.parameters);
571
570
  if (query.facets) q.facets = JSON.stringify(query.facets);
572
571
  if (query.ids && query.ids.length > 0) q.ids = query.ids;
573
572
  if (query.slugs && query.slugs.length > 0) q.slugs = query.slugs;
@@ -659,18 +658,52 @@ var CatalogModule = class {
659
658
  }
660
659
  );
661
660
  }
662
- /** Get available filter fields for dynamic filter UI */
663
- async getFilters() {
661
+ /**
662
+ * Available filters for a dynamic filter UI.
663
+ *
664
+ * Derived from curated PARAMETERS the merchant marked filterable, so a
665
+ * visitor can never filter by something that does not appear in the
666
+ * product's parameters. Labels are per language, hence `locale`.
667
+ */
668
+ async getFilters(options) {
669
+ return this.client.request(
670
+ "GET",
671
+ "/catalog/filters",
672
+ { query: { locale: _optionalChain([options, 'optionalAccess', _25 => _25.locale]) } }
673
+ );
674
+ }
675
+ /**
676
+ * Curated parameter groups of a product, already resolved (label, value,
677
+ * unit, order). Returns an ARRAY of groups so a template can lay them out
678
+ * however it likes: one group as a spec table, another as badges.
679
+ *
680
+ * A variant's own parameters ride along on `ProductDetail.variants[]`, so
681
+ * this call is for the parent product.
682
+ */
683
+ async getProductParameters(slug, options) {
684
+ return this.client.request(
685
+ "GET",
686
+ `/catalog/products/${slug}/parameters`,
687
+ { query: { locale: _optionalChain([options, 'optionalAccess', _26 => _26.locale]) } }
688
+ );
689
+ }
690
+ /**
691
+ * One specific parameter group of a product, by its slug. 404 when the
692
+ * product does not have that group, which is deliberate: the caller asked
693
+ * for a named thing, so an empty array would hide a wrong slug.
694
+ */
695
+ async getProductParameterGroup(slug, groupSlug, options) {
664
696
  return this.client.request(
665
697
  "GET",
666
- "/catalog/filters"
698
+ `/catalog/products/${slug}/parameters/${groupSlug}`,
699
+ { query: { locale: _optionalChain([options, 'optionalAccess', _27 => _27.locale]) } }
667
700
  );
668
701
  }
669
702
  /**
670
- * Facet groups + selection-aware counts for the current filter set (custom
671
- * fields, labels, price, availability, rating, subcategories). Pass the SAME
672
- * query you pass to `getProducts` (category, search, price, inStock, ratingMin,
673
- * customFields, facets slugs, labels): counts for each facet are computed with
703
+ * Facet groups + selection-aware counts for the current filter set
704
+ * (parameters, labels, price, availability, rating, subcategories). Pass the
705
+ * SAME query you pass to `getProducts` (category, search, price, inStock,
706
+ * ratingMin, parameters, facets slugs, labels): counts are computed with
674
707
  * that facet excluded, and values that drop to 0 are still returned (render
675
708
  * them disabled). Use this to build an Alza-style filter sidebar.
676
709
  */
@@ -686,8 +719,7 @@ var CatalogModule = class {
686
719
  if (query.inStock !== void 0) q.inStock = query.inStock;
687
720
  if (query.ratingMin !== void 0) q.ratingMin = query.ratingMin;
688
721
  if (query.search) q.search = query.search;
689
- if (query.customFields)
690
- q.customFields = JSON.stringify(query.customFields);
722
+ if (query.parameters) q.parameters = JSON.stringify(query.parameters);
691
723
  if (query.facets) q.facets = JSON.stringify(query.facets);
692
724
  if (query.labels && query.labels.length > 0) q.labels = query.labels;
693
725
  if (query.categories && query.categories.length > 0)
@@ -722,7 +754,7 @@ var CatalogModule = class {
722
754
  "GET",
723
755
  `/catalog/product-groups/${encodeURIComponent(slug)}`,
724
756
  {
725
- query: { locale: _optionalChain([options, 'optionalAccess', _25 => _25.locale]), currency: _optionalChain([options, 'optionalAccess', _26 => _26.currency]) }
757
+ query: { locale: _optionalChain([options, 'optionalAccess', _28 => _28.locale]), currency: _optionalChain([options, 'optionalAccess', _29 => _29.currency]) }
726
758
  }
727
759
  );
728
760
  }
@@ -737,7 +769,7 @@ var CatalogModule = class {
737
769
  return this.client.request(
738
770
  "GET",
739
771
  `/catalog/products/${encodeURIComponent(productSlug)}/cross-sell`,
740
- { query: { locale: _optionalChain([options, 'optionalAccess', _27 => _27.locale]), currency: _optionalChain([options, 'optionalAccess', _28 => _28.currency]) } }
772
+ { query: { locale: _optionalChain([options, 'optionalAccess', _30 => _30.locale]), currency: _optionalChain([options, 'optionalAccess', _31 => _31.currency]) } }
741
773
  );
742
774
  }
743
775
  /** Active promotions applicable to a product (with countdown end time) */
@@ -777,7 +809,7 @@ var CatalogModule = class {
777
809
  /** List configured payment methods (filtered by currency). */
778
810
  async listPaymentMethods(opts) {
779
811
  const query = {};
780
- if (_optionalChain([opts, 'optionalAccess', _29 => _29.currency])) query.currency = opts.currency;
812
+ if (_optionalChain([opts, 'optionalAccess', _32 => _32.currency])) query.currency = opts.currency;
781
813
  return this.client.request(
782
814
  "GET",
783
815
  "/catalog/payment-methods",
@@ -1071,7 +1103,7 @@ var OrdersModule = class {
1071
1103
  "GET",
1072
1104
  "/orders",
1073
1105
  {
1074
- query: { page: _optionalChain([options, 'optionalAccess', _30 => _30.page]), limit: _optionalChain([options, 'optionalAccess', _31 => _31.limit]) }
1106
+ query: { page: _optionalChain([options, 'optionalAccess', _33 => _33.page]), limit: _optionalChain([options, 'optionalAccess', _34 => _34.limit]) }
1075
1107
  }
1076
1108
  );
1077
1109
  }
@@ -1566,7 +1598,7 @@ var ConsentModule = class {
1566
1598
  }
1567
1599
  if (result.error) return { data: null, error: result.error };
1568
1600
  return {
1569
- data: _optionalChain([result, 'access', _32 => _32.data, 'optionalAccess', _33 => _33.consented]) ? result.data.consent : null,
1601
+ data: _optionalChain([result, 'access', _35 => _35.data, 'optionalAccess', _36 => _36.consented]) ? result.data.consent : null,
1570
1602
  error: null
1571
1603
  };
1572
1604
  }
@@ -1653,10 +1685,10 @@ var ShippingModule = class {
1653
1685
  */
1654
1686
  async listMethods(opts) {
1655
1687
  const query = {};
1656
- if (_optionalChain([opts, 'optionalAccess', _34 => _34.currency])) query.currency = opts.currency;
1657
- if (_optionalChain([opts, 'optionalAccess', _35 => _35.country])) query.country = opts.country;
1658
- if (_optionalChain([opts, 'optionalAccess', _36 => _36.cartTotal]) != null) query.cartTotal = String(opts.cartTotal);
1659
- if (_optionalChain([opts, 'optionalAccess', _37 => _37.cartWeightKg]) != null)
1688
+ if (_optionalChain([opts, 'optionalAccess', _37 => _37.currency])) query.currency = opts.currency;
1689
+ if (_optionalChain([opts, 'optionalAccess', _38 => _38.country])) query.country = opts.country;
1690
+ if (_optionalChain([opts, 'optionalAccess', _39 => _39.cartTotal]) != null) query.cartTotal = String(opts.cartTotal);
1691
+ if (_optionalChain([opts, 'optionalAccess', _40 => _40.cartWeightKg]) != null)
1660
1692
  query.cartWeightKg = String(opts.cartWeightKg);
1661
1693
  return this.client.request(
1662
1694
  "GET",
@@ -566,8 +566,7 @@ var CatalogModule = class {
566
566
  if (query.inStock !== void 0) q.inStock = query.inStock;
567
567
  if (query.ratingMin !== void 0) q.ratingMin = query.ratingMin;
568
568
  if (query.search) q.search = query.search;
569
- if (query.customFields)
570
- q.customFields = JSON.stringify(query.customFields);
569
+ if (query.parameters) q.parameters = JSON.stringify(query.parameters);
571
570
  if (query.facets) q.facets = JSON.stringify(query.facets);
572
571
  if (query.ids && query.ids.length > 0) q.ids = query.ids;
573
572
  if (query.slugs && query.slugs.length > 0) q.slugs = query.slugs;
@@ -659,18 +658,52 @@ var CatalogModule = class {
659
658
  }
660
659
  );
661
660
  }
662
- /** Get available filter fields for dynamic filter UI */
663
- async getFilters() {
661
+ /**
662
+ * Available filters for a dynamic filter UI.
663
+ *
664
+ * Derived from curated PARAMETERS the merchant marked filterable, so a
665
+ * visitor can never filter by something that does not appear in the
666
+ * product's parameters. Labels are per language, hence `locale`.
667
+ */
668
+ async getFilters(options) {
669
+ return this.client.request(
670
+ "GET",
671
+ "/catalog/filters",
672
+ { query: { locale: options?.locale } }
673
+ );
674
+ }
675
+ /**
676
+ * Curated parameter groups of a product, already resolved (label, value,
677
+ * unit, order). Returns an ARRAY of groups so a template can lay them out
678
+ * however it likes: one group as a spec table, another as badges.
679
+ *
680
+ * A variant's own parameters ride along on `ProductDetail.variants[]`, so
681
+ * this call is for the parent product.
682
+ */
683
+ async getProductParameters(slug, options) {
684
+ return this.client.request(
685
+ "GET",
686
+ `/catalog/products/${slug}/parameters`,
687
+ { query: { locale: options?.locale } }
688
+ );
689
+ }
690
+ /**
691
+ * One specific parameter group of a product, by its slug. 404 when the
692
+ * product does not have that group, which is deliberate: the caller asked
693
+ * for a named thing, so an empty array would hide a wrong slug.
694
+ */
695
+ async getProductParameterGroup(slug, groupSlug, options) {
664
696
  return this.client.request(
665
697
  "GET",
666
- "/catalog/filters"
698
+ `/catalog/products/${slug}/parameters/${groupSlug}`,
699
+ { query: { locale: options?.locale } }
667
700
  );
668
701
  }
669
702
  /**
670
- * Facet groups + selection-aware counts for the current filter set (custom
671
- * fields, labels, price, availability, rating, subcategories). Pass the SAME
672
- * query you pass to `getProducts` (category, search, price, inStock, ratingMin,
673
- * customFields, facets slugs, labels): counts for each facet are computed with
703
+ * Facet groups + selection-aware counts for the current filter set
704
+ * (parameters, labels, price, availability, rating, subcategories). Pass the
705
+ * SAME query you pass to `getProducts` (category, search, price, inStock,
706
+ * ratingMin, parameters, facets slugs, labels): counts are computed with
674
707
  * that facet excluded, and values that drop to 0 are still returned (render
675
708
  * them disabled). Use this to build an Alza-style filter sidebar.
676
709
  */
@@ -686,8 +719,7 @@ var CatalogModule = class {
686
719
  if (query.inStock !== void 0) q.inStock = query.inStock;
687
720
  if (query.ratingMin !== void 0) q.ratingMin = query.ratingMin;
688
721
  if (query.search) q.search = query.search;
689
- if (query.customFields)
690
- q.customFields = JSON.stringify(query.customFields);
722
+ if (query.parameters) q.parameters = JSON.stringify(query.parameters);
691
723
  if (query.facets) q.facets = JSON.stringify(query.facets);
692
724
  if (query.labels && query.labels.length > 0) q.labels = query.labels;
693
725
  if (query.categories && query.categories.length > 0)
@@ -271,7 +271,55 @@ interface ProductVariant {
271
271
  */
272
272
  id: string;
273
273
  sku: string;
274
+ /**
275
+ * Variant name in the requested locale. Before SDK 1.1.0 this was always the
276
+ * warehouse item name, so translated shops showed one language to everyone.
277
+ */
274
278
  name: string;
279
+ /**
280
+ * Deep-link token for this variant — NOT a URL of its own.
281
+ *
282
+ * A variant has no standalone product page: the catalog 404s its slug and
283
+ * every listing excludes it, because a variant is bought from the parent's
284
+ * detail page. Link to `/product/{product.slug}?variant={variant.variantSlug}`
285
+ * and preselect the variant from that query parameter.
286
+ *
287
+ * Added in SDK 1.1.0.
288
+ */
289
+ variantSlug: string;
290
+ /**
291
+ * Short description of THIS variant, or `null` when the merchant left it
292
+ * empty. `null` means INHERIT: fall back to `ProductDetail.shortDescription`
293
+ * instead of rendering an empty block. Sanitised HTML.
294
+ *
295
+ * Added in SDK 1.1.0.
296
+ */
297
+ shortDescription?: string | null;
298
+ /** Long description of THIS variant. Same inherit-on-null contract as
299
+ * `shortDescription`. Added in SDK 1.1.0. */
300
+ longDescription?: string | null;
301
+ /**
302
+ * Gallery of THIS variant, ordered. Empty means the variant has no photos of
303
+ * its own, so keep showing the parent's gallery.
304
+ *
305
+ * Added in SDK 1.1.0.
306
+ */
307
+ images: ProductDetail["images"];
308
+ /**
309
+ * Per-variant SEO/OG overrides, or `null` when the merchant wrote none. The
310
+ * canonical URL stays the parent's, so use these only when a variant is
311
+ * preselected via `?variant=`.
312
+ *
313
+ * Added in SDK 1.1.0.
314
+ */
315
+ seo?: {
316
+ title?: string | null;
317
+ description?: string | null;
318
+ keywords?: string | null;
319
+ ogTitle?: string | null;
320
+ ogDescription?: string | null;
321
+ ogImage?: string | null;
322
+ } | null;
275
323
  /**
276
324
  * Axis name/value pairs identifying this variant (e.g.
277
325
  * `[{name: 'Barva', value: 'červená'}]`) — matches the wire shape the API
@@ -300,6 +348,14 @@ interface ProductVariant {
300
348
  * "default photo" or to render the picture in a subtler style.
301
349
  */
302
350
  imageIsInherited: boolean;
351
+ /**
352
+ * Parameters of this variant. A variant carries its own value where it has
353
+ * one and inherits the parent's everywhere else, so you can render the rows
354
+ * that actually differ under each variant. Empty when nothing is assigned.
355
+ *
356
+ * Added in SDK 1.0.0.
357
+ */
358
+ parameterGroups: ProductParameterGroup[];
303
359
  }
304
360
  interface ProductLabel {
305
361
  id: string;
@@ -513,25 +569,41 @@ interface VariantAxis {
513
569
  values: VariantAxisValue[];
514
570
  }
515
571
  /**
516
- * One custom-field (data-group value) rendered as a spec-table row. BOOLEAN
517
- * carries a typed `booleanValue` (value is null) so the storefront can localize
518
- * Ano/Ne; MONEY carries its currency in `unit`; PERCENTAGE carries "%" in
519
- * `unit`.
572
+ * One row of a curated parameter group.
573
+ *
574
+ * A parameter is something the merchant explicitly published: a label they
575
+ * wrote, a value resolved from a fixed string, a product field, or ONE named
576
+ * field of one warehouse data group. Nothing here reveals warehouse structure:
577
+ * no ids, no field keys, no internal types.
578
+ *
579
+ * `value` is null only for boolean parameters, where `booleanValue` carries the
580
+ * typed value so the storefront localizes Ano/Ne itself. A parameter with no
581
+ * value is omitted from the array rather than rendered as an empty row.
520
582
  */
521
- interface ProductCustomField {
522
- key: string;
523
- name: string;
524
- /** TEXT | NUMBER | DECIMAL | BOOLEAN | DATE | TIME | DATETIME | PERCENTAGE | MONEY | ITEM_LIST | ... */
525
- type: string;
583
+ interface ProductParameter {
584
+ label: string;
526
585
  value: string | null;
527
586
  booleanValue: boolean | null;
587
+ /** "cm", "g", a currency code, "%"; null when the parameter has none. */
528
588
  unit: string | null;
529
589
  }
530
- /** A spec-table section (one inventory data group) with its fields. */
531
- interface ProductCustomFieldGroup {
532
- key: string;
590
+ /**
591
+ * One curated parameter group. A product can carry several, so a template can
592
+ * render one as a spec table and another as badges. Ordering is array order,
593
+ * both for the groups and for the parameters inside them.
594
+ */
595
+ interface ProductParameterGroup {
596
+ /**
597
+ * Stable public identifier derived from the merchant's own group name
598
+ * ("Parametry oblečení" -> "parametry-obleceni"). Pass it to
599
+ * `catalog.getProductParameterGroup` to fetch just this group.
600
+ */
601
+ slug: string;
533
602
  name: string;
534
- fields: ProductCustomField[];
603
+ parameters: ProductParameter[];
604
+ }
605
+ interface ProductParametersResponse {
606
+ groups: ProductParameterGroup[];
535
607
  }
536
608
  interface ProductDetail extends ProductListItem {
537
609
  longDescription?: string;
@@ -561,14 +633,15 @@ interface ProductDetail extends ProductListItem {
561
633
  variantAxes: VariantAxis[];
562
634
  volumePricing: ProductVolumePrice[];
563
635
  /**
564
- * Structured product parameters from custom fields (inventory data groups),
565
- * grouped into spec-table sections (GAP-12). Empty when the product has no
566
- * data-group values. Distinct from `longDescription` (free HTML): this is
567
- * machine-readable key/value data for a "Parametry" table + comparison
568
- * engines. (Corrected from the old untyped `Record<string, unknown>` — the
569
- * API never populated that; it now sends this structured shape.)
636
+ * Curated parameter groups, already resolved. Empty when the merchant
637
+ * assigned none. Distinct from `longDescription` (free HTML): this is
638
+ * machine-readable key/value data for a "Parametry" table, comparison
639
+ * engines and AEO.
640
+ *
641
+ * Replaced `customFields` in SDK 1.0.0. The old field returned raw warehouse
642
+ * data groups, which published internal bookkeeping nobody curated.
570
643
  */
571
- customFields: ProductCustomFieldGroup[];
644
+ parameterGroups: ProductParameterGroup[];
572
645
  seo: {
573
646
  title?: string | null;
574
647
  description?: string | null;
@@ -675,13 +748,22 @@ interface CategoryDetail extends Category {
675
748
  ogImage?: string | null;
676
749
  };
677
750
  }
678
- type DataGroupFieldType = "TEXT" | "NUMBER" | "DECIMAL" | "BOOLEAN" | "DATE" | "TIME" | "DATETIME" | "PERCENTAGE" | "MONEY" | "ASSET" | "ITEM_LIST" | "DYNAMIC_NUMBER_CALCULATION_FROM_OTHERS";
751
+ /**
752
+ * One available filter, derived from a curated parameter the merchant marked
753
+ * filterable. A visitor can therefore never filter by a field that does not
754
+ * appear in the product's parameters.
755
+ */
679
756
  interface FilterField {
757
+ /** Parameter slug. Pass it back in `ProductsQuery.parameters` or `facets`. */
680
758
  key: string;
759
+ /** Parameter label in the requested language. */
681
760
  name: string;
682
- type: DataGroupFieldType | string;
683
- groupKey: string;
761
+ /** How to render it: value list, numeric range, or yes/no. */
762
+ type: "enum" | "range" | "boolean" | string;
763
+ /** Slug of the parameter group this filter belongs to. */
764
+ groupSlug: string;
684
765
  groupName: string;
766
+ unit?: string | null;
685
767
  values?: string[];
686
768
  }
687
769
  interface FacetValue {
@@ -701,14 +783,14 @@ interface FacetRange {
701
783
  max: number | null;
702
784
  }
703
785
  interface Facet {
786
+ /** Parameter slug. Never a warehouse field key. */
704
787
  key: string;
705
788
  name: string;
706
789
  /** "enum" (checkboxes), "range" (slider) or "boolean". */
707
790
  type: "enum" | "range" | "boolean" | string;
708
- groupKey: string;
791
+ /** Slug of the parameter group this facet belongs to. */
792
+ groupSlug: string;
709
793
  groupName: string;
710
- /** Underlying data-group field type (TEXT, NUMBER, MONEY, ...). */
711
- fieldType: string;
712
794
  /** enum/boolean facets: selectable values with counts. */
713
795
  values?: FacetValue[];
714
796
  /** range facets: numeric bounds within the current context. */
@@ -803,11 +885,17 @@ interface ProductsQuery {
803
885
  /** Minimum aggregate rating, e.g. 4 for "4 and up". */
804
886
  ratingMin?: number;
805
887
  search?: string;
806
- /** Custom-field filters. A value may be an array = multi-select (OR within
807
- * the key), e.g. {"barva": ["cerna", "bila"]}. */
808
- customFields?: Record<string, string | number | boolean | string[] | unknown>;
809
- /** Slug-based facet selection for SEO URLs: facet key -> value slugs, e.g.
810
- * {"barva": ["cerna"]}. Resolved server-side to the underlying values. */
888
+ /**
889
+ * Parameter filters, keyed by PARAMETER SLUG. A value may be an array =
890
+ * multi-select (OR within the key), e.g. {"barva": ["cerna", "bila"]}.
891
+ * Range filters use the `_min` / `_max` suffix, e.g. {"hmotnost_min": 100}.
892
+ *
893
+ * Replaced `customFields` in SDK 1.0.0, which was keyed by a warehouse
894
+ * data-group field key.
895
+ */
896
+ parameters?: Record<string, string | number | boolean | string[] | unknown>;
897
+ /** Slug-based facet selection for SEO URLs: parameter slug -> value slugs,
898
+ * e.g. {"barva": ["cerna"]}. Resolved server-side to the stored values. */
811
899
  facets?: Record<string, string[]>;
812
900
  /** Filter by specific product IDs (comma-separated in URL) */
813
901
  ids?: string[];
@@ -852,7 +940,22 @@ interface LoginInput {
852
940
  password: string;
853
941
  }
854
942
  interface CartItemProduct {
943
+ /**
944
+ * Slug of the page this line links to. For a variant line this is the
945
+ * PARENT's slug: a variant has no page of its own, so linking to its own slug
946
+ * landed customers on a 404 (fixed 2026-08-03, SDK 1.1.0).
947
+ */
855
948
  slug: string;
949
+ /**
950
+ * Deep-link token of the variant on this line, `null` for a plain product.
951
+ * Build the link as `/product/{slug}?variant={variantSlug}` so the customer
952
+ * returns to the exact variant sitting in their cart.
953
+ *
954
+ * Added in SDK 1.1.0.
955
+ */
956
+ variantSlug?: string | null;
957
+ /** Product name in the CART's language. Before SDK 1.1.0 the API picked an
958
+ * arbitrary translation row, so this could come back in another language. */
856
959
  name: string;
857
960
  sku: string;
858
961
  imageUrl?: string;
@@ -1146,7 +1249,10 @@ interface DigitalDownload {
1146
1249
  fileName: string;
1147
1250
  /** Localized product name the file belongs to (may be null). */
1148
1251
  productName: string | null;
1149
- /** Product slug for linking back to the PDP (may be null). */
1252
+ /**
1253
+ * Product slug for linking back to the PDP (may be null). Resolved the same
1254
+ * way as everywhere else: per-locale slug first, then the product id.
1255
+ */
1150
1256
  productSlug: string | null;
1151
1257
  fileSize: number;
1152
1258
  mimeType: string;
@@ -1168,7 +1274,10 @@ interface CourseListItem {
1168
1274
  courseId: string;
1169
1275
  /** Localized course (product) name, best-effort. */
1170
1276
  name: string | null;
1171
- /** Product slug for linking to the PDP. */
1277
+ /**
1278
+ * Product slug for linking to the PDP. Resolved the same way as in the
1279
+ * catalog: per-locale slug first, then the product id.
1280
+ */
1172
1281
  slug: string;
1173
1282
  imageUrl: string | null;
1174
1283
  totalLessons: number;
@@ -1220,6 +1329,7 @@ interface CourseModule {
1220
1329
  interface CourseDetail {
1221
1330
  courseId: string;
1222
1331
  name: string | null;
1332
+ /** Product slug for linking to the PDP (resolved per-locale slug, else id). */
1223
1333
  slug: string;
1224
1334
  imageUrl: string | null;
1225
1335
  /** Welcome text shown at the top of the member area (markdown). */
@@ -1572,15 +1682,17 @@ interface Bundle {
1572
1682
  slug: string;
1573
1683
  name: string;
1574
1684
  description: string | null;
1575
- bundlePrice: number;
1685
+ /** `null` when the eshop hides prices from guests and this visitor has no price entitlement. */
1686
+ bundlePrice: number | null;
1576
1687
  currency: string;
1577
1688
  coverImage: string | null;
1578
1689
  endsAt: number | null;
1579
- itemsSum: number;
1580
- /** Absolute saving vs buying the components separately, in `currency`. */
1581
- savings: number;
1582
- /** Percentage saving, 0–100. 0 when `itemsSum` is zero. */
1583
- savingsPercent: number;
1690
+ /** `null` when prices are hidden (see `bundlePrice`). */
1691
+ itemsSum: number | null;
1692
+ /** Absolute saving vs buying the components separately, in `currency`. `null` when prices are hidden. */
1693
+ savings: number | null;
1694
+ /** Percentage saving, 0–100. 0 when `itemsSum` is zero. `null` when prices are hidden. */
1695
+ savingsPercent: number | null;
1584
1696
  /** Minimum bundles per order. Default 1. */
1585
1697
  minQuantity: number;
1586
1698
  /** Maximum bundles per order. `null` = uncapped. */
@@ -2284,15 +2396,42 @@ declare class CatalogModule {
2284
2396
  locale?: string;
2285
2397
  currency?: string;
2286
2398
  }): Promise<SdkResult<PaginatedResponse<ProductListItem>>>;
2287
- /** Get available filter fields for dynamic filter UI */
2288
- getFilters(): Promise<SdkResult<{
2399
+ /**
2400
+ * Available filters for a dynamic filter UI.
2401
+ *
2402
+ * Derived from curated PARAMETERS the merchant marked filterable, so a
2403
+ * visitor can never filter by something that does not appear in the
2404
+ * product's parameters. Labels are per language, hence `locale`.
2405
+ */
2406
+ getFilters(options?: {
2407
+ locale?: string;
2408
+ }): Promise<SdkResult<{
2289
2409
  filters: FilterField[];
2290
2410
  }>>;
2291
2411
  /**
2292
- * Facet groups + selection-aware counts for the current filter set (custom
2293
- * fields, labels, price, availability, rating, subcategories). Pass the SAME
2294
- * query you pass to `getProducts` (category, search, price, inStock, ratingMin,
2295
- * customFields, facets slugs, labels): counts for each facet are computed with
2412
+ * Curated parameter groups of a product, already resolved (label, value,
2413
+ * unit, order). Returns an ARRAY of groups so a template can lay them out
2414
+ * however it likes: one group as a spec table, another as badges.
2415
+ *
2416
+ * A variant's own parameters ride along on `ProductDetail.variants[]`, so
2417
+ * this call is for the parent product.
2418
+ */
2419
+ getProductParameters(slug: string, options?: {
2420
+ locale?: string;
2421
+ }): Promise<SdkResult<ProductParametersResponse>>;
2422
+ /**
2423
+ * One specific parameter group of a product, by its slug. 404 when the
2424
+ * product does not have that group, which is deliberate: the caller asked
2425
+ * for a named thing, so an empty array would hide a wrong slug.
2426
+ */
2427
+ getProductParameterGroup(slug: string, groupSlug: string, options?: {
2428
+ locale?: string;
2429
+ }): Promise<SdkResult<ProductParameterGroup>>;
2430
+ /**
2431
+ * Facet groups + selection-aware counts for the current filter set
2432
+ * (parameters, labels, price, availability, rating, subcategories). Pass the
2433
+ * SAME query you pass to `getProducts` (category, search, price, inStock,
2434
+ * ratingMin, parameters, facets slugs, labels): counts are computed with
2296
2435
  * that facet excluded, and values that drop to 0 are still returned (render
2297
2436
  * them disabled). Use this to build an Alza-style filter sidebar.
2298
2437
  */
@@ -2794,4 +2933,4 @@ declare class NewsletterModule {
2794
2933
  unsubscribe(email: string): Promise<SdkResult<NewsletterUnsubscribeResult>>;
2795
2934
  }
2796
2935
 
2797
- export { type DownloadUrl as $, type ActivePromotion as A, BehioStorefront as B, type CookieConsent as C, type CheckoutAddress as D, type CheckoutInput as E, type CheckoutPaymentMethod as F, type CheckoutSettings as G, type CookieConsentInput as H, type CourseAttachment as I, type CourseCertificate as J, type CourseComment as K, type CourseCommentReply as L, type CourseCommentsList as M, type CourseDetail as N, type CourseLesson as O, type CourseListItem as P, type CourseModule as Q, type CoursePostedComment as R, type SdkResult as S, type CourseProgress as T, type CourseTutorMessage as U, type CourseTutorThread as V, type CrossSellItem as W, type CustomerAddress as X, type CustomerProfile as Y, type DataGroupFieldType as Z, type DigitalDownload as _, type AddToCartInput as a, type ProductPrice as a$, type Facet as a0, type FacetAvailability as a1, type FacetCategory as a2, type FacetLabel as a3, type FacetPriceRange as a4, type FacetRange as a5, type FacetRatingBucket as a6, type FacetValue as a7, type FacetsResponse as a8, type FilterField as a9, type OrderAccessVerifyResponse as aA, type OrderDetail as aB, type OrderItem as aC, type OrderListItem as aD, type OrderStatus as aE, type OrderStatusHistory as aF, OrderStatuses as aG, type OrderTracking as aH, type Page as aI, type PageAttachment as aJ, type PageDetail as aK, type PaginatedResponse as aL, type PaymentStatus as aM, PaymentStatuses as aN, type PickupPoint as aO, type PickupPointHours as aP, type PickupPointsInput as aQ, type PriceDisplay as aR, type ProductAvailability as aS, type ProductCustomField as aT, type ProductCustomFieldGroup as aU, type ProductDetail as aV, type ProductGroup as aW, type ProductLabel as aX, type ProductListItem as aY, type ProductMedia as aZ, type ProductMediaVariant as a_, type FulfillmentStatus as aa, FulfillmentStatuses as ab, type GiftCardBalance as ac, type GiftCardPurchaseInput as ad, type GiftCardPurchaseResult as ae, type GiftCardSummary as af, type LessonNote as ag, type LessonQuiz as ah, type LoginInput as ai, type LoyaltyBalance as aj, type LoyaltyNextTier as ak, type LoyaltyProgram as al, type LoyaltySummary as am, type LoyaltyTier as an, type LoyaltyTierPerks as ao, type LoyaltyTransaction as ap, type Menu as aq, type MenuItem as ar, type MenuItemRef as as, type MenuItemType as at, type MessageResponse as au, type NewsletterOptInDefault as av, type NewsletterSubscribeInput as aw, type NewsletterSubscribeResult as ax, type NewsletterUnsubscribeResult as ay, type OrderAccessRequestResponse as az, type AddressDetail as b, type ProductPromotionSummary as b0, type ProductReview as b1, type ProductReviewsResponse as b2, ProductSort as b3, type ProductSortValue as b4, type ProductVariant as b5, type ProductVolumePrice as b6, type ProductsQuery as b7, type QuizAnswerInput as b8, type QuizAnswerResult as b9, type ShopSeoIdentity as bA, type StockBehavior as bB, type StockMode as bC, type SubmitQuoteInput as bD, type SubmitReturnInput as bE, type SubmitReviewInput as bF, type Subscription as bG, type SubscriptionAction as bH, type SubscriptionFrequency as bI, type SubscriptionItem as bJ, type SubscriptionStatus as bK, type TaxBreakdownLine as bL, type VariantAxis as bM, type VariantAxisValue as bN, type WishlistItem as bO, err as bP, ok as bQ, toSdkError as bR, type QuizQuestion as ba, type QuizResult as bb, type QuoteItem as bc, type QuoteRequest as bd, type RegisterInput as be, type RegisterResult as bf, type RequestInterceptor as bg, type RequestInterceptorConfig as bh, type ResponseInterceptor as bi, type ResponseInterceptorData as bj, type ReturnRequest as bk, type ReturnRequestItem as bl, type ReturnStatus as bm, type ReturnStatusItem as bn, type ReturnableOrder as bo, type ReturnableOrderItem as bp, type SdkError as bq, type ShippingMethodSummary as br, type ShippingQuote as bs, type ShippingQuoteInput as bt, type ShopInfo as bu, type ShopScript as bv, type ShopScriptPlacement as bw, type ShopScriptType as bx, type ShopScripts as by, type ShopSeo as bz, type AddressSuggestion as c, type AddressType as d, AddressTypes as e, type AuthTokens as f, type BackInStockSubscription as g, type BadgeTone as h, BehioApiError as i, type BehioErrorCode as j, type BehioEventHandler as k, type BehioEventType as l, BehioNetworkError as m, type BehioStorefrontConfig as n, type Bundle as o, type BundleItem as p, type Cart as q, type CartBundleLine as r, type CartBundleLineItem as s, type CartDiscount as t, type CartItem as u, type CartItemProduct as v, type CartPromotion as w, type Category as x, type CategoryDetail as y, type CertificateVerification as z };
2936
+ export { type DigitalDownload as $, type ActivePromotion as A, BehioStorefront as B, type CookieConsent as C, type CertificateVerification as D, type CheckoutAddress as E, type CheckoutInput as F, type CheckoutPaymentMethod as G, type CheckoutSettings as H, type CookieConsentInput as I, type CourseAttachment as J, type CourseCertificate as K, type CourseComment as L, type CourseCommentReply as M, type CourseCommentsList as N, type CourseDetail as O, type ProductDetail as P, type CourseLesson as Q, type CourseListItem as R, type SdkResult as S, type CourseModule as T, type CoursePostedComment as U, type CourseProgress as V, type CourseTutorMessage as W, type CourseTutorThread as X, type CrossSellItem as Y, type CustomerAddress as Z, type CustomerProfile as _, type ProductVariant as a, type ProductParametersResponse as a$, type DownloadUrl as a0, type Facet as a1, type FacetAvailability as a2, type FacetCategory as a3, type FacetLabel as a4, type FacetPriceRange as a5, type FacetRange as a6, type FacetRatingBucket as a7, type FacetValue as a8, type FacetsResponse as a9, type OrderAccessRequestResponse as aA, type OrderAccessVerifyResponse as aB, type OrderDetail as aC, type OrderItem as aD, type OrderListItem as aE, type OrderStatus as aF, type OrderStatusHistory as aG, OrderStatuses as aH, type OrderTracking as aI, type Page as aJ, type PageAttachment as aK, type PageDetail as aL, type PaginatedResponse as aM, type PaymentStatus as aN, PaymentStatuses as aO, type PickupPoint as aP, type PickupPointHours as aQ, type PickupPointsInput as aR, type PriceDisplay as aS, type ProductAvailability as aT, type ProductGroup as aU, type ProductLabel as aV, type ProductListItem as aW, type ProductMedia as aX, type ProductMediaVariant as aY, type ProductParameter as aZ, type ProductParameterGroup as a_, type FilterField as aa, type FulfillmentStatus as ab, FulfillmentStatuses as ac, type GiftCardBalance as ad, type GiftCardPurchaseInput as ae, type GiftCardPurchaseResult as af, type GiftCardSummary as ag, type LessonNote as ah, type LessonQuiz as ai, type LoginInput as aj, type LoyaltyBalance as ak, type LoyaltyNextTier as al, type LoyaltyProgram as am, type LoyaltySummary as an, type LoyaltyTier as ao, type LoyaltyTierPerks as ap, type LoyaltyTransaction as aq, type Menu as ar, type MenuItem as as, type MenuItemRef as at, type MenuItemType as au, type MessageResponse as av, type NewsletterOptInDefault as aw, type NewsletterSubscribeInput as ax, type NewsletterSubscribeResult as ay, type NewsletterUnsubscribeResult as az, type AddToCartInput as b, type ProductPrice as b0, type ProductPromotionSummary as b1, type ProductReview as b2, type ProductReviewsResponse as b3, ProductSort as b4, type ProductSortValue as b5, type ProductVolumePrice as b6, type ProductsQuery as b7, type QuizAnswerInput as b8, type QuizAnswerResult as b9, type ShopSeoIdentity as bA, type StockBehavior as bB, type StockMode as bC, type SubmitQuoteInput as bD, type SubmitReturnInput as bE, type SubmitReviewInput as bF, type Subscription as bG, type SubscriptionAction as bH, type SubscriptionFrequency as bI, type SubscriptionItem as bJ, type SubscriptionStatus as bK, type TaxBreakdownLine as bL, type VariantAxis as bM, type VariantAxisValue as bN, type WishlistItem as bO, err as bP, ok as bQ, toSdkError as bR, type QuizQuestion as ba, type QuizResult as bb, type QuoteItem as bc, type QuoteRequest as bd, type RegisterInput as be, type RegisterResult as bf, type RequestInterceptor as bg, type RequestInterceptorConfig as bh, type ResponseInterceptor as bi, type ResponseInterceptorData as bj, type ReturnRequest as bk, type ReturnRequestItem as bl, type ReturnStatus as bm, type ReturnStatusItem as bn, type ReturnableOrder as bo, type ReturnableOrderItem as bp, type SdkError as bq, type ShippingMethodSummary as br, type ShippingQuote as bs, type ShippingQuoteInput as bt, type ShopInfo as bu, type ShopScript as bv, type ShopScriptPlacement as bw, type ShopScriptType as bx, type ShopScripts as by, type ShopSeo as bz, type AddressDetail as c, type AddressSuggestion as d, type AddressType as e, AddressTypes as f, type AuthTokens as g, type BackInStockSubscription as h, type BadgeTone as i, BehioApiError as j, type BehioErrorCode as k, type BehioEventHandler as l, type BehioEventType as m, BehioNetworkError as n, type BehioStorefrontConfig as o, type Bundle as p, type BundleItem as q, type Cart as r, type CartBundleLine as s, type CartBundleLineItem as t, type CartDiscount as u, type CartItem as v, type CartItemProduct as w, type CartPromotion as x, type Category as y, type CategoryDetail as z };