@decocms/apps-magento 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 (39) hide show
  1. package/package.json +10 -22
  2. package/src/index.ts +1 -28
  3. package/src/README.md +0 -65
  4. package/src/__tests__/cart.test.ts +0 -139
  5. package/src/__tests__/client.test.ts +0 -252
  6. package/src/__tests__/features.test.ts +0 -51
  7. package/src/__tests__/graphql.test.ts +0 -183
  8. package/src/__tests__/magentoClient.test.ts +0 -166
  9. package/src/__tests__/newsletter-subscribe.test.ts +0 -86
  10. package/src/__tests__/product-stockAlert.test.ts +0 -80
  11. package/src/__tests__/stringifySearchCriteria.test.ts +0 -56
  12. package/src/__tests__/transform.test.ts +0 -346
  13. package/src/__tests__/user-loader.test.ts +0 -134
  14. package/src/__tests__/wishlist-actions.test.ts +0 -140
  15. package/src/__tests__/wishlist-loader.test.ts +0 -97
  16. package/src/actions/newsletter/subscribe.ts +0 -40
  17. package/src/actions/product/stockAlert.ts +0 -67
  18. package/src/actions/wishlist/addItem.ts +0 -57
  19. package/src/actions/wishlist/removeItem.ts +0 -59
  20. package/src/client.ts +0 -252
  21. package/src/loaders/cart.ts +0 -64
  22. package/src/loaders/features.ts +0 -16
  23. package/src/loaders/user.ts +0 -60
  24. package/src/loaders/wishlist.ts +0 -29
  25. package/src/middleware.ts +0 -19
  26. package/src/types.ts +0 -51
  27. package/src/utils/__tests__/instrumentation.test.ts +0 -59
  28. package/src/utils/cacheTimeControl.ts +0 -69
  29. package/src/utils/client/types.ts +0 -270
  30. package/src/utils/constants.ts +0 -126
  31. package/src/utils/fetchCache.ts +0 -55
  32. package/src/utils/graphql-types.ts +0 -99
  33. package/src/utils/graphql.ts +0 -155
  34. package/src/utils/instrumentedFetch.ts +0 -57
  35. package/src/utils/operationRouter.ts +0 -43
  36. package/src/utils/stringifySearchCriteria.ts +0 -62
  37. package/src/utils/transform.ts +0 -283
  38. package/src/utils/user.ts +0 -16
  39. package/tsconfig.json +0 -7
