@decocms/apps-vtex 8.0.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 (133) hide show
  1. package/package.json +7 -52
  2. package/src/index.ts +12 -15
  3. package/src/utils/constants.ts +2 -56
  4. package/src/utils/cookieSanitizer.ts +59 -59
  5. package/src/utils/operationRouter.ts +76 -72
  6. package/src/utils/types.ts +709 -1557
  7. package/src/vtexClient.ts +444 -0
  8. package/src/README.md +0 -6
  9. package/src/__tests__/client-segment-cookie.test.ts +0 -255
  10. package/src/__tests__/client-set-cookie-forward.test.ts +0 -257
  11. package/src/__tests__/schemas.test.ts +0 -71
  12. package/src/actions/address.ts +0 -250
  13. package/src/actions/analytics/sendEvent.ts +0 -86
  14. package/src/actions/auth.ts +0 -333
  15. package/src/actions/checkout.ts +0 -659
  16. package/src/actions/index.ts +0 -11
  17. package/src/actions/masterData.ts +0 -168
  18. package/src/actions/misc.ts +0 -188
  19. package/src/actions/newsletter.ts +0 -105
  20. package/src/actions/orders.ts +0 -34
  21. package/src/actions/profile.ts +0 -201
  22. package/src/actions/session.ts +0 -85
  23. package/src/actions/trigger.ts +0 -43
  24. package/src/actions/wishlist.ts +0 -114
  25. package/src/client.ts +0 -667
  26. package/src/commerceLoaders.ts +0 -267
  27. package/src/hooks/__tests__/createCart.render.test.ts +0 -114
  28. package/src/hooks/__tests__/createCart.test.ts +0 -92
  29. package/src/hooks/__tests__/createUseCart.test.ts +0 -184
  30. package/src/hooks/__tests__/createUseUser.test.ts +0 -48
  31. package/src/hooks/__tests__/createUseWishlist.test.ts +0 -87
  32. package/src/hooks/cartQuery.ts +0 -204
  33. package/src/hooks/createCart.ts +0 -427
  34. package/src/hooks/createUseCart.ts +0 -360
  35. package/src/hooks/createUseUser.ts +0 -153
  36. package/src/hooks/createUseWishlist.ts +0 -242
  37. package/src/hooks/index.ts +0 -25
  38. package/src/hooks/useAutocomplete.ts +0 -83
  39. package/src/hooks/useCart.ts +0 -243
  40. package/src/hooks/useUser.ts +0 -78
  41. package/src/hooks/useWishlist.ts +0 -119
  42. package/src/invoke.ts +0 -235
  43. package/src/loaders/ProductDetailsPage.ts +0 -1
  44. package/src/loaders/ProductList.ts +0 -1
  45. package/src/loaders/ProductListingPage.ts +0 -1
  46. package/src/loaders/address.ts +0 -115
  47. package/src/loaders/autocomplete.ts +0 -58
  48. package/src/loaders/brands.ts +0 -44
  49. package/src/loaders/cart/attachments.ts +0 -53
  50. package/src/loaders/cart/full.ts +0 -67
  51. package/src/loaders/cart/gifts.ts +0 -43
  52. package/src/loaders/cart/orderFormId.ts +0 -31
  53. package/src/loaders/cart/shipping.test.ts +0 -125
  54. package/src/loaders/cart/shipping.ts +0 -136
  55. package/src/loaders/cart/summary.ts +0 -36
  56. package/src/loaders/cart.ts +0 -52
  57. package/src/loaders/catalog.ts +0 -163
  58. package/src/loaders/collections.ts +0 -55
  59. package/src/loaders/index.ts +0 -20
  60. package/src/loaders/intelligentSearch/__tests__/productListingPage.test.ts +0 -51
  61. package/src/loaders/intelligentSearch/productDetailsPage.ts +0 -113
  62. package/src/loaders/intelligentSearch/productList.ts +0 -154
  63. package/src/loaders/intelligentSearch/productListingPage.ts +0 -526
  64. package/src/loaders/intelligentSearch/suggestions.ts +0 -46
  65. package/src/loaders/legacy/productDetailsPage.ts +0 -1
  66. package/src/loaders/legacy/productList.ts +0 -1
  67. package/src/loaders/legacy/relatedProductsLoader.ts +0 -81
  68. package/src/loaders/legacy.ts +0 -635
  69. package/src/loaders/logistics.ts +0 -111
  70. package/src/loaders/minicart.ts +0 -78
  71. package/src/loaders/navbar.ts +0 -26
  72. package/src/loaders/orders.ts +0 -92
  73. package/src/loaders/pageType.ts +0 -68
  74. package/src/loaders/paths/PDPDefaultPath.ts +0 -51
  75. package/src/loaders/payment.ts +0 -97
  76. package/src/loaders/productListFull.ts +0 -159
  77. package/src/loaders/profile.ts +0 -138
  78. package/src/loaders/promotion.ts +0 -30
  79. package/src/loaders/search.ts +0 -124
  80. package/src/loaders/session.ts +0 -83
  81. package/src/loaders/user.ts +0 -87
  82. package/src/loaders/wishlist.ts +0 -89
  83. package/src/loaders/wishlistProducts.ts +0 -69
  84. package/src/loaders/workflow/products.ts +0 -64
  85. package/src/loaders/workflow.ts +0 -316
  86. package/src/logo.png +0 -0
  87. package/src/manifest.gen.ts +0 -89
  88. package/src/middleware.ts +0 -240
  89. package/src/mod.ts +0 -157
  90. package/src/registry.ts +0 -9
  91. package/src/schemas.gen.ts +0 -3191
  92. package/src/schemas.ts +0 -30
  93. package/src/types.ts +0 -248
  94. package/src/utils/__tests__/cartProjection.test.ts +0 -118
  95. package/src/utils/__tests__/cookieSanitizer.test.ts +0 -162
  96. package/src/utils/__tests__/fetch.test.ts +0 -80
  97. package/src/utils/__tests__/fetchCache.test.ts +0 -155
  98. package/src/utils/__tests__/instrumentedFetch.test.ts +0 -158
  99. package/src/utils/__tests__/intelligentSearch.test.ts +0 -88
  100. package/src/utils/__tests__/minicart.test.ts +0 -184
  101. package/src/utils/__tests__/operationRouter.test.ts +0 -227
  102. package/src/utils/__tests__/resilience.test.ts +0 -205
  103. package/src/utils/__tests__/resourceRange.test.ts +0 -32
  104. package/src/utils/__tests__/simulationCache.test.ts +0 -40
  105. package/src/utils/__tests__/sitemap.test.ts +0 -185
  106. package/src/utils/__tests__/slugify.test.ts +0 -31
  107. package/src/utils/__tests__/transform.test.ts +0 -769
  108. package/src/utils/accountLoaders.ts +0 -203
  109. package/src/utils/authHelpers.ts +0 -85
  110. package/src/utils/batch.ts +0 -18
  111. package/src/utils/cartProjection.ts +0 -96
  112. package/src/utils/cookies.ts +0 -167
  113. package/src/utils/enrichment.ts +0 -560
  114. package/src/utils/fetch.ts +0 -107
  115. package/src/utils/fetchCache.ts +0 -199
  116. package/src/utils/index.ts +0 -19
  117. package/src/utils/instrumentedFetch.ts +0 -97
  118. package/src/utils/intelligentSearch.ts +0 -96
  119. package/src/utils/legacy.ts +0 -139
  120. package/src/utils/minicart.ts +0 -139
  121. package/src/utils/pickAndOmit.ts +0 -25
  122. package/src/utils/proxy.ts +0 -435
  123. package/src/utils/resilience.ts +0 -352
  124. package/src/utils/resourceRange.ts +0 -10
  125. package/src/utils/segment.ts +0 -152
  126. package/src/utils/similars.ts +0 -37
  127. package/src/utils/simulationCache.ts +0 -73
  128. package/src/utils/sitemap.ts +0 -282
  129. package/src/utils/slugCache.ts +0 -28
  130. package/src/utils/slugify.ts +0 -13
  131. package/src/utils/transform.ts +0 -1522
  132. package/src/utils/vtexId.ts +0 -138
  133. package/tsconfig.json +0 -7
