@decocms/apps-vtex 8.1.0-next.0 → 8.1.0-next.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.
Files changed (139) hide show
  1. package/package.json +7 -52
  2. package/src/index.ts +10 -28
  3. package/src/utils/constants.ts +2 -56
  4. package/src/utils/cookieSanitizer.ts +59 -59
  5. package/src/utils/operationRouter.ts +75 -65
  6. package/src/utils/types.ts +709 -1557
  7. package/src/vtexClient.ts +354 -343
  8. package/src/README.md +0 -6
  9. package/src/__conformance__/upstream.test.ts +0 -158
  10. package/src/__tests__/client-segment-cookie.test.ts +0 -255
  11. package/src/__tests__/client-set-cookie-forward.test.ts +0 -257
  12. package/src/__tests__/schemas.test.ts +0 -71
  13. package/src/actions/address.ts +0 -250
  14. package/src/actions/analytics/sendEvent.ts +0 -86
  15. package/src/actions/auth.ts +0 -333
  16. package/src/actions/checkout.ts +0 -659
  17. package/src/actions/index.ts +0 -11
  18. package/src/actions/masterData.ts +0 -168
  19. package/src/actions/misc.ts +0 -188
  20. package/src/actions/newsletter.ts +0 -105
  21. package/src/actions/orders.ts +0 -34
  22. package/src/actions/profile.ts +0 -201
  23. package/src/actions/session.ts +0 -85
  24. package/src/actions/trigger.ts +0 -43
  25. package/src/actions/wishlist.ts +0 -114
  26. package/src/client.ts +0 -724
  27. package/src/commerceLoaders.ts +0 -267
  28. package/src/hooks/__tests__/createCart.render.test.ts +0 -114
  29. package/src/hooks/__tests__/createCart.test.ts +0 -92
  30. package/src/hooks/__tests__/createUseCart.test.ts +0 -184
  31. package/src/hooks/__tests__/createUseUser.test.ts +0 -48
  32. package/src/hooks/__tests__/createUseWishlist.test.ts +0 -87
  33. package/src/hooks/cartQuery.ts +0 -204
  34. package/src/hooks/createCart.ts +0 -427
  35. package/src/hooks/createUseCart.ts +0 -360
  36. package/src/hooks/createUseUser.ts +0 -153
  37. package/src/hooks/createUseWishlist.ts +0 -242
  38. package/src/hooks/index.ts +0 -25
  39. package/src/hooks/useAutocomplete.ts +0 -83
  40. package/src/hooks/useCart.ts +0 -243
  41. package/src/hooks/useUser.ts +0 -78
  42. package/src/hooks/useWishlist.ts +0 -119
  43. package/src/invoke.ts +0 -235
  44. package/src/loaders/ProductDetailsPage.ts +0 -1
  45. package/src/loaders/ProductList.ts +0 -1
  46. package/src/loaders/ProductListingPage.ts +0 -1
  47. package/src/loaders/__tests__/legacyProductList.test.ts +0 -157
  48. package/src/loaders/address.ts +0 -115
  49. package/src/loaders/autocomplete.ts +0 -56
  50. package/src/loaders/brands.ts +0 -44
  51. package/src/loaders/cart/attachments.ts +0 -53
  52. package/src/loaders/cart/full.ts +0 -67
  53. package/src/loaders/cart/gifts.ts +0 -43
  54. package/src/loaders/cart/orderFormId.ts +0 -31
  55. package/src/loaders/cart/shipping.test.ts +0 -125
  56. package/src/loaders/cart/shipping.ts +0 -136
  57. package/src/loaders/cart/summary.ts +0 -36
  58. package/src/loaders/cart.ts +0 -52
  59. package/src/loaders/catalog.ts +0 -163
  60. package/src/loaders/collections.ts +0 -55
  61. package/src/loaders/index.ts +0 -20
  62. package/src/loaders/intelligentSearch/__tests__/productListingPage.test.ts +0 -51
  63. package/src/loaders/intelligentSearch/productDetailsPage.ts +0 -111
  64. package/src/loaders/intelligentSearch/productList.ts +0 -170
  65. package/src/loaders/intelligentSearch/productListingPage.ts +0 -525
  66. package/src/loaders/intelligentSearch/suggestions.ts +0 -44
  67. package/src/loaders/legacy/productDetailsPage.ts +0 -1
  68. package/src/loaders/legacy/productList.ts +0 -1
  69. package/src/loaders/legacy/relatedProductsLoader.ts +0 -79
  70. package/src/loaders/legacy.ts +0 -710
  71. package/src/loaders/logistics.ts +0 -111
  72. package/src/loaders/minicart.ts +0 -78
  73. package/src/loaders/navbar.ts +0 -26
  74. package/src/loaders/orders.ts +0 -92
  75. package/src/loaders/pageType.ts +0 -68
  76. package/src/loaders/paths/PDPDefaultPath.ts +0 -51
  77. package/src/loaders/payment.ts +0 -97
  78. package/src/loaders/productListFull.ts +0 -157
  79. package/src/loaders/profile.ts +0 -138
  80. package/src/loaders/promotion.ts +0 -30
  81. package/src/loaders/search.ts +0 -124
  82. package/src/loaders/session.ts +0 -83
  83. package/src/loaders/user.ts +0 -87
  84. package/src/loaders/wishlist.ts +0 -89
  85. package/src/loaders/wishlistProducts.ts +0 -69
  86. package/src/loaders/workflow/products.ts +0 -62
  87. package/src/loaders/workflow.ts +0 -316
  88. package/src/logo.png +0 -0
  89. package/src/manifest.gen.ts +0 -89
  90. package/src/middleware.cacheHeaders.test.ts +0 -44
  91. package/src/middleware.ts +0 -240
  92. package/src/mod.ts +0 -173
  93. package/src/registry.ts +0 -9
  94. package/src/schemas.gen.ts +0 -3191
  95. package/src/schemas.ts +0 -30
  96. package/src/types.ts +0 -248
  97. package/src/utils/__tests__/cartProjection.test.ts +0 -118
  98. package/src/utils/__tests__/cookieSanitizer.test.ts +0 -162
  99. package/src/utils/__tests__/fetch.test.ts +0 -80
  100. package/src/utils/__tests__/fetchCache.test.ts +0 -155
  101. package/src/utils/__tests__/instrumentedFetch.test.ts +0 -158
  102. package/src/utils/__tests__/intelligentSearch.test.ts +0 -88
  103. package/src/utils/__tests__/minicart.test.ts +0 -184
  104. package/src/utils/__tests__/operationRouter.test.ts +0 -227
  105. package/src/utils/__tests__/resilience.test.ts +0 -205
  106. package/src/utils/__tests__/resourceRange.test.ts +0 -32
  107. package/src/utils/__tests__/simulationCache.test.ts +0 -40
  108. package/src/utils/__tests__/sitemap.test.ts +0 -185
  109. package/src/utils/__tests__/slugify.test.ts +0 -31
  110. package/src/utils/__tests__/storefrontBaseUrl.test.ts +0 -61
  111. package/src/utils/__tests__/transform.test.ts +0 -1111
  112. package/src/utils/accountLoaders.ts +0 -203
  113. package/src/utils/authHelpers.ts +0 -85
  114. package/src/utils/batch.ts +0 -18
  115. package/src/utils/buildOfferShelf.test.ts +0 -59
  116. package/src/utils/cartProjection.ts +0 -96
  117. package/src/utils/cookies.ts +0 -167
  118. package/src/utils/enrichment.ts +0 -556
  119. package/src/utils/fetch.ts +0 -111
  120. package/src/utils/fetchCache.ts +0 -55
  121. package/src/utils/index.ts +0 -19
  122. package/src/utils/instrumentedFetch.ts +0 -98
  123. package/src/utils/intelligentSearch.ts +0 -96
  124. package/src/utils/legacy.ts +0 -139
  125. package/src/utils/minicart.ts +0 -139
  126. package/src/utils/pickAndOmit.ts +0 -25
  127. package/src/utils/proxy.ts +0 -495
  128. package/src/utils/resilience.ts +0 -352
  129. package/src/utils/resourceRange.ts +0 -10
  130. package/src/utils/segment.ts +0 -152
  131. package/src/utils/similars.ts +0 -35
  132. package/src/utils/simulationCache.ts +0 -73
  133. package/src/utils/sitemap.ts +0 -283
  134. package/src/utils/slugCache.ts +0 -28
  135. package/src/utils/slugify.ts +0 -13
  136. package/src/utils/transform.ts +0 -1691
  137. package/src/utils/vtexId.ts +0 -151
  138. package/src/vtexClient.test.ts +0 -204
  139. package/tsconfig.json +0 -7
