@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
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@decocms/apps-vtex",
3
- "version": "8.1.0-next.0",
3
+ "version": "8.1.0-next.1",
4
4
  "type": "module",
5
- "description": "Deco commerce app: VTEX integration",
5
+ "description": "Thin VTEX API client for Deco sites",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/decocms/blocks.git",
@@ -10,67 +10,22 @@
10
10
  },
11
11
  "files": [
12
12
  "src",
13
- "tsconfig.json"
13
+ "!src/**/*.test.ts",
14
+ "!src/**/__tests__"
14
15
  ],
15
16
  "main": "./src/index.ts",
16
17
  "exports": {
17
- ".": "./src/index.ts",
18
- "./commerceLoaders": "./src/commerceLoaders.ts",
19
- "./mod": "./src/mod.ts",
20
- "./schemas": "./src/schemas.ts",
21
- "./client": "./src/client.ts",
22
- "./types": "./src/types.ts",
23
- "./actions": "./src/actions/index.ts",
24
- "./actions/*": "./src/actions/*.ts",
25
- "./actions/analytics/*": "./src/actions/analytics/*.ts",
26
- "./loaders": "./src/loaders/index.ts",
27
- "./loaders/*": "./src/loaders/*.ts",
28
- "./utils": "./src/utils/index.ts",
29
- "./utils/*": "./src/utils/*.ts",
30
- "./loaders/intelligentSearch/*": "./src/loaders/intelligentSearch/*.ts",
31
- "./loaders/legacy/*": "./src/loaders/legacy/*.ts",
32
- "./loaders/workflow/*": "./src/loaders/workflow/*.ts",
33
- "./inline-loaders/productDetailsPage": "./src/loaders/intelligentSearch/productDetailsPage.ts",
34
- "./inline-loaders/productListingPage": "./src/loaders/intelligentSearch/productListingPage.ts",
35
- "./inline-loaders/productList": "./src/loaders/productListFull.ts",
36
- "./inline-loaders/productListShelf": "./src/loaders/intelligentSearch/productList.ts",
37
- "./inline-loaders/relatedProducts": "./src/loaders/legacy/relatedProductsLoader.ts",
38
- "./inline-loaders/suggestions": "./src/loaders/intelligentSearch/suggestions.ts",
39
- "./inline-loaders/minicart": "./src/loaders/minicart.ts",
40
- "./inline-loaders/workflowProducts": "./src/loaders/workflow/products.ts",
41
- "./hooks": "./src/hooks/index.ts",
42
- "./hooks/*": "./src/hooks/*.ts",
43
- "./middleware": "./src/middleware.ts",
44
- "./registry": "./src/registry.ts"
18
+ ".": "./src/index.ts"
45
19
  },
46
20
  "scripts": {
47
21
  "build": "tsc",
48
- "generate:schemas": "bun ../blocks-cli/scripts/generate-app-schemas.ts",
49
22
  "test": "vitest run --root ../.. packages/apps-vtex/",
50
- "typecheck": "tsc --noEmit",
51
- "lint:unused": "knip"
23
+ "typecheck": "tsc --noEmit"
52
24
  },
53
25
  "dependencies": {
54
- "@decocms/blocks": "8.1.0-next.0",
55
- "@decocms/apps-commerce": "8.1.0-next.0",
56
- "@decocms/apps-website": "8.1.0-next.0",
57
- "@decocms/tanstack": "8.1.0-next.0"
58
- },
59
- "peerDependencies": {
60
- "@tanstack/react-query": ">=5.0.0",
61
- "react": "^19.0.0",
62
- "react-dom": "^19.0.0"
63
- },
64
- "peerDependenciesMeta": {
65
- "@tanstack/react-query": {
66
- "optional": true
67
- }
26
+ "@decocms/blocks": "8.1.0-next.1"
68
27
  },
69
28
  "devDependencies": {
70
- "@tanstack/react-query": "^5.96.0",
71
- "@types/react": "^19.0.0",
72
- "@types/react-dom": "^19.0.0",
73
- "knip": "^5.86.0",
74
29
  "typescript": "^5.9.0"
75
30
  },
