@decocms/apps 1.1.2 → 1.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/apps",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "description": "Deco commerce apps for TanStack Start - Shopify, VTEX, commerce types, analytics utils",
6
6
  "exports": {
@@ -53,6 +53,7 @@ export default async function vtexProductDetailsPage(
53
53
  const page = toProductPage(product, sku, kitItems, {
54
54
  baseUrl,
55
55
  priceCurrency: "BRL",
56
+ leanVariants: true,
56
57
  });
57
58
 
58
59
  return {
@@ -105,6 +105,10 @@ interface ProductOptions {
105
105
  imagesByKey?: Map<string, string>;
106
106
  /** Original attributes to be included in the transformed product */
107
107
  includeOriginalAttributes?: string[];
108
+ /** Use lean toProductVariant for hasVariant[] instead of full toProduct at level=1 */
109
+ leanVariants?: boolean;
110
+ /** Property names to keep on lean variant additionalProperty. Defaults to VARIANT_PROPERTY_NAMES. */
111
+ variantPropertyNames?: Set<string>;
108
112
  }
109
113
 
110
114
  /** Returns first available sku */
@@ -389,7 +393,9 @@ export const toProduct = <P extends LegacyProductVTEX | ProductVTEX>(
389
393
  ? ({
390
394
  "@type": "ProductGroup",
391
395
  productGroupID: productId,
392
- hasVariant: items.map((sku) => toProduct(product, sku, 1, variantOptions)),
396
+ hasVariant: options.leanVariants
397
+ ? items.map((sku) => toProductVariant(product, sku, variantOptions))
398
+ : items.map((sku) => toProduct(product, sku, 1, variantOptions)),
393
399
  url: getProductGroupURL(baseUrl, product).href,
394
400
  name: product.productName,
395
401
  additionalProperty: [
@@ -659,6 +665,70 @@ export const toProductShelf = <P extends LegacyProductVTEX | ProductVTEX>(
659
665
  };
660
666
  };
661
667
 
668
+ /** Property names that differentiate SKU variants (used by variant selectors) */
669
+ const VARIANT_PROPERTY_NAMES = new Set(["Cor", "Voltagem", "Tamanho"]);
670
+
671
+ /**
672
+ * Build a minimal offer for variant display. Keeps only availability and seller.
673
+ * No priceSpecification, no inventoryLevel, no teasers.
674
+ */
675
+ const buildOfferVariant = (offer: Offer): Offer => ({
676
+ "@type": "Offer",
677
+ identifier: offer.identifier,
678
+ price: offer.price,
679
+ seller: offer.seller,
680
+ availability: offer.availability,
681
+ priceSpecification: [],
682
+ inventoryLevel: { value: 0 },
683
+ });
684
+
685
+ /**
686
+ * Minimal product transform for variant entries inside isVariantOf.hasVariant[].
687
+ *
688
+ * Keeps only what variant selectors need:
689
+ * - url, productID, sku, name, inProductGroupWithID
690
+ * - additionalProperty filtered to variant-differentiating props (Cor, Voltagem, Tamanho)
691
+ * - offers with availability + seller only (no price specs)
692
+ *
693
+ * Drops: images, description, video, brand, category, gtin, releaseDate,
694
+ * alternateName, isAccessoryOrSparePartFor, isVariantOf
695
+ */
696
+ export const toProductVariant = <P extends LegacyProductVTEX | ProductVTEX>(
697
+ product: P,
698
+ sku: P["items"][number],
699
+ options: ProductOptions,
700
+ ): Product => {
701
+ const { baseUrl, priceCurrency } = options;
702
+ const { productId } = product;
703
+ const { name, itemId: skuId } = sku;
704
+ const variantProps = options.variantPropertyNames ?? VARIANT_PROPERTY_NAMES;
705
+
706
+ // additionalProperty: only variant-differentiating specs
707
+ const specificationsAdditionalProperty = isLegacySku(sku)
708
+ ? toAdditionalPropertiesLegacy(sku)
709
+ : toAdditionalProperties(sku);
710
+ const additionalProperty = specificationsAdditionalProperty.filter((prop) =>
711
+ variantProps.has(prop.name ?? ""),
712
+ );
713
+
714
+ // Offers: all sellers but lean (availability + seller only)
715
+ const offerConverter = isLegacyProduct(product) ? toOfferLegacy : toOffer;
716
+ const allOffers = (sku.sellers ?? []).map(offerConverter).sort(bestOfferFirst);
717
+ const bestOffer = allOffers[0];
718
+ const leanOffers = bestOffer ? [buildOfferVariant(bestOffer)] : [];
719
+
720
+ return {
721
+ "@type": "Product",
722
+ productID: skuId,
723
+ sku: skuId,
724
+ name,
725
+ url: getProductURL(baseUrl, product, sku.itemId).href,
726
+ inProductGroupWithID: productId,
727
+ additionalProperty,
728
+ offers: aggregateOffers(leanOffers, priceCurrency),
729
+ };
730
+ };
731
+
662
732
  const toBreadcrumbList = (
663
733
  product: ProductVTEX | LegacyProductVTEX,
664
734
  { baseUrl }: ProductOptions,