@@ -1,163 +0,0 @@
1
- /**
2
- * VTEX Catalog System API loaders.
3
- * Pure async functions using vtexFetch. Require configureVtex() to have been called.
4
- *
5
- * Ported from deco-cx/apps vtex/loaders/legacy/*.ts and vtex/utils/client.ts
6
- * @see https://developers.vtex.com/docs/api-reference/catalog-api
7
- */
8
- import { getVtexConfig, vtexFetch } from "../client";
9
-
10
- // ---------------------------------------------------------------------------
11
- // Product search (public)
12
- // ---------------------------------------------------------------------------
13
-
14
- export type LegacySort =
15
- | ""
16
- | "OrderByTopSaleDESC"
17
- | "OrderByReleaseDateDESC"
18
- | "OrderByBestDiscountDESC"
19
- | "OrderByPriceDESC"
20
- | "OrderByPriceASC"
21
- | "OrderByNameASC"
22
- | "OrderByNameDESC"
23
- | "OrderByScoreDESC";
24
-
25
- export interface SearchProductsOpts {
26
- fq?: string | string[];
27
- ft?: string;
28
- sort?: LegacySort;
29
- from?: number;
30
- to?: number;
31
- }
32
-
33
- /**
34
- * Search products using the VTEX Catalog API.
35
- * @see https://developers.vtex.com/docs/api-reference/search-api#get-/api/catalog_system/pub/products/search
36
- */
37
- export async function searchProducts<T = any>(opts: SearchProductsOpts = {}): Promise<T[]> {
38
- const params = new URLSearchParams();
39
- const fqs = Array.isArray(opts.fq) ? opts.fq : opts.fq ? [opts.fq] : [];
40
- for (const f of fqs) params.append("fq", f);
41
- if (opts.ft) params.set("ft", opts.ft);
42
- if (opts.sort) params.set("O", opts.sort);
43
- if (opts.from != null) params.set("_from", String(opts.from));
44
- if (opts.to != null) params.set("_to", String(opts.to));
45
-
46
- const { salesChannel } = getVtexConfig();
47
- if (salesChannel) params.set("sc", salesChannel);
48
-
49
- return vtexFetch<T[]>(`/api/catalog_system/pub/products/search/?${params}`);
50
- }
51
-
52
- /**
53
- * Get a product by productId or skuId.
54
- * @see https://developers.vtex.com/docs/api-reference/search-api#get-/api/catalog_system/pub/products/search
55
- */
56
- export async function getProductByIdOrSku<T = any>(opts: {
57
- productId?: string;
58
- skuId?: string;
59
- }): Promise<T | null> {
60
- let fq: string;
61
- if (opts.productId) fq = `productId:${opts.productId}`;
62
- else if (opts.skuId) fq = `skuId:${opts.skuId}`;
63
- else throw new Error("Neither productId nor skuId provided.");
64
-
65
- const results = await searchProducts<T>({ fq });
66
- return results[0] ?? null;
67
- }
68
-
69
- // ---------------------------------------------------------------------------
70
- // Product variations (public)
71
- // ---------------------------------------------------------------------------
72
-
73
- /**
74
- * Get product SKU variations.
75
- * @see https://developers.vtex.com/docs/api-reference/catalog-api#get-/api/catalog_system/pub/products/variations/-productId-
76
- */
77
- export async function getProductVariations<T = any>(productId: string): Promise<T> {
78
- return vtexFetch<T>(`/api/catalog_system/pub/products/variations/${productId}`);
79
- }
80
-
81
- // ---------------------------------------------------------------------------
82
- // Product specification (private — requires appKey/appToken)
83
- // ---------------------------------------------------------------------------
84
-
85
- /**
86
- * Get product specifications (private API).
87
- * @see https://developers.vtex.com/docs/api-reference/catalog-api#get-/api/catalog_system/pvt/products/-productId-/specification
88
- */
89
- export async function getProductSpecification<T = any>(productId: string): Promise<T> {
90
- return vtexFetch<T>(`/api/catalog_system/pvt/products/${productId}/Specification`);
91
- }
92
-
93
- // ---------------------------------------------------------------------------
94
- // Cross-selling
95
- // ---------------------------------------------------------------------------
96
-
97
- export type CrossSellingType =
98
- | "similars"
99
- | "suggestions"
100
- | "accessories"
101
- | "whosawalsosaw"
102
- | "whosawalsobought"
103
- | "whoboughtalsobought"
104
- | "showtogether";
105
-
106
- /**
107
- * Get cross-selling products.
108
- * @see https://developers.vtex.com/docs/api-reference/catalog-api#get-/api/catalog_system/pub/products/crossselling/-type-/-productId-
109
- */
110
- export async function getCrossSelling<T = any>(
111
- type: CrossSellingType,
112
- productId: string,
113
- ): Promise<T[]> {
114
- return vtexFetch<T[]>(`/api/catalog_system/pub/products/crossselling/${type}/${productId}`);
115
- }
116
-
117
- // ---------------------------------------------------------------------------
118
- // Categories
119
- // ---------------------------------------------------------------------------
120
-
121
- /**
122
- * Get the category tree up to a given depth level.
123
- * @see https://developers.vtex.com/docs/api-reference/catalog-api#get-/api/catalog_system/pub/category/tree/-categoryLevels-
124
- */
125
- export async function getCategoryTree<T = any>(levels = 3): Promise<T[]> {
126
- return vtexFetch<T[]>(`/api/catalog_system/pub/category/tree/${levels}`);
127
- }
128
-
129
- // ---------------------------------------------------------------------------
130
- // Brands
131
- // ---------------------------------------------------------------------------
132
-
133
- /**
134
- * Get all brands.
135
- * @see https://developers.vtex.com/docs/api-reference/catalog-api#get-/api/catalog_system/pub/brand/list
136
- */
137
- export async function getBrands<T = any>(): Promise<T[]> {
138
- return vtexFetch<T[]>("/api/catalog_system/pub/brand/list");
139
- }
140
-
141
- // ---------------------------------------------------------------------------
142
- // Page type
143
- // ---------------------------------------------------------------------------
144
-
145
- /**
146
- * Get the page type for a given term/path.
147
- * @see https://developers.vtex.com/docs/api-reference/catalog-api#get-/api/catalog_system/pub/portal/pagetype/-term-
148
- */
149
- export async function getPageType<T = any>(term: string): Promise<T> {
150
- return vtexFetch<T>(`/api/catalog_system/pub/portal/pagetype/${term}`);
151
- }
152
-
153
- // ---------------------------------------------------------------------------
154
- // Facets (legacy)
155
- // ---------------------------------------------------------------------------
156
-
157
- /**
158
- * Get facets/filters for a search term.
159
- * @see https://developers.vtex.com/docs/api-reference/search-api#get-/api/catalog_system/pub/facets/search/-term-
160
- */
161
- export async function getFacets<T = any>(term: string): Promise<T> {
162
- return vtexFetch<T>(`/api/catalog_system/pub/facets/search/${term}`);
163
- }
@@ -1,55 +0,0 @@
1
- /**
2
- * VTEX Collections loader.
3
- * Pure async function — requires configureVtex() to have been called.
4
- *
5
- * Ported from deco-cx/apps:
6
- * vtex/loaders/collections/list.ts
7
- *
8
- * @see https://developers.vtex.com/docs/api-reference/catalog-api#get-/api/catalog_system/pvt/collection/search
9
- */
10
- import { vtexFetch } from "../client";
11
- import type { CollectionList } from "../utils/types";
12
-
13
- export interface CollectionOption {
14
- value: string;
15
- label: string;
16
- }
17
-
18
- /**
19
- * Fetch collections, optionally filtering by search term.
20
- *
21
- * Without a term returns up to 3 000 collections; with a term
22
- * returns the first 15 matches. Results are mapped to a simple
23
- * `{ value, label }` list suitable for dropdowns / selectors.
24
- *
25
- * Note: uses the **pvt** (private) endpoint — requires appKey/appToken.
26
- */
27
- export async function getCollections(term?: string): Promise<CollectionOption[]> {
28
- const params = new URLSearchParams();
29
-
30
- if (term) {
31
- params.set("page", "1");
32
- params.set("pageSize", "15");
33
- const list = await vtexFetch<CollectionList>(
34
- `/api/catalog_system/pvt/collection/search/${encodeURIComponent(term)}?${params}`,
35
- );
36
- return mapToOptions(list);
37
- }
38
-
39
- params.set("page", "1");
40
- params.set("pageSize", "3000");
41
- params.set("orderByAsc", "false");
42
- const list = await vtexFetch<CollectionList>(
43
- `/api/catalog_system/pvt/collection/search?${params}`,
44
- );
45
- return mapToOptions(list);
46
- }
47
-
48
- function mapToOptions(list: CollectionList): CollectionOption[] {
49
- return (
50
- list.items?.map((c) => ({
51
- value: `${c.id}`,
52
- label: `${c.id} - ${c.name}`,
53
- })) ?? []
54
- );
55
- }
@@ -1,20 +0,0 @@
1
- export * from "./address";
2
- export * from "./brands";
3
- export * from "./cart";
4
- export * from "./cart/shipping";
5
- export * from "./catalog";
6
- export * from "./collections";
7
- export * from "./legacy";
8
- export * from "./logistics";
9
- export * from "./navbar";
10
- export * from "./orders";
11
- export * from "./pageType";
12
- export * from "./payment";
13
- export * from "./profile";
14
- export * from "./promotion";
15
- export * from "./search";
16
- export * from "./session";
17
- export * from "./user";
18
- export * from "./wishlist";
19
- export * from "./wishlistProducts";
20
- export * from "./workflow";
@@ -1,51 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { mapLabelledFuzzyToFuzzy, resolvePage } from "../productListingPage";
3
-
4
- describe("mapLabelledFuzzyToFuzzy", () => {
5
- it("translates 'automatic' to 'auto'", () => {
6
- expect(mapLabelledFuzzyToFuzzy("automatic")).toBe("auto");
7
- });
8
-
9
- it("translates 'enabled' to '1'", () => {
10
- expect(mapLabelledFuzzyToFuzzy("enabled")).toBe("1");
11
- });
12
-
13
- it("translates 'disabled' to '0'", () => {
14
- expect(mapLabelledFuzzyToFuzzy("disabled")).toBe("0");
15
- });
16
-
17
- it("returns undefined for missing label", () => {
18
- expect(mapLabelledFuzzyToFuzzy(undefined)).toBeUndefined();
19
- });
20
- });
21
-
22
- describe("resolvePage (#391)", () => {
23
- it("defaults to page 0 with no props.page and no URL page", () => {
24
- expect(resolvePage(undefined, undefined)).toBe(0);
25
- });
26
-
27
- it("converts a 1-indexed URL ?page= to the 0-indexed internal page", () => {
28
- expect(resolvePage(undefined, "3")).toBe(2);
29
- });
30
-
31
- it("uses props.page directly (already 0-indexed) over the URL", () => {
32
- expect(resolvePage(5, "3")).toBe(5);
33
- });
34
-
35
- it("coerces a string props.page instead of silently falling back to 0", () => {
36
- expect(resolvePage("3", undefined)).toBe(3);
37
- });
38
-
39
- it("falls through to the URL page when props.page is a non-finite string", () => {
40
- expect(resolvePage("not-a-number", "3")).toBe(2);
41
- });
42
-
43
- it("resets a malformed ?page= to 0 instead of propagating NaN", () => {
44
- expect(resolvePage(undefined, "abc")).toBe(0);
45
- });
46
-
47
- it("floors a fractional page and never returns a negative page", () => {
48
- expect(resolvePage(2.7, undefined)).toBe(2);
49
- expect(resolvePage(-1, undefined)).toBe(0);
50
- });
51
- });
@@ -1,111 +0,0 @@
1
- /**
2
- * PDP loader using Legacy Catalog API + shared transform pipeline.
3
- * Maps VTEX catalog response to schema.org ProductDetailsPage
4
- * following the same pattern as deco-cx/apps.
5
- */
6
-
7
- import type { ProductDetailsPage } from "@decocms/apps-commerce/types";
8
- import { getVtexConfig, storefrontBaseUrl, vtexCachedFetch } from "../../client";
9
- import PDPDefaultPath from "../paths/PDPDefaultPath";
10
- import { searchBySlug } from "../../utils/slugCache";
11
- import { pickSku, toProductPage } from "../../utils/transform";
12
- import type { LegacyProduct } from "../../utils/types";
13
-
14
- export interface PDPProps {
15
- slug?: string;
16
- skuId?: string;
17
- /** When true, PDP pages with ?skuId remain indexable */
18
- indexingSkus?: boolean;
19
- /** Use product.description instead of metaTagDescription for SEO */
20
- preferDescription?: boolean;
21
- /**
22
- * Use lean variant transform for hasVariant[]. Defaults to false on PDPs:
23
- * variant selectors need image[] and real inventoryLevel to render thumbnails
24
- * and per-SKU stock state, so a full toProduct(level=1) is the safe default.
25
- * Opt-in only if payload size becomes a problem.
26
- */
27
- leanVariants?: boolean;
28
- /** When leanVariants is true, still include image[0] on each variant. Default true. */
29
- variantIncludeImage?: boolean;
30
- /** When leanVariants is true, still include inventoryLevel on each variant. Default true. */
31
- variantIncludeInventory?: boolean;
32
- }
33
-
34
- export default async function vtexProductDetailsPage(
35
- props: PDPProps,
36
- ): Promise<ProductDetailsPage | null> {
37
- const {
38
- slug,
39
- skuId,
40
- indexingSkus,
41
- preferDescription,
42
- leanVariants = false,
43
- variantIncludeImage = true,
44
- variantIncludeInventory = true,
45
- } = props;
46
-
47
- try {
48
- // Only the admin hits the PDP at its raw route pattern (`/:slug/p`), so the
49
- // `slug` route-param resolves to the literal placeholder `:slug` — there's
50
- // no real product in the URL, so render the best seller as a preview.
51
- //
52
- // This is NOT a general fallback: a concrete slug that resolves to no
53
- // product (e.g. `/dssadals/p`) must still 404 like any missing product, and
54
- // a genuinely absent slug must NOT pull in an unrelated product either. So
55
- // we trigger ONLY on the `:`-prefixed placeholder, never on empty/missing.
56
- // Mirrors deco-cx/apps' PDPDefaultPath behavior.
57
- let effectiveSlug = slug;
58
-
59
- if (slug?.startsWith(":")) {
60
- const defaultPaths = await PDPDefaultPath({ count: 1 });
61
- effectiveSlug = defaultPaths?.possiblePaths[0];
62
- }
63
-
64
- if (!effectiveSlug) return null;
65
-
66
- const linkText = effectiveSlug.replace(/\/p$/, "").replace(/^\//, "").toLowerCase();
67
- const config = getVtexConfig();
68
- const sc = config.salesChannel;
69
-
70
- const products = await searchBySlug(linkText);
71
-
72
- if (!products || products.length === 0) {
73
- return null;
74
- }
75
-
76
- const product = products[0];
77
- const baseUrl = storefrontBaseUrl(config);
78
-
79
- const sku = pickSku(product, skuId);
80
-
81
- const kitItems: LegacyProduct[] =
82
- Array.isArray(sku.kitItems) && sku.kitItems.length > 0
83
- ? ((await vtexCachedFetch<LegacyProduct[]>(
84
- `/api/catalog_system/pub/products/search/?fq=${sku.kitItems.map((item: any) => `skuId:${item.itemId}`).join("&fq=")}&_from=0&_to=49${sc ? `&sc=${sc}` : ""}`,
85
- )) ?? [])
86
- : [];
87
-
88
- const page = toProductPage(product, sku, kitItems, {
89
- baseUrl,
90
- priceCurrency: "BRL",
91
- leanVariants,
92
- variantIncludeImage,
93
- variantIncludeInventory,
94
- });
95
-
96
- return {
97
- ...page,
98
- seo: {
99
- title: product.productTitle || product.productName,
100
- description: preferDescription
101
- ? product.description
102
- : product.metaTagDescription || product.description?.substring(0, 160) || "",
103
- canonical: `/${product.linkText}/p`,
104
- noIndexing: indexingSkus ? false : !!skuId,
105
- },
106
- };
107
- } catch (error) {
108
- console.error("[VTEX] PDP error:", error);
109
- return null;
110
- }
111
- }
@@ -1,170 +0,0 @@
1
- /**
2
- * Lean product list loader for shelf/card display.
3
- * Same API call as productList.ts but uses toProductShelf() for ~90% smaller payloads.
4
- *
5
- * Use this loader for ProductShelf sections where only card-level data is needed
6
- * (name, URL, images, price, installments, PIX, availability, brand).
7
- */
8
-
9
- import type { Product } from "@decocms/apps-commerce/types";
10
- import { getVtexConfig, intelligentSearch, storefrontBaseUrl, toFacetPath } from "../../client";
11
- import { pickSku, sortProducts, toProductShelf } from "../../utils/transform";
12
- import type { Product as ProductVTEX } from "../../utils/types";
13
-
14
- export interface ProductListProps {
15
- props?: CollectionProps | QueryProps | ProductIDProps | FacetsProps;
16
- /**
17
- * Include every SKU as a lean variant in each product's isVariantOf.hasVariant[]
18
- * so shelf cards can render the full size/color grid. Default false (lean shelf:
19
- * a single in-stock variant per product).
20
- */
21
- completeVariants?: boolean;
22
- /**
23
- * `imageLabel`s that survive the shelf transform's 2-image cap. Storefronts
24
- * that pick the card image by name (a still/packshot asset, a colour
25
- * thumbnail) need this: those assets are registered last on the SKU, so the
26
- * positional cap drops them and the card falls back to the first photo.
27
- */
28
- keepImageNames?: string[];
29
- }
30
-
31
- interface CollectionProps {
32
- collection: string;
33
- count?: number;
34
- sort?: string;
35
- hideUnavailableItems?: boolean;
36
- }
37
-
38
- interface QueryProps {
39
- query: string;
40
- count?: number;
41
- sort?: string;
42
- fuzzy?: string;
43
- hideUnavailableItems?: boolean;
44
- }
45
-
46
- interface ProductIDProps {
47
- ids: string[];
48
- hideUnavailableItems?: boolean;
49
- }
50
-
51
- interface FacetsProps {
52
- query?: string;
53
- facets: string;
54
- count?: number;
55
- sort?: string;
56
- hideUnavailableItems?: boolean;
57
- }
58
-
59
- function isCollectionProps(p: any): p is CollectionProps {
60
- return typeof p?.collection === "string";
61
- }
62
- function isProductIDProps(p: any): p is ProductIDProps {
63
- return Array.isArray(p?.ids) && p.ids.length > 0;
64
- }
65
- function isFacetsProps(p: any): p is FacetsProps {
66
- return typeof p?.facets === "string";
67
- }
68
-
69
- function resolveParams(props: ProductListProps): {
70
- query: string;
71
- count: number;
72
- sort: string;
73
- facetPath: string;
74
- fuzzy?: string;
75
- hideUnavailableItems: boolean;
76
- ids?: string[];
77
- } {
78
- const inner = props.props ?? props;
79
-
80
- if (isProductIDProps(inner)) {
81
- return {
82
- query: `sku:${inner.ids.join(";")}`,
83
- count: inner.ids.length,
84
- sort: "",
85
- facetPath: "",
86
- hideUnavailableItems: inner.hideUnavailableItems ?? false,
87
- ids: inner.ids,
88
- };
89
- }
90
-
91
- if (isFacetsProps(inner)) {
92
- return {
93
- query: inner.query ?? "",
94
- count: inner.count ?? 12,
95
- sort: inner.sort ?? "",
96
- facetPath: inner.facets,
97
- hideUnavailableItems: inner.hideUnavailableItems ?? false,
98
- };
99
- }
100
-
101
- if (isCollectionProps(inner)) {
102
- return {
103
- query: "",
104
- count: inner.count ?? 12,
105
- sort: inner.sort ?? "",
106
- facetPath: toFacetPath([{ key: "productClusterIds", value: inner.collection }]),
107
- hideUnavailableItems: inner.hideUnavailableItems ?? false,
108
- };
109
- }
110
-
111
- return {
112
- query: (inner as any).query ?? "",
113
- count: (inner as any).count ?? 12,
114
- sort: (inner as any).sort ?? "",
115
- facetPath: "",
116
- fuzzy: (inner as any).fuzzy,
117
- hideUnavailableItems: (inner as any).hideUnavailableItems ?? false,
118
- };
119
- }
120
-
121
- export default async function vtexProductListShelf(
122
- props: ProductListProps,
123
- ): Promise<Product[] | null> {
124
- try {
125
- const { query, count, sort, facetPath, fuzzy, hideUnavailableItems, ids } =
126
- resolveParams(props);
127
-
128
- const config = getVtexConfig();
129
- const locale = config.locale ?? "pt-BR";
130
-
131
- const params: Record<string, string> = {
132
- page: "1",
133
- count: String(count),
134
- locale,
135
- hideUnavailableItems: String(hideUnavailableItems),
136
- };
137
- if (query) params.query = query;
138
- if (sort) params.sort = sort;
139
- if (fuzzy) params.fuzzy = fuzzy;
140
-
141
- const endpoint = facetPath ? `/product_search/${facetPath}` : "/product_search/";
142
-
143
- const data = await intelligentSearch<{ products: ProductVTEX[] }>(endpoint, params);
144
-
145
- const vtexProducts = data.products ?? [];
146
- const baseUrl = storefrontBaseUrl(config);
147
-
148
- let products = vtexProducts.map((p) => {
149
- const fetchedSkus = ids ? new Set(ids) : null;
150
- const preferredSku = fetchedSkus
151
- ? (p.items.find((item) => fetchedSkus.has(item.itemId)) ?? pickSku(p))
152
- : pickSku(p);
153
- return toProductShelf(p, preferredSku, 0, {
154
- baseUrl,
155
- priceCurrency: "BRL",
156
- shelfCompleteVariants: props.completeVariants,
157
- keepImageNames: props.keepImageNames,
158
- });
159
- });
160
-
161
- if (ids) {
162
- products = sortProducts(products, ids, "sku");
163
- }
164
-
165
- return products;
166
- } catch (error) {
167
- console.error("[VTEX] ProductListShelf error:", error);
168
- return null;
169
- }
170
- }