@@ -1,67 +0,0 @@
1
- /**
2
- * `vtex/loaders/cart/full` — the drawer/minicart loader.
3
- *
4
- * Returns the full canonical `Minicart`, but requests only `SECTIONS_DRAWER`
5
- * from VTEX (not the legacy 15-section superset). Call it when the user opens
6
- * the cart drawer — not on every page view.
7
- *
8
- * Like the summary loader, a first-time visitor gets an empty `Minicart` shell
9
- * with no VTEX call.
10
- *
11
- * Registered in the app manifest as `vtex/loaders/cart/full`
12
- * (`invoke.vtex.loaders.cart.full`).
13
- */
14
-
15
- import type { Minicart } from "@decocms/apps-commerce/types";
16
- import { SECTIONS_DRAWER } from "@decocms/apps-commerce/types";
17
- import { getOrCreateCartV2 } from "../../actions/checkout";
18
- import type { OrderForm } from "../../types";
19
- import { resolveOrderFormId } from "./orderFormId";
20
-
21
- export interface CartFullProps {
22
- orderFormId?: string;
23
- /** Free-shipping threshold in major units. `0` disables the progress bar. */
24
- freeShippingTarget?: number;
25
- /** Override the OrderForm's locale (BCP-47, e.g. `"pt-BR"`). */
26
- locale?: string;
27
- /** Where the checkout button sends the user. Default: `/checkout`. */
28
- checkoutHref?: string;
29
- /** Whether the UI should expose the coupon input. Default: `true`. */
30
- enableCoupon?: boolean;
31
- }
32
-
33
- function emptyMinicart(props: CartFullProps): Minicart<OrderForm | null> {
34
- return {
35
- original: null,
36
- storefront: {
37
- items: [],
38
- subtotal: 0,
39
- discounts: 0,
40
- total: 0,
41
- locale: props.locale ?? "pt-BR",
42
- currency: "BRL",
43
- enableCoupon: props.enableCoupon ?? true,
44
- freeShippingTarget: props.freeShippingTarget ?? 0,
45
- checkoutHref: props.checkoutHref ?? "/checkout",
46
- },
47
- };
48
- }
49
-
50
- export default async function cartFull(
51
- props: CartFullProps = {},
52
- ): Promise<Minicart<OrderForm | null>> {
53
- const orderFormId = resolveOrderFormId(props.orderFormId);
54
- if (!orderFormId) return emptyMinicart(props);
55
-
56
- return (await getOrCreateCartV2({
57
- orderFormId,
58
- projection: "minicart",
59
- sections: SECTIONS_DRAWER,
60
- minicartOptions: {
61
- freeShippingTarget: props.freeShippingTarget,
62
- locale: props.locale,
63
- checkoutHref: props.checkoutHref,
64
- enableCoupon: props.enableCoupon,
65
- },
66
- })) as Minicart<OrderForm>;
67
- }
@@ -1,43 +0,0 @@
1
- /**
2
- * `vtex/loaders/cart/gifts` — selectable gifts + promotion teasers only.
3
- *
4
- * A focused read: fetches just the `ratesAndBenefitsData` (+ `items` so gift
5
- * eligibility resolves) and returns the gift-relevant slice, so a "you earned a
6
- * gift" UI does not have to load the whole cart. Empty for visitors with no
7
- * cart yet (no VTEX call).
8
- */
9
-
10
- import { getOrCreateCartV2 } from "../../actions/checkout";
11
- import type { OrderForm } from "../../types";
12
- import { resolveOrderFormId } from "./orderFormId";
13
-
14
- export interface CartGiftsProps {
15
- orderFormId?: string;
16
- }
17
-
18
- export interface CartGifts {
19
- orderFormId: string | null;
20
- /** VTEX `selectableGifts` — gifts the shopper can choose. */
21
- selectableGifts: unknown[];
22
- /** VTEX `ratesAndBenefitsData` — active promotions / teasers. */
23
- ratesAndBenefits: OrderForm["ratesAndBenefitsData"] | null;
24
- }
25
-
26
- const EMPTY: CartGifts = { orderFormId: null, selectableGifts: [], ratesAndBenefits: null };
27
-
28
- export default async function cartGifts(props: CartGiftsProps = {}): Promise<CartGifts> {
29
- const orderFormId = resolveOrderFormId(props.orderFormId);
30
- if (!orderFormId) return EMPTY;
31
-
32
- const orderForm = (await getOrCreateCartV2({
33
- orderFormId,
34
- projection: "raw",
35
- sections: ["items", "ratesAndBenefitsData", "messages"],
36
- })) as OrderForm;
37
-
38
- return {
39
- orderFormId: orderForm.orderFormId ?? null,
40
- selectableGifts: orderForm.selectableGifts ?? [],
41
- ratesAndBenefits: orderForm.ratesAndBenefitsData ?? null,
42
- };
43
- }
@@ -1,31 +0,0 @@
1
- /**
2
- * Read the current visitor's `orderFormId` from the request cookie.
3
- *
4
- * Shared by every Cart v2 loader. Returns `undefined` for first-time visitors
5
- * (no cart yet) — loaders MUST treat that as "empty, do not create" so a page
6
- * view never provisions a zero-item OrderForm on VTEX.
7
- */
8
-
9
- import { RequestContext } from "@decocms/blocks/sdk/requestContext";
10
-
11
- export const ORDER_FORM_COOKIE = "checkout.vtex.com__orderFormId";
12
-
13
- /** Extract `orderFormId` from the inbound request cookie header, if present. */
14
- export function readOrderFormIdFromRequest(cookieName = ORDER_FORM_COOKIE): string | undefined {
15
- const ctx = RequestContext.current;
16
- const cookieHeader = ctx?.request.headers.get("cookie");
17
- if (!cookieHeader) return undefined;
18
- const match = cookieHeader.match(new RegExp(`(?:^|;\\s*)${cookieName}=([^;]+)`));
19
- return match?.[1] ? decodeURIComponent(match[1]) : undefined;
20
- }
21
-
22
- /**
23
- * Resolve the orderFormId a loader should use: an explicit prop wins, else the
24
- * cookie. `undefined` means "no cart exists yet".
25
- */
26
- export function resolveOrderFormId(
27
- explicit?: string,
28
- cookieName = ORDER_FORM_COOKIE,
29
- ): string | undefined {
30
- return explicit ?? readOrderFormIdFromRequest(cookieName);
31
- }
@@ -1,125 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
- import { configureVtex } from "../../client";
3
-
4
- const simulateCartMock = vi.fn(async (props: any) => ({
5
- logisticsInfo: [{ slas: [{ id: "sla-1" }] }],
6
- echo: props,
7
- }));
8
-
9
- vi.mock("../../actions/checkout", () => ({
10
- simulateCart: (props: any) => simulateCartMock(props),
11
- }));
12
-
13
- import cartShipping, { getShippingSimulation } from "./shipping";
14
- import { __resetSimulationCacheForTests } from "../../utils/simulationCache";
15
-
16
- describe("getShippingSimulation (#373)", () => {
17
- beforeEach(() => {
18
- configureVtex({ account: "acme", salesChannel: "1" });
19
- __resetSimulationCacheForTests();
20
- simulateCartMock.mockClear();
21
- });
22
-
23
- afterEach(() => {
24
- __resetSimulationCacheForTests();
25
- });
26
-
27
- const props = {
28
- items: [{ id: "1", quantity: 1, seller: "1" }],
29
- postalCode: "01310-100",
30
- };
31
-
32
- it("calls simulateCart on a cache MISS and caches the response body", async () => {
33
- const result = await getShippingSimulation(props);
34
- expect(simulateCartMock).toHaveBeenCalledTimes(1);
35
- expect(result).toEqual({ logisticsInfo: [{ slas: [{ id: "sla-1" }] }], echo: expect.anything() });
36
- });
37
-
38
- it("serves the cached response on a second call with the same tuple — no 2nd simulateCart call", async () => {
39
- await getShippingSimulation(props);
40
- await getShippingSimulation(props);
41
- expect(simulateCartMock).toHaveBeenCalledTimes(1);
42
- });
43
-
44
- it("calls simulateCart again for a different postalCode (different cache key)", async () => {
45
- await getShippingSimulation(props);
46
- await getShippingSimulation({ ...props, postalCode: "20040-020" });
47
- expect(simulateCartMock).toHaveBeenCalledTimes(2);
48
- });
49
-
50
- it("calls simulateCart again for a different items composition", async () => {
51
- await getShippingSimulation(props);
52
- await getShippingSimulation({ ...props, items: [{ id: "2", quantity: 1, seller: "1" }] });
53
- expect(simulateCartMock).toHaveBeenCalledTimes(2);
54
- });
55
-
56
- it("is order-insensitive for the items array (same composition, different order)", async () => {
57
- const twoItems = {
58
- ...props,
59
- items: [
60
- { id: "1", quantity: 1, seller: "1" },
61
- { id: "2", quantity: 2, seller: "1" },
62
- ],
63
- };
64
- const reordered = {
65
- ...props,
66
- items: [
67
- { id: "2", quantity: 2, seller: "1" },
68
- { id: "1", quantity: 1, seller: "1" },
69
- ],
70
- };
71
- await getShippingSimulation(twoItems);
72
- await getShippingSimulation(reordered);
73
- expect(simulateCartMock).toHaveBeenCalledTimes(1);
74
- });
75
-
76
- it("varies the cache key by salesChannel (different sc → different simulation)", async () => {
77
- await getShippingSimulation(props);
78
- configureVtex({ account: "acme", salesChannel: "2" });
79
- await getShippingSimulation(props);
80
- expect(simulateCartMock).toHaveBeenCalledTimes(2);
81
- });
82
-
83
- it("the cached response never carries cookies — only the plain JSON body", async () => {
84
- const result = await getShippingSimulation(props);
85
- expect(result).not.toHaveProperty("headers");
86
- expect(JSON.stringify(result)).not.toContain("set-cookie");
87
- });
88
- });
89
-
90
- describe("cartShipping (drawer loader, built on getShippingSimulation)", () => {
91
- beforeEach(() => {
92
- configureVtex({ account: "acme", salesChannel: "1" });
93
- __resetSimulationCacheForTests();
94
- simulateCartMock.mockClear();
95
- });
96
-
97
- afterEach(() => {
98
- __resetSimulationCacheForTests();
99
- });
100
-
101
- const props = {
102
- items: [{ id: "1", quantity: 1, seller: "1" }],
103
- postalCode: "01310-100",
104
- };
105
-
106
- it("returns empty options when items or postalCode are missing", async () => {
107
- expect(await cartShipping({ items: [], postalCode: "" })).toEqual({
108
- postalCode: "",
109
- options: [],
110
- });
111
- });
112
-
113
- it("normalizes SLAs from the (cached) simulation into a de-duplicated option list", async () => {
114
- const result = await cartShipping(props);
115
- expect(result.postalCode).toBe(props.postalCode);
116
- expect(result.options).toHaveLength(1);
117
- expect(result.options[0].id).toBe("sla-1");
118
- });
119
-
120
- it("shares the underlying simulation cache — a second call does not re-simulate", async () => {
121
- await cartShipping(props);
122
- await cartShipping(props);
123
- expect(simulateCartMock).toHaveBeenCalledTimes(1);
124
- });
125
- });
@@ -1,136 +0,0 @@
1
- /**
2
- * Cached shipping simulation loader (#373).
3
- *
4
- * Wraps `simulateCart` (a POST to `/api/checkout/pub/orderForms/simulation`)
5
- * with a cache keyed only on the non-personalized inputs — items,
6
- * postalCode, country, and salesChannel. See `../../utils/simulationCache.ts`
7
- * for why this can't just be `vtexCachedFetch` (POST + cookie-rotation).
8
- *
9
- * On a cache MISS, `simulateCart` still goes through `vtexFetchWithCookies`
10
- * as normal — cookies rotate exactly as before. Only the response BODY
11
- * (SLAs + logistics info) is cached; cookies are never stored or replayed.
12
- */
13
- import { djb2 } from "@decocms/blocks/sdk/djb2";
14
- import { simulateCart, type SimulateCartProps, type SimulationItem } from "../../actions/checkout";
15
- import { getVtexConfig } from "../../client";
16
- import { getSimulationCache } from "../../utils/simulationCache";
17
-
18
- /** Shipping SLAs can shift with promotions/stock — keep the TTL short. */
19
- const DEFAULT_TTL_SECONDS = 5 * 60;
20
-
21
- export interface ShippingSimulationProps {
22
- items: SimulationItem[];
23
- postalCode: string;
24
- country?: string;
25
- /** Override the cache TTL (seconds). Defaults to 5 minutes. */
26
- ttlSeconds?: number;
27
- }
28
-
29
- function buildCacheKey(props: ShippingSimulationProps): string {
30
- const config = getVtexConfig();
31
- const normalizedItems = [...props.items]
32
- .map((item) => ({ id: String(item.id), quantity: item.quantity, seller: item.seller }))
33
- .sort((a, b) => (a.id === b.id ? a.seller.localeCompare(b.seller) : a.id.localeCompare(b.id)));
34
-
35
- const raw = JSON.stringify({
36
- account: config.account,
37
- salesChannel: config.salesChannel ?? null,
38
- items: normalizedItems,
39
- postalCode: props.postalCode,
40
- country: props.country ?? config.country ?? "BRA",
41
- });
42
- return `shipping-sim:${djb2(raw)}`;
43
- }
44
-
45
- /**
46
- * Fetch shipping SLAs for a cart, serving a cached response body when
47
- * available for the same `{items, postalCode, salesChannel}` tuple.
48
- */
49
- export async function getShippingSimulation(props: ShippingSimulationProps): Promise<any> {
50
- const cache = getSimulationCache();
51
- const key = buildCacheKey(props);
52
-
53
- const cached = await cache.get(key);
54
- if (cached != null) {
55
- try {
56
- return JSON.parse(cached);
57
- } catch {
58
- // Corrupted cache entry — fall through to a fresh simulation.
59
- }
60
- }
61
-
62
- const simulateProps: SimulateCartProps = {
63
- items: props.items,
64
- postalCode: props.postalCode,
65
- country: props.country,
66
- };
67
- const result = await simulateCart(simulateProps);
68
- await cache.put(key, JSON.stringify(result), props.ttlSeconds ?? DEFAULT_TTL_SECONDS);
69
- return result;
70
- }
71
-
72
- // ---------------------------------------------------------------------------
73
- // `vtex/loaders/cart/shipping` — normalized shipping options for the drawer
74
- // ---------------------------------------------------------------------------
75
- //
76
- // Runs a (cached) VTEX cart simulation for the given items + postal code and
77
- // returns a normalized, de-duplicated list of shipping SLAs (price in major
78
- // units). Separate from the cart mutation path so the drawer can show
79
- // delivery estimates without re-fetching the whole OrderForm. Built on
80
- // `getShippingSimulation` above instead of calling `simulateCart` directly,
81
- // so repeated drawer opens for the same {items, postalCode} share the cache.
82
-
83
- const CENTS_PER_MAJOR = 100;
84
-
85
- export interface CartShippingProps {
86
- items: SimulationItem[];
87
- postalCode: string;
88
- country?: string;
89
- }
90
-
91
- export interface ShippingOption {
92
- id: string;
93
- name: string;
94
- /** Price in major units. */
95
- price: number;
96
- shippingEstimate: string;
97
- deliveryChannel?: string;
98
- }
99
-
100
- export interface CartShipping {
101
- postalCode: string;
102
- options: ShippingOption[];
103
- }
104
-
105
- interface SimSla {
106
- id: string;
107
- name: string;
108
- price: number;
109
- shippingEstimate: string;
110
- deliveryChannel?: string;
111
- }
112
-
113
- export default async function cartShipping(props: CartShippingProps): Promise<CartShipping> {
114
- const { items, postalCode, country } = props;
115
- if (!items?.length || !postalCode) return { postalCode, options: [] };
116
-
117
- const sim = await getShippingSimulation({ items, postalCode, country });
118
- const logisticsInfo: Array<{ slas?: SimSla[] }> = sim?.logisticsInfo ?? [];
119
-
120
- // Collapse SLAs across all items into one unique-by-id option list.
121
- const byId = new Map<string, ShippingOption>();
122
- for (const info of logisticsInfo) {
123
- for (const sla of info.slas ?? []) {
124
- if (byId.has(sla.id)) continue;
125
- byId.set(sla.id, {
126
- id: sla.id,
127
- name: sla.name,
128
- price: (sla.price ?? 0) / CENTS_PER_MAJOR,
129
- shippingEstimate: sla.shippingEstimate,
130
- deliveryChannel: sla.deliveryChannel,
131
- });
132
- }
133
- }
134
-
135
- return { postalCode, options: [...byId.values()] };
136
- }
@@ -1,36 +0,0 @@
1
- /**
2
- * `vtex/loaders/cart/summary` — the badge loader.
3
- *
4
- * Returns the smallest useful cart shape: `{ orderFormId, totalItems, total }`.
5
- * For a first-time visitor (no orderFormId cookie) it returns an empty summary
6
- * **without touching VTEX** — this is the "don't create a cart on page load"
7
- * guarantee. Only visitors who already have a cart pay a checkout API call, and
8
- * that call requests just `items`+`totalizers` (via `SECTIONS_MINIMAL`).
9
- *
10
- * Registered in the app manifest as `vtex/loaders/cart/summary`, so it is
11
- * invoke-callable from the client (`invoke.vtex.loaders.cart.summary`) in both
12
- * Next.js and TanStack Start.
13
- */
14
-
15
- import type { CartSummary } from "@decocms/apps-commerce/types";
16
- import { SECTIONS_MINIMAL } from "@decocms/apps-commerce/types";
17
- import { getOrCreateCartV2 } from "../../actions/checkout";
18
- import { resolveOrderFormId } from "./orderFormId";
19
-
20
- export interface CartSummaryProps {
21
- /** Override the orderFormId; defaults to the request cookie. */
22
- orderFormId?: string;
23
- }
24
-
25
- const EMPTY_SUMMARY: CartSummary = { orderFormId: null, totalItems: 0, total: 0 };
26
-
27
- export default async function cartSummary(props: CartSummaryProps = {}): Promise<CartSummary> {
28
- const orderFormId = resolveOrderFormId(props.orderFormId);
29
- if (!orderFormId) return EMPTY_SUMMARY;
30
-
31
- return (await getOrCreateCartV2({
32
- orderFormId,
33
- projection: "summary",
34
- sections: SECTIONS_MINIMAL,
35
- })) as CartSummary;
36
- }
@@ -1,52 +0,0 @@
1
- /**
2
- * VTEX Cart (OrderForm) loader.
3
- * Pure async function — requires configureVtex() to have been called.
4
- *
5
- * Ported from deco-cx/apps:
6
- * vtex/loaders/cart.ts
7
- *
8
- * @see https://developers.vtex.com/docs/api-reference/checkout-api#get-/api/checkout/pub/orderForm
9
- */
10
-
11
- import { DEFAULT_EXPECTED_SECTIONS } from "../actions/checkout";
12
- import { getVtexConfig, vtexFetch } from "../client";
13
- import { forceHttpsOnAssets } from "../utils/transform";
14
- import type { OrderForm } from "../utils/types";
15
-
16
- /**
17
- * Fetch the current cart (OrderForm).
18
- *
19
- * When `orderFormId` is provided the existing cart is retrieved;
20
- * otherwise a fresh OrderForm is created via POST.
21
- *
22
- * @param orderFormId - Optional existing orderForm ID (from checkout cookie)
23
- * @param salesChannel - Optional sales channel override
24
- * @param authCookie - Optional cookie string for authenticated requests
25
- */
26
- export async function getCart(
27
- orderFormId?: string,
28
- opts?: { salesChannel?: string; authCookie?: string },
29
- ): Promise<OrderForm> {
30
- const { salesChannel } = getVtexConfig();
31
- const sc = opts?.salesChannel ?? salesChannel;
32
- const headers: Record<string, string> = {};
33
- if (opts?.authCookie) headers.cookie = opts.authCookie;
34
-
35
- const scParam = sc ? `?sc=${sc}` : "";
36
-
37
- const body = JSON.stringify({ expectedOrderFormSections: DEFAULT_EXPECTED_SECTIONS });
38
-
39
- const cart = orderFormId
40
- ? await vtexFetch<OrderForm>(`/api/checkout/pub/orderForm/${orderFormId}${scParam}`, {
41
- method: "POST",
42
- headers,
43
- body,
44
- })
45
- : await vtexFetch<OrderForm>(`/api/checkout/pub/orderForm${scParam}`, {
46
- method: "POST",
47
- headers,
48
- body,
49
- });
50
-
51
- return forceHttpsOnAssets(cart);
52
- }
@@ -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
- }