76
31
  "publishConfig": {
package/src/index.ts CHANGED
@@ -1,32 +1,14 @@
1
1
  /**
2
- * VTEX app entry point.
3
- *
4
- * Next major: `createVtexClient` is the thin, instrumented VTEX client
5
- * (see ./vtexClient.ts and /next/upstream-clients). Everything else below is
6
- * the v7 app surface, kept exported for v7 consumers until v7 is dropped.
7
- *
8
- * v7: re-exports client config + initializer + app contract.
9
- *
10
- * For actions/loaders/utils, use sub-path imports:
11
- * import { addItemsToCart } from "@decocms/apps/vtex/actions/checkout"
12
- * import { searchProducts } from "@decocms/apps/vtex/loaders/catalog"
13
- * import { slugify } from "@decocms/apps/vtex/utils/slugify"
14
- *
15
- * Or barrel imports:
16
- * import { addItemsToCart } from "@decocms/apps/vtex/actions"
17
- * import { searchProducts } from "@decocms/apps/vtex/loaders"
2
+ * `@decocms/apps-vtex`: a thin, instrumented VTEX client (`createVtexClient`).
3
+ * See ./vtexClient.ts and /next/upstream-clients.
18
4
  */
19
- export * from "./client";
20
- export { configure, type VtexState } from "./mod";
21
- export { type CreateVtexFetchOptions, createVtexFetch } from "./utils/instrumentedFetch";
22
- export { vtexOperationRouter } from "./utils/operationRouter";
23
5
  export {
24
- createVtexClient,
25
- type VtexCatalogSearchArgs,
26
- type VtexClient,
27
- type VtexClientConfig,
28
- VtexError,
29
- type VtexRequestOptions,
30
- type VtexResponse,
31
- type VtexSearchArgs,
6
+ createVtexClient,
7
+ type VtexCatalogSearchArgs,
8
+ type VtexClient,
9
+ type VtexClientConfig,
10
+ VtexError,
11
+ type VtexRequestOptions,
12
+ type VtexResponse,
13
+ type VtexSearchArgs,
32
14
  } from "./vtexClient";
@@ -1,62 +1,8 @@
1
1
  /**
2
- * Tuning knobs for the VTEX fetch resilience + cache layer.
3
- *
4
- * Every timeout, limit, and threshold that governs how `resilience.ts`
5
- * (abort/timeout, circuit breaker, retry budget) and `fetchCache.ts` (SWR +
6
- * stale-if-error) behave under VTEX slowness/outages lives HERE, in one file,
7
- * with the reasoning for each number next to it. Auditing or tuning the
8
- * resilience posture means reading one file, not hunting across two.
2
+ * Tuning knobs for VTEX request resilience (timeouts, retries, circuit
3
+ * breaker), with the reasoning for each number next to it.
9
4
  */
10
5
 
11
- // ---------------------------------------------------------------------------
12
- // fetchCache.ts — SWR + stale-if-error cache for VTEX GET responses
13
- // ---------------------------------------------------------------------------
14
-
15
- /** Max distinct cache keys kept in memory; oldest `createdAt` evicted first. */
16
- export const FETCH_CACHE_MAX_ENTRIES = 500;
17
-
18
- /**
19
- * How long a cached response is considered FRESH, keyed by status class.
20
- * Past this the entry is stale — served via SWR (2xx) while a background
21
- * refresh runs, or treated as expired (404/5xx). See `ttlForStatus` in
22
- * `fetchCache.ts`.
23
- */
24
- export const FETCH_CACHE_FRESH_TTL_MS = {
25
- /** 2xx — 3 min. Catalog/price data doesn't need to be second-fresh. */
26
- success: 180_000,
27
- /** 404 — 10s. Short on purpose: a just-published SKU shouldn't 404 long. */
28
- notFound: 10_000,
29
- /** 5xx — never "fresh". A server error is never treated as a good cache hit. */
30
- serverError: 0,
31
- } as const;
32
-
33
- /**
34
- * Stale-if-error window: how long PAST the freshness TTL a last-good 2xx entry
35
- * may still be served when the origin is failing (5xx / timeout / circuit
36
- * open). This is the "availability first" knob — a warm key survives a full
37
- * VTEX outage for up to this long with zero upstream pressure; once an entry
38
- * is older than `freshTtl + this`, it's considered too stale to serve and the
39
- * error surfaces (→ the degraded / branded-error path takes over). Mirrors the
40
- * edge `sie` window sites configure for the product/listing cache profiles.
41
- */
42
- export const FETCH_CACHE_STALE_IF_ERROR_MS = 86_400_000; // 24h
43
-
44
- /**
45
- * Inflight-slot backstop timeout. Bounds how long a single hung `fetch()` can
46
- * hold a dedup entry alive. Without this, a VTEX subrequest that never
47
- * settles leaks the inflight Map slot forever and every subsequent request
48
- * for the same cache key joins the zombie Promise, pinning memory until
49
- * `exceededMemory` (observed in prod: 514 hard crashes / 24h on a PLP route).
50
- *
51
- * MUST stay ABOVE `RESILIENCE_CONFIG.totalTimeoutMs` (see below) — the
52
- * resilient fetch already owns real per-call abort/timeout, so this is only a
53
- * last-resort backstop. If it fired first it would kill a slow-but-recoverable
54
- * response the resilience layer was about to deliver, discard the good body
55
- * (it never reaches the cache), and free the dedup slot early so a concurrent
56
- * request launches a duplicate upstream fetch.
57
- */
58
- export const FETCH_CACHE_INFLIGHT_BACKSTOP_MS = 15_000;
59
-
60
6
  // ---------------------------------------------------------------------------
61
7
  // resilience.ts — abort/timeout, retry budget, circuit breaker
62
8
  // ---------------------------------------------------------------------------
@@ -29,36 +29,36 @@
29
29
  * `*.vtexcommercestable.com.br` / `*.myvtex.com` / `secure.<storefront>` APIs.
30
30
  */
31
31
  export const VTEX_COOKIE_PREFIXES: readonly string[] = [
32
- "VtexIdclientAutCookie",
33
- "checkout.vtex.com",
34
- "CheckoutOrderFormOwnership",
35
- "vtex_session",
36
- "vtex_segment",
37
- "vtex_is_",
38
- "janus_sid",
32
+ "VtexIdclientAutCookie",
33
+ "checkout.vtex.com",
34
+ "CheckoutOrderFormOwnership",
35
+ "vtex_session",
36
+ "vtex_segment",
37
+ "vtex_is_",
38
+ "janus_sid",
39
39
  ];
40
40
 
41
41
  export type DropReason = "non_ascii" | "not_in_allowlist" | "malformed";
42
42
 
43
43
  export interface DroppedCookie {
44
- name: string;
45
- reason: DropReason;
44
+ name: string;
45
+ reason: DropReason;
46
46
  }
47
47
 
48
48
  export interface CookieSanitizeResult {
49
- /** Cookie header string ready to forward (may be empty). */
50
- cookies: string;
51
- /** Cookies that were filtered out, with the reason per cookie. */
52
- dropped: DroppedCookie[];
49
+ /** Cookie header string ready to forward (may be empty). */
50
+ cookies: string;
51
+ /** Cookies that were filtered out, with the reason per cookie. */
52
+ dropped: DroppedCookie[];
53
53
  }
54
54
 
55
55
  export interface CookieSanitizeOptions {
56
- /**
57
- * When true, additionally enforces an allowlist: only cookies whose name
58
- * starts with one of `VTEX_COOKIE_PREFIXES` are kept.
59
- * @default false
60
- */
61
- allowlist?: boolean;
56
+ /**
57
+ * When true, additionally enforces an allowlist: only cookies whose name
58
+ * starts with one of `VTEX_COOKIE_PREFIXES` are kept.
59
+ * @default false
60
+ */
61
+ allowlist?: boolean;
62
62
  }
63
63
 
64
64
  /**
@@ -93,47 +93,47 @@ const ASCII_VALUE_RE = /^[\x20-\x7E]*$/;
93
93
  * ```
94
94
  */
95
95
  export function sanitizeOutboundCookieHeader(
96
- raw: string,
97
- opts: CookieSanitizeOptions = {},
96
+ raw: string,
97
+ opts: CookieSanitizeOptions = {},
98
98
  ): CookieSanitizeResult {
99
- if (!raw) return { cookies: "", dropped: [] };
99
+ if (!raw) return { cookies: "", dropped: [] };
100
100
 
101
- const kept: string[] = [];
102
- const dropped: DroppedCookie[] = [];
103
- const allowlist = opts.allowlist === true;
101
+ const kept: string[] = [];
102
+ const dropped: DroppedCookie[] = [];
103
+ const allowlist = opts.allowlist === true;
104
104
 
105
- for (const segment of raw.split(";")) {
106
- const pair = segment.trim();
107
- if (!pair) continue;
105
+ for (const segment of raw.split(";")) {
106
+ const pair = segment.trim();
107
+ if (!pair) continue;
108
108
 
109
- const eq = pair.indexOf("=");
110
- if (eq <= 0) {
111
- dropped.push({ name: pair.slice(0, 32), reason: "malformed" });
112
- continue;
113
- }
109
+ const eq = pair.indexOf("=");
110
+ if (eq <= 0) {
111
+ dropped.push({ name: pair.slice(0, 32), reason: "malformed" });
112
+ continue;
113
+ }
114
114
 
115
- const name = pair.slice(0, eq);
116
- const value = pair.slice(eq + 1);
115
+ const name = pair.slice(0, eq);
116
+ const value = pair.slice(eq + 1);
117
117
 
118
- if (!TOKEN_RE.test(name)) {
119
- dropped.push({ name, reason: "malformed" });
120
- continue;
121
- }
118
+ if (!TOKEN_RE.test(name)) {
119
+ dropped.push({ name, reason: "malformed" });
120
+ continue;
121
+ }
122
122
 
123
- if (!ASCII_VALUE_RE.test(value)) {
124
- dropped.push({ name, reason: "non_ascii" });
125
- continue;
126
- }
123
+ if (!ASCII_VALUE_RE.test(value)) {
124
+ dropped.push({ name, reason: "non_ascii" });
125
+ continue;
126
+ }
127
127
 
128
- if (allowlist && !VTEX_COOKIE_PREFIXES.some((p) => name.startsWith(p))) {
129
- dropped.push({ name, reason: "not_in_allowlist" });
130
- continue;
131
- }
128
+ if (allowlist && !VTEX_COOKIE_PREFIXES.some((p) => name.startsWith(p))) {
129
+ dropped.push({ name, reason: "not_in_allowlist" });
130
+ continue;
131
+ }
132
132
 
133
- kept.push(`${name}=${value}`);
134
- }
133
+ kept.push(`${name}=${value}`);
134
+ }
135
135
 
136
- return { cookies: kept.join("; "), dropped };
136
+ return { cookies: kept.join("; "), dropped };
137
137
  }
138
138
 
139
139
  /**
@@ -142,7 +142,7 @@ export function sanitizeOutboundCookieHeader(
142
142
  * Equivalent to `sanitizeOutboundCookieHeader(raw, { allowlist: true }).cookies`.
143
143
  */
144
144
  export function extractVtexCookies(raw: string): string {
145
- return sanitizeOutboundCookieHeader(raw, { allowlist: true }).cookies;
145
+ return sanitizeOutboundCookieHeader(raw, { allowlist: true }).cookies;
146
146
  }
147
147
 
148
148
  /**
@@ -158,16 +158,16 @@ const _warned = new Set<string>();
158
158
  * arbitrary `host` label so we can correlate in logs.
159
159
  */
160
160
  export function warnDroppedCookies(dropped: DroppedCookie[], host: string): void {
161
- if (dropped.length === 0) return;
162
- for (const d of dropped) {
163
- const key = `${host}::${d.name}::${d.reason}`;
164
- if (_warned.has(key)) continue;
165
- _warned.add(key);
166
- console.warn(`[vtex.cookie.dropped] host=${host} name=${d.name} reason=${d.reason}`);
167
- }
161
+ if (dropped.length === 0) return;
162
+ for (const d of dropped) {
163
+ const key = `${host}::${d.name}::${d.reason}`;
164
+ if (_warned.has(key)) continue;
165
+ _warned.add(key);
166
+ console.warn(`[vtex.cookie.dropped] host=${host} name=${d.name} reason=${d.reason}`);
167
+ }
168
168
  }
169
169
 
170
170
  /** Reset the dedup set — exposed for tests. */
171
171
  export function _resetCookieWarnDedupForTests(): void {
172
- _warned.clear();
172
+ _warned.clear();
173
173
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * URL-derived operation name router for VTEX API calls.
3
3
  *
4
- * Plugged into `@decocms/start`'s `createInstrumentedFetch` via the
4
+ * Plugged into `createInstrumentedFetch` (`@decocms/blocks/fetch`) via the
5
5
  * `resolveOperation(url, method)` option. The resolved string becomes the
6
6
  * span suffix (`vtex.<operation>`) and the `fetch.operation` span +
7
7
  * histogram label, so it must be:
@@ -25,8 +25,8 @@
25
25
  type OperationResolver = string | ((match: RegExpMatchArray, method: string) => string);
26
26
 
27
27
  interface Matcher {
28
- pattern: RegExp;
29
- operation: OperationResolver;
28
+ pattern: RegExp;
29
+ operation: OperationResolver;
30
30
  }
31
31
 
32
32
  const m = (pattern: RegExp, operation: OperationResolver): Matcher => ({ pattern, operation });
@@ -42,66 +42,66 @@ const m = (pattern: RegExp, operation: OperationResolver): Matcher => ({ pattern
42
42
  * prefixes them with the integration name at span time.
43
43
  */
44
44
  const MATCHERS: ReadonlyArray<Matcher> = [
45
- m(/^\/api\/io\/_v\/api\/intelligent-search\/([a-z_-]+)/, (mm) => `intelligent-search.${mm[1]}`),
46
- m(/^\/_v\/private\/graphql\/v1/, "io.graphql"),
47
- m(/^\/_v\/segment\//, "io.segment"),
45
+ m(/^\/api\/io\/_v\/api\/intelligent-search\/([a-z_-]+)/, (mm) => `intelligent-search.${mm[1]}`),
46
+ m(/^\/_v\/private\/graphql\/v1/, "io.graphql"),
47
+ m(/^\/_v\/segment\//, "io.segment"),
48
48
 
49
- m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/items\/update/, (_mm, method) =>
50
- method === "POST" ? "checkout.orderform.items.update" : "checkout.orderform.items",
51
- ),
52
- m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/items/, (_mm, method) => {
53
- if (method === "DELETE") return "checkout.orderform.items.remove";
54
- if (method === "PATCH" || method === "PUT") return "checkout.orderform.items.update";
55
- return "checkout.orderform.items.add";
56
- }),
57
- m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/coupons/, "checkout.orderform.coupons"),
58
- m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/profile/, "checkout.orderform.profile"),
59
- m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/shippingData/, "checkout.orderform.shipping"),
60
- m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/paymentData/, "checkout.orderform.payment"),
61
- m(/^\/api\/checkout\/pub\/orderForm\/[^/]+/, (_mm, method) =>
62
- method === "GET" ? "checkout.orderform.get" : "checkout.orderform.update",
63
- ),
64
- m(/^\/api\/checkout\/pub\/orderForm(?:\/?$)/, (_mm, method) =>
65
- method === "POST" ? "checkout.orderform.create" : "checkout.orderform.get",
66
- ),
67
- m(/^\/api\/checkout\/pub\/orderForms\/simulation/, "checkout.simulation"),
68
- m(/^\/api\/checkout\/pub\/regions/, "checkout.regions"),
69
- m(/^\/api\/checkout\/pub\/postal-code/, "checkout.postal-code"),
49
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/items\/update/, (_mm, method) =>
50
+ method === "POST" ? "checkout.orderform.items.update" : "checkout.orderform.items",
51
+ ),
52
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/items/, (_mm, method) => {
53
+ if (method === "DELETE") return "checkout.orderform.items.remove";
54
+ if (method === "PATCH" || method === "PUT") return "checkout.orderform.items.update";
55
+ return "checkout.orderform.items.add";
56
+ }),
57
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/coupons/, "checkout.orderform.coupons"),
58
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/profile/, "checkout.orderform.profile"),
59
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/shippingData/, "checkout.orderform.shipping"),
60
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+\/paymentData/, "checkout.orderform.payment"),
61
+ m(/^\/api\/checkout\/pub\/orderForm\/[^/]+/, (_mm, method) =>
62
+ method === "GET" ? "checkout.orderform.get" : "checkout.orderform.update",
63
+ ),
64
+ m(/^\/api\/checkout\/pub\/orderForm(?:\/?$)/, (_mm, method) =>
65
+ method === "POST" ? "checkout.orderform.create" : "checkout.orderform.get",
66
+ ),
67
+ m(/^\/api\/checkout\/pub\/orderForms\/simulation/, "checkout.simulation"),
68
+ m(/^\/api\/checkout\/pub\/regions/, "checkout.regions"),
69
+ m(/^\/api\/checkout\/pub\/postal-code/, "checkout.postal-code"),
70
70
 