@@ -1,60 +0,0 @@
1
- /**
2
- * Resolves the current customer into a schema.org `Person` from
3
- * Magento's `/customer/section/load?sections=customer,carbono-customer`
4
- * endpoint, scoped by the visitor's PHPSESSID cookie.
5
- *
6
- * Ported from `deco-cx/apps/magento/loaders/user.ts`. The Fresh
7
- * version used `clientAdmin["GET /:site/customer/section/load"]` with
8
- * typed indexed routes — the TanStack/Node port uses `magentoFetch`
9
- * (which already applies auth/origin headers for same-origin) plus an
10
- * explicit `Cookie: PHPSESSID=…` header so Magento associates the
11
- * request with the logged-in customer.
12
- *
13
- * Returns null when:
14
- * - the session cookie is absent (anonymous visitor — expected),
15
- * - the customer slice is missing or has no data_id (Magento returns
16
- * {} for guest sessions),
17
- * - the HTTP call throws or returns a non-2xx (defensive — the
18
- * storefront just renders the logged-out UI).
19
- */
20
- import type { Person } from "@decocms/apps-commerce/types";
21
- import { getMagentoConfig, magentoFetch } from "../client";
22
- import type { CustomerSectionLoad } from "../utils/client/types";
23
- import { SESSION_COOKIE } from "../utils/constants";
24
- import { getUserCookie } from "../utils/user";
25
-
26
- export default async function user(_props: unknown, req: Request): Promise<Person | null> {
27
- const sessionId = getUserCookie(req.headers);
28
- if (!sessionId) return null;
29
-
30
- const { site } = getMagentoConfig();
31
- const path = `/${encodeURIComponent(site)}/customer/section/load?sections=customer,carbono-customer`;
32
-
33
- try {
34
- const res = await magentoFetch(path, {
35
- headers: { Cookie: `${SESSION_COOKIE}=${sessionId}` },
36
- });
37
- if (!res.ok) return null;
38
-
39
- const response = (await res.json()) as CustomerSectionLoad;
40
- const carbono = response["carbono-customer"];
41
- const customer = response.customer;
42
-
43
- if (!carbono?.data_id || !customer) return null;
44
-
45
- const { customerId, email } = carbono;
46
- const { fullname, firstname } = customer;
47
-
48
- return {
49
- "@id": customerId,
50
- email: email,
51
- givenName: firstname,
52
- ...(firstname &&
53
- fullname && {
54
- familyName: fullname.replace(firstname, "").trim(),
55
- }),
56
- };
57
- } catch {
58
- return null;
59
- }
60
- }
@@ -1,29 +0,0 @@
1
- /**
2
- * Resolves the visitor's saved wishlist via Magento's
3
- * `/customer/section/load?sections=wishlist` endpoint, scoped by the
4
- * PHPSESSID cookie.
5
- *
6
- * Ported from `deco-cx/apps/magento/loaders/wishlist.ts`. Returns null
7
- * when the session cookie is absent or Magento reports no wishlist
8
- * (e.g. a logged-in customer who never saved an item).
9
- */
10
- import { getMagentoConfig, magentoFetch } from "../client";
11
- import type { CustomerSectionLoad, Wishlist } from "../utils/client/types";
12
- import { SESSION_COOKIE } from "../utils/constants";
13
- import { getUserCookie } from "../utils/user";
14
-
15
- export default async function wishlist(_props: unknown, req: Request): Promise<Wishlist | null> {
16
- const sessionId = getUserCookie(req.headers);
17
- if (!sessionId) return null;
18
-
19
- const { site } = getMagentoConfig();
20
- const path = `/${encodeURIComponent(site)}/customer/section/load?sections=wishlist`;
21
-
22
- const res = await magentoFetch(path, {
23
- headers: { Cookie: `${SESSION_COOKIE}=${sessionId}` },
24
- });
25
- if (!res.ok) return null;
26
-
27
- const { wishlist } = (await res.json()) as CustomerSectionLoad;
28
- return wishlist ?? null;
29
- }
package/src/middleware.ts DELETED
@@ -1,19 +0,0 @@
1
- /**
2
- * Magento middleware — currently a passthrough.
3
- *
4
- * The legacy deco-cx/apps middleware reconciled the cart id cookie
5
- * after checkout (`changeCardIdAfterCheckout`) and seeded the
6
- * `form_key` for anonymous sessions. Both flows touched response
7
- * headers and `customer/section/load` endpoints — non-trivial port,
8
- * deferred to a follow-up PR. Today a production Magento storefront
9
- * handles cart reconciliation on the client.
10
- *
11
- * Shape matches `@decocms/apps-commerce/app-types` so it can be
12
- * plugged into the autoconfig pipeline once magento is registered
13
- * there.
14
- */
15
- import type { AppMiddleware } from "@decocms/apps-commerce/app-types";
16
-
17
- export const magentoMiddleware: AppMiddleware = async (_request, next) => {
18
- return next();
19
- };
package/src/types.ts DELETED
@@ -1,51 +0,0 @@
1
- /**
2
- * Shared types for the Magento app — kept minimal in this initial port.
3
- * Loader/action ports should extend this file rather than duplicating
4
- * inline types.
5
- */
6
- import type { MagentoFeatures } from "./client";
7
-
8
- export interface MagentoCart {
9
- id: string | null;
10
- items: MagentoCartItem[];
11
- totals?: {
12
- subtotal?: number;
13
- grand_total?: number;
14
- discount_amount?: number;
15
- shipping_amount?: number;
16
- };
17
- coupon_code?: string | null;
18
- }
19
-
20
- export interface MagentoCartItem {
21
- item_id: number;
22
- sku: string;
23
- name?: string;
24
- qty: number;
25
- price?: number;
26
- row_total?: number;
27
- }
28
-
29
- export type Features = MagentoFeatures;
30
-
31
- /**
32
- * Magento newsletter subscription response shape — what
33
- * `actions/newsletter/subscribe` returns to the storefront.
34
- */
35
- export interface NewsletterData {
36
- success: boolean;
37
- message: string;
38
- }
39
-
40
- /**
41
- * Stock-alert mutation response from Magento's GraphQL endpoint —
42
- * `actions/product/stockAlert` returns this (or `{ error }`).
43
- */
44
- export interface ProductStockAlertResponse {
45
- data?: {
46
- productStockAlert: {
47
- message: string;
48
- status: boolean;
49
- };
50
- };
51
- }
@@ -1,59 +0,0 @@
1
- /**
2
- * Coverage for the Magento observability wiring added so cache/upstream
3
- * telemetry flows automatically:
4
- * - `magentoOperationRouter` names REST resources + GraphQL.
5
- * - `setMagentoFetch` actually reroutes `magentoFetch`'s egress (the hook
6
- * that lets `createMagentoFetch()`'s instrumentation take effect).
7
- */
8
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
9
- import { magentoOperationRouter } from "../operationRouter";
10
-
11
- describe("magentoOperationRouter", () => {
12
- it("names REST resources by their first V1 segment", () => {
13
- expect(magentoOperationRouter("https://x.com/rest/default/V1/products/42", "GET")).toBe(
14
- "rest.products",
15
- );
16
- expect(magentoOperationRouter("https://x.com/rest/V1/carts/mine", "POST")).toBe("rest.carts");
17
- });
18
-
19
- it("names GraphQL calls `graphql`", () => {
20
- expect(magentoOperationRouter("https://x.com/graphql", "POST")).toBe("graphql");
21
- });
22
-
23
- it("returns undefined when nothing matches (framework falls back)", () => {
24
- expect(magentoOperationRouter("https://x.com/media/logo.png", "GET")).toBeUndefined();
25
- });
26
-
27
- it("tolerates non-absolute URLs", () => {
28
- expect(magentoOperationRouter("/rest/default/V1/orders?x=1", "GET")).toBe("rest.orders");
29
- });
30
- });
31
-
32
- describe("setMagentoFetch routing", () => {
33
- beforeEach(() => {
34
- vi.resetModules();
35
- });
36
- afterEach(() => {
37
- vi.restoreAllMocks();
38
- });
39
-
40
- it("routes magentoFetch egress through the fetch set via setMagentoFetch", async () => {
41
- const { configureMagento, setMagentoFetch, magentoFetch } = await import("../../client");
42
- configureMagento({
43
- baseUrl: "https://loja.example.com/",
44
- apiKey: "k",
45
- storeId: 1,
46
- site: "example",
47
- });
48
- const custom = vi
49
- .fn()
50
- .mockResolvedValue(new Response("{}", { status: 200 })) as unknown as typeof fetch;
51
- const globalSpy = vi.spyOn(globalThis, "fetch");
52
- setMagentoFetch(custom);
53
-
54
- await magentoFetch("/rest/default/V1/products/1");
55
-
56
- expect(custom).toHaveBeenCalledOnce();
57
- expect(globalSpy).not.toHaveBeenCalled(); // did NOT hit the default fetch
58
- });
59
- });
@@ -1,69 +0,0 @@
1
- /**
2
- * Cache-time-control helpers — verbatim port of
3
- * `deco-cx/apps/magento/utils/cacheTimeControl.ts`.
4
- *
5
- * Magento product loaders pass the request URL through
6
- * `filterSearchParamsFromURL` before using it as a cache key, so that
7
- * tracking parameters (utm_*, gclid, fbclid, etc.) don't fragment the
8
- * cache across thousands of variants for what is conceptually the
9
- * same page.
10
- */
11
-
12
- export const DEFAULT_CACHE_MAX_AGE = 3600; // 1h
13
-
14
- /**
15
- * Pattern list (each entry is a regex source) of URL search-param
16
- * keys that get stripped before a Magento URL goes into the cache key
17
- * or downstream search-criteria. Mirrors prod byte-for-byte — the
18
- * `.*` suffixes intentionally match `utm_source`, `utm_medium`, etc.
19
- */
20
- export const SEARCH_PARAMS_TO_IGNORE = [
21
- "gclid",
22
- "gbraid",
23
- "gdftrk",
24
- "_ga",
25
- "mc_.*",
26
- "trk_.*",
27
- "utm_.*",
28
- "sc_.*",
29
- "dm_i",
30
- "_ke",
31
- "fbclid",
32
- "qitc",
33
- "queryID",
34
- "indexName",
35
- "objectID",
36
- "utm_source",
37
- "utm_medium",
38
- "utm_campaign",
39
- "gad_.*",
40
- ];
41
-
42
- /**
43
- * Filter an array of [key, value] pairs, dropping any whose key matches
44
- * one of the `SEARCH_PARAMS_TO_IGNORE` regex patterns. Pure function so
45
- * callers can sort/transform after.
46
- */
47
- export const filterSearchParams = (params: [string, string][]): [string, string][] => {
48
- return params.filter(
49
- ([key]) => !SEARCH_PARAMS_TO_IGNORE.find((matchKey) => new RegExp(matchKey).test(key)),
50
- );
51
- };
52
-
53
- /**
54
- * Strip the tracking params from a URL (or URL string) and return the
55
- * cleaned `href`. Used by Magento PDP/PLP loaders as the cache key
56
- * basis so cache lookups don't depend on the visitor's referer chain.
57
- */
58
- export const filterSearchParamsFromURL = (defaultURL: string | URL): string => {
59
- const url = new URL(defaultURL);
60
- const paramsArray = Array.from(url.searchParams.entries());
61
- const filteredParams = filterSearchParams(paramsArray);
62
-
63
- url.search = "";
64
- for (const [key, value] of filteredParams) {
65
- url.searchParams.append(key, value);
66
- }
67
-
68
- return url.href;
69
- };
@@ -1,270 +0,0 @@
1
- /**
2
- * Magento REST API response shapes — the subset of types from
3
- * `deco-cx/apps/magento/utils/client/types.ts` that the port has
4
- * reached so far. Extended as more loaders/actions land.
5
- *
6
- * Keep field names **exactly** as Magento returns them (mostly
7
- * snake_case, occasional camelCase from carbono-customer). Consumer
8
- * sites already render against these shapes — any rename is a
9
- * breaking change at the storefront, not just the API boundary.
10
- */
11
-
12
- // ---------------------------------------------------------------------------
13
- // Customer / user section payloads (added by the user+wishlist port)
14
- // ---------------------------------------------------------------------------
15
-
16
- /**
17
- * `customer` slice of `/customer/section/load?sections=customer,…`.
18
- * Magento returns this on every authenticated section call.
19
- */
20
- export interface Customer {
21
- data_id: number;
22
- fullname?: string;
23
- firstname?: string;
24
- }
25
-
26
- /**
27
- * `carbono-customer` slice. A storefront-specific overlay that mirrors the
28
- * `customer` slice plus a website/store id pair and a normalized email.
29
- * Other magento sites that don't run the Carbono module will get this
30
- * absent; loaders/user.ts checks for it before mapping to a Person.
31
- */
32
- export interface CarbonoCustomer {
33
- websiteId?: string;
34
- email?: string;
35
- customerId?: string;
36
- data_id: number;
37
- }
38
-
39
- /**
40
- * `cart` slice of the customer section bundle — minimal projection of
41
- * the cart that the minicart island renders before the full cart loader
42
- * has resolved. Not the same as the full Cart payload from
43
- * `/V1/carts/:cartId` (which lives in MagentoCart in types.ts).
44
- */
45
- export interface CartUser {
46
- summary_count: number;
47
- subtotalAmount: number | null;
48
- subtotal: string;
49
- possible_onepage_checkout: boolean;
50
- items: [];
51
- isGuestCheckoutAllowed: boolean;
52
- website_id: string;
53
- storeId: string;
54
- adyen_payment_methods: unknown[];
55
- extra_actions: string;
56
- cart_empty_message: string;
57
- subtotal_incl_tax: string;
58
- subtotal_excl_tax: string;
59
- mpFSBCartTotal: unknown | null;
60
- data_id: number;
61
- minicart_improvements: MinicartImprovements;
62
- }
63
-
64
- export interface MinicartImprovements {
65
- coupon_code: string | null;
66
- country_id: string;
67
- api_base_url: string;
68
- is_logged_in: boolean;
69
- quote_id: string;
70
- base_url: string;
71
- }
72
-
73
- /**
74
- * Bundle shape returned by
75
- * `GET /:site/customer/section/load?sections=customer,carbono-customer,wishlist,…`.
76
- * Keys are optional because the caller picks which sections to request.
77
- */
78
- export interface CustomerSectionLoad {
79
- customer?: Customer;
80
- "carbono-customer"?: CarbonoCustomer;
81
- cart?: CartUser;
82
- wishlist?: Wishlist;
83
- }
84
-
85
- // ---------------------------------------------------------------------------
86
- // Wishlist payloads
87
- // ---------------------------------------------------------------------------
88
-
89
- export interface Wishlist {
90
- counter: string;
91
- items: WishlistItem[];
92
- counter_number: number;
93
- data_id: number;
94
- }
95
-
96
- export interface WishlistItem {
97
- image: WishlistItemImage;
98
- product_sku: string;
99
- product_id: string;
100
- product_url: string;
101
- product_name: string;
102
- product_price: string;
103
- product_is_saleable_and_visible: boolean;
104
- product_has_required_options: boolean;
105
- add_to_cart_params: string;
106
- delete_item_params: string;
107
- }
108
-
109
- export interface WishlistItemImage {
110
- template: string;
111
- src: string;
112
- width: number;
113
- height: number;
114
- alt: string;
115
- }
116
-
117
- // ---------------------------------------------------------------------------
118
- // Shared attribute/category shapes (added by the transform port)
119
- // ---------------------------------------------------------------------------
120
-
121
- export interface CustomAttribute {
122
- attribute_code: string;
123
- value: string | string[];
124
- }
125
-
126
- export interface CategoryLink {
127
- position: number;
128
- category_id: string;
129
- }
130
-
131
- export interface MagentoCategory {
132
- id: number;
133
- parent_id: number;
134
- name: string;
135
- is_active: boolean;
136
- position: number;
137
- level: number;
138
- children: string;
139
- created_at: string;
140
- updated_at: string;
141
- path: string;
142
- include_in_menu: boolean;
143
- custom_attributes: CustomAttribute[];
144
- }
145
-
146
- // ---------------------------------------------------------------------------
147
- // Product detail shapes (used by PDP / PLP / list loaders)
148
- // ---------------------------------------------------------------------------
149
-
150
- export interface MagentoPriceInfo {
151
- final_price: number;
152
- max_price: number;
153
- max_regular_price: number;
154
- minimal_regular_price: number;
155
- special_price: number | null;
156
- minimal_price: number;
157
- regular_price: number;
158
- formatted_prices: {
159
- final_price: string;
160
- max_price: string;
161
- minimal_price: string;
162
- max_regular_price: string;
163
- minimal_regular_price: string | null;
164
- special_price: string | null;
165
- regular_price: string;
166
- };
167
- extension_attributes: {
168
- msrp: {
169
- msrp_price: string;
170
- is_applicable: string;
171
- is_shown_price_on_gesture: string;
172
- msrp_message: string;
173
- explanation_message: string;
174
- };
175
- tax_adjustments: {
176
- final_price: number;
177
- max_price: number;
178
- max_regular_price: number;
179
- minimal_regular_price: number;
180
- special_price: number;
181
- minimal_price: number;
182
- regular_price: number;
183
- formatted_prices: {
184
- final_price: string;
185
- max_price: string;
186
- minimal_price: string;
187
- max_regular_price: string;
188
- minimal_regular_price: string | null;
189
- special_price: string;
190
- regular_price: string;
191
- };
192
- };
193
- weee_attributes: unknown[];
194
- weee_adjustment: string;
195
- };
196
- }
197
-
198
- export interface MagentoStock {
199
- item_id: number;
200
- product_id: number;
201
- stock_id: number;
202
- qty?: number;
203
- is_in_stock?: boolean;
204
- is_qty_decimal?: boolean;
205
- show_default_notification_message?: boolean;
206
- use_config_min_qty?: boolean;
207
- min_qty?: number;
208
- use_config_min_sale_qty?: boolean;
209
- min_sale_qty?: number;
210
- use_config_max_sale_qty?: boolean;
211
- max_sale_qty?: number;
212
- use_config_backorders?: boolean;
213
- backorders?: number;
214
- use_config_notify_stock_qty?: boolean;
215
- notify_stock_qty?: number;
216
- use_config_qty_increments?: boolean;
217
- qty_increments?: number;
218
- use_config_enable_qty_inc?: boolean;
219
- enable_qty_increments?: boolean;
220
- use_config_manage_stock?: boolean;
221
- manage_stock?: boolean;
222
- low_stock_date?: string | null;
223
- is_decimal_divided?: boolean;
224
- stock_status_changed_auto?: number;
225
- }
226
-
227
- export interface MagentoImage {
228
- url: string;
229
- code: string;
230
- height: number;
231
- width: number;
232
- label: string;
233
- resized_width: number;
234
- resized_height: number;
235
- disabled: boolean;
236
- }
237
-
238
- export interface MediaEntry {
239
- id: number;
240
- media_type: string;
241
- label: string | null;
242
- position: number;
243
- disabled: boolean;
244
- types: string[];
245
- file: string;
246
- }
247
-
248
- export interface MagentoProduct {
249
- id: number;
250
- sku: string;
251
- name: string;
252
- price: number;
253
- status: number;
254
- visibility: number;
255
- type_id: string;
256
- created_at: string;
257
- updated_at: string;
258
- weight: number;
259
- url: string;
260
- extension_attributes: {
261
- website_ids?: number[];
262
- category_links: CategoryLink[];
263
- stock_item?: MagentoStock;
264
- };
265
- custom_attributes: CustomAttribute[];
266
- price_info?: MagentoPriceInfo;
267
- currency_code?: string;
268
- images?: MagentoImage[];
269
- media_gallery_entries?: MediaEntry[];
270
- }
@@ -1,126 +0,0 @@
1
- /**
2
- * Magento constants — ported verbatim from
3
- * `deco-cx/apps/magento/utils/constants.ts`.
4
- *
5
- * Keep this file boring and append-only. Magento's REST and GraphQL
6
- * payloads rely on these identifiers as-is (URL_KEY for PDP slug
7
- * matching, GRAND_TOTAL/SUBTOTAL/… for the totals composition that
8
- * cart.ts pulls, IN_STOCK/OUT_OF_STOCK for schema.org availability).
9
- * Mutating any of these values would silently break consumer sites
10
- * that already render against them.
11
- */
12
-
13
- import type { FiltersGraphQL } from "../client";
14
-
15
- // ---------------------------------------------------------------------------
16
- // SWR fetch-cache tuning (consumed by utils/fetchCache.ts via the shared
17
- // `createFetchCache` in @decocms/blocks/sdk/fetchCache). Mirrors the shape of
18
- // VTEX's constants so Magento's cache posture is tuned in one place.
19
- // ---------------------------------------------------------------------------
20
-
21
- /** Max distinct cache keys kept in memory; oldest `createdAt` evicted first. */
22
- export const FETCH_CACHE_MAX_ENTRIES = 500;
23
-
24
- /** How long a cached Magento response stays FRESH, keyed by status class. */
25
- export const FETCH_CACHE_FRESH_TTL_MS = {
26
- /** 2xx — 3 min. Catalog/price data doesn't need to be second-fresh. */
27
- success: 180_000,
28
- /** 404 — 10s. A just-published product shouldn't 404 for long. */
29
- notFound: 10_000,
30
- /** 5xx — never treated as a good cache hit. */
31
- serverError: 0,
32
- } as const;
33
-
34
- /** Stale-if-error window: serve last-good this long past freshness on outage. */
35
- export const FETCH_CACHE_STALE_IF_ERROR_MS = 86_400_000; // 24h
36
-
37
- /** Inflight-slot backstop: bounds how long one hung fetch holds a dedup slot. */
38
- export const FETCH_CACHE_INFLIGHT_BACKSTOP_MS = 15_000;
39
-
40
- export const URL_KEY = "url_key";
41
-
42
- // Schema.org availability mapping (used by utils/transform.ts to
43
- // produce Offer.availability — kept here so transform doesn't import
44
- // schema.org strings as magic literals).
45
- export const IN_STOCK = "https://schema.org/InStock";
46
- export const OUT_OF_STOCK = "https://schema.org/OutOfStock";
47
-
48
- // Rating bounds used by `utils/transform.ts` (and the review/rating
49
- // loaders that follow) when mapping Magento's integer-rating scale
50
- // into schema.org `AggregateRating`'s 1–5 range.
51
- export const MAX_RATING_VALUE = 5;
52
- export const MIN_RATING_VALUE = 1;
53
-
54
- /**
55
- * Default filter mapping consumed by `utils/graphql.ts:filtersFromUrlGraphQL`.
56
- * Each entry pairs a Magento attribute slug with the comparison operator
57
- * the storefront's URL filters use. Sites can extend this via the
58
- * `customFilters` prop on PLP/list loaders without forking the array.
59
- */
60
- export const DEFAULT_GRAPHQL_FILTERS: FiltersGraphQL[] = [
61
- { value: "activity", type: "EQUAL" },
62
- { value: "category_gear", type: "EQUAL" },
63
- { value: "category_id", type: "EQUAL" },
64
- { value: "category_uid", type: "EQUAL" },
65
- { value: "category_url_path", type: "EQUAL" },
66
- { value: "climate", type: "EQUAL" },
67
- { value: "collar", type: "EQUAL" },
68
- { value: "color", type: "EQUAL" },
69
- { value: "description", type: "MATCH" },
70
- { value: "eco_collection", type: "EQUAL" },
71
- { value: "erin_recommends", type: "EQUAL" },
72
- { value: "features_bags", type: "EQUAL" },
73
- { value: "format", type: "EQUAL" },
74
- { value: "gender", type: "EQUAL" },
75
- { value: "material", type: "EQUAL" },
76
- { value: "name", type: "MATCH" },
77
- { value: "new", type: "EQUAL" },
78
- { value: "pattern", type: "EQUAL" },
79
- { value: "performance_fabric", type: "EQUAL" },
80
- { value: "price", type: "RANGE" },
81
- { value: "purpose", type: "EQUAL" },
82
- { value: "sale", type: "EQUAL" },
83
- { value: "short_description", type: "MATCH" },
84
- { value: "size", type: "EQUAL" },
85
- { value: "sku", type: "EQUAL" },
86
- { value: "sleeve", type: "EQUAL" },
87
- { value: "strap_bags", type: "EQUAL" },
88
- { value: "style_bags", type: "EQUAL" },
89
- { value: "style_bottom", type: "EQUAL" },
90
- { value: "style_general", type: "EQUAL" },
91
- { value: "url_key", type: "EQUAL" },
92
- ];
93
-
94
- /**
95
- * Query-string keys that should be stripped before forwarding a request
96
- * URL to Magento (e.g. when computing a cache key or building a
97
- * paginated request). Mirrors the Fresh-era REMOVABLE_URL_SEARCHPARAMS.
98
- */
99
- export const REMOVABLE_URL_SEARCHPARAMS = ["p", "product_list_order"];
100
-
101
- // ---------------------------------------------------------------------------
102
- // Cart totals composition — field names sent to Magento's
103
- // /V1/carts/:cartId/totals?fields=… endpoint. The cart loader joins
104
- // these into the `fields` query param to keep the response narrow.
105
- // ---------------------------------------------------------------------------
106
-
107
- export const GRAND_TOTAL = "grand_total";
108
- export const SUBTOTAL = "subtotal";
109
- export const DISCOUNT_AMOUNT = "discount_amount";
110
- export const BASE_DISCOUNT_AMOUNT = "base_discount_amount";
111
- export const SHIPPING_AMOUNT = "shipping_amount";
112
- export const BASE_SHIPPING_AMOUNT = "base_shipping_amount";
113
- export const SHIPPING_DISCOUNT_AMOUNT = "shipping_discount_amount";
114
- export const COUPON_CODE = "coupon_code";
115
- export const BASE_CURRENCY_CODE = "base_currency_code";
116
-
117
- // ---------------------------------------------------------------------------
118
- // Cookie names — single source of truth so loaders/actions/middleware
119
- // don't drift on string literals (Magento is case-sensitive about
120
- // these and a typo produces a silent anonymous-session bug).
121
- // ---------------------------------------------------------------------------
122
-
123
- export const SESSION_COOKIE = "PHPSESSID";
124
- export const CUSTOMER_COOKIE = "dataservices_customer_id";
125
- export const CART_COOKIE = "dataservices_cart_id";
126
- export const FORM_KEY_COOKIE = "form_key";