71
- m(/^\/api\/sessions/, (_mm, method) => (method === "POST" ? "sessions.update" : "sessions.get")),
72
- m(/^\/api\/segments\//, "segments.get"),
71
+ m(/^\/api\/sessions/, (_mm, method) => (method === "POST" ? "sessions.update" : "sessions.get")),
72
+ m(/^\/api\/segments\//, "segments.get"),
73
73
 
74
- m(/^\/api\/catalog_system\/pub\/portal\/pagetype\//, "catalog.pagetype"),
75
- m(
76
- /^\/api\/catalog_system\/pub\/products\/crossselling\/([^/]+)/,
77
- (mm) => `catalog.crossselling.${mm[1]}`,
78
- ),
79
- m(/^\/api\/catalog_system\/pub\/products\/variations\//, "catalog.products.variations"),
80
- m(/^\/api\/catalog_system\/pub\/products\/search/, "catalog.products.search"),
81
- m(/^\/api\/catalog_system\/pub\/facets\/search/, "catalog.facets.search"),
82
- m(/^\/api\/catalog_system\/pub\/category\/tree/, "catalog.category.tree"),
83
- m(/^\/api\/catalog_system\/(?:pub|pvt)\/specification/, "catalog.specification"),
84
- m(/^\/api\/catalog_system\/pub\/brand/, "catalog.brand"),
85
- m(/^\/api\/catalog_system\/pvt\/sku\//, "catalog.sku"),
86
- m(/^\/api\/catalog_system\//, "catalog.other"),
74
+ m(/^\/api\/catalog_system\/pub\/portal\/pagetype\//, "catalog.pagetype"),
75
+ m(
76
+ /^\/api\/catalog_system\/pub\/products\/crossselling\/([^/]+)/,
77
+ (mm) => `catalog.crossselling.${mm[1]}`,
78
+ ),
79
+ m(/^\/api\/catalog_system\/pub\/products\/variations\//, "catalog.products.variations"),
80
+ m(/^\/api\/catalog_system\/pub\/products\/search/, "catalog.products.search"),
81
+ m(/^\/api\/catalog_system\/pub\/facets\/search/, "catalog.facets.search"),
82
+ m(/^\/api\/catalog_system\/pub\/category\/tree/, "catalog.category.tree"),
83
+ m(/^\/api\/catalog_system\/(?:pub|pvt)\/specification/, "catalog.specification"),
84
+ m(/^\/api\/catalog_system\/pub\/brand/, "catalog.brand"),
85
+ m(/^\/api\/catalog_system\/pvt\/sku\//, "catalog.sku"),
86
+ m(/^\/api\/catalog_system\//, "catalog.other"),
87
87
 
88
- m(/^\/api\/wishlist\//, "wishlist"),
89
- m(/^\/api\/profile-system\/profile\//, "profile"),
90
- m(/^\/api\/dataentities\/([^/]+)/, (mm) => `masterdata.${mm[1]}`),
88
+ m(/^\/api\/wishlist\//, "wishlist"),
89
+ m(/^\/api\/profile-system\/profile\//, "profile"),
90
+ m(/^\/api\/dataentities\/([^/]+)/, (mm) => `masterdata.${mm[1]}`),
91
91
 
92
- m(/^\/api\/oms\/user\/orders\/[^/]+\/cancel/, "oms.orders.cancel"),
93
- m(/^\/api\/oms\/user\/orders/, "oms.orders"),
94
- m(/^\/api\/oms\/pvt\/orders/, "oms.orders.pvt"),
92
+ m(/^\/api\/oms\/user\/orders\/[^/]+\/cancel/, "oms.orders.cancel"),
93
+ m(/^\/api\/oms\/user\/orders/, "oms.orders"),
94
+ m(/^\/api\/oms\/pvt\/orders/, "oms.orders.pvt"),
95
95
 
96
- m(/^\/api\/vtexid\/pub\/logout/, "vtexid.logout"),
97
- m(/^\/api\/vtexid\/pub\/authentication\/start/, "vtexid.authentication.start"),
98
- m(/^\/api\/vtexid\/pub\/authentication\/[a-z]+\/validate/, "vtexid.authentication.validate"),
99
- m(/^\/api\/vtexid\/pub\/authenticated\/user/, "vtexid.user"),
100
- m(/^\/api\/vtexid\//, "vtexid.other"),
96
+ m(/^\/api\/vtexid\/pub\/logout/, "vtexid.logout"),
97
+ m(/^\/api\/vtexid\/pub\/authentication\/start/, "vtexid.authentication.start"),
98
+ m(/^\/api\/vtexid\/pub\/authentication\/[a-z]+\/validate/, "vtexid.authentication.validate"),
99
+ m(/^\/api\/vtexid\/pub\/authenticated\/user/, "vtexid.user"),
100
+ m(/^\/api\/vtexid\//, "vtexid.other"),
101
101
 
102
- m(/^\/api\/events\/v1\//, "events.send"),
103
- m(/^\/sitemap.*\.xml$/, "sitemap"),
104
- m(/^\/api\/license-manager/, "license-manager"),
102
+ m(/^\/api\/events\/v1\//, "events.send"),
103
+ m(/^\/sitemap.*\.xml$/, "sitemap"),
104
+ m(/^\/api\/license-manager/, "license-manager"),
105
105
  ];
106
106
 
107
107
  /**
@@ -118,16 +118,26 @@ const MATCHERS: ReadonlyArray<Matcher> = [
118
118
  * });
119
119
  * ```
120
120
  */
121
- import { extractPathname } from "@decocms/blocks/sdk/urlUtils";
121
+ /** The URL's pathname; tolerates relative or malformed URLs by stripping `?`/`#`. */
122
+ function extractPathname(url: string): string {
123
+ try {
124
+ return new URL(url).pathname;
125
+ } catch {
126
+ const qs = url.indexOf("?");
127
+ const hash = url.indexOf("#");
128
+ const end = [qs, hash].filter((i) => i >= 0).sort((a, b) => a - b)[0];
129
+ return end === undefined ? url : url.slice(0, end);
130
+ }
131
+ }
122
132
 
123
133
  export function vtexOperationRouter(url: string, method: string): string | undefined {
124
- const pathname = extractPathname(url);
134
+ const pathname = extractPathname(url);
125
135
 
126
- const upperMethod = method.toUpperCase();
127
- for (const { pattern, operation } of MATCHERS) {
128
- const match = pathname.match(pattern);
129
- if (!match) continue;
130
- return typeof operation === "function" ? operation(match, upperMethod) : operation;
131
- }
132
- return undefined;
136
+ const upperMethod = method.toUpperCase();
137
+ for (const { pattern, operation } of MATCHERS) {
138
+ const match = pathname.match(pattern);
139
+ if (!match) continue;
140
+ return typeof operation === "function" ? operation(match, upperMethod) : operation;
141
+ }
142
+ return undefined;
133
143
  }