@faststore/core 4.9.3-dev.1 → 4.9.3-dev.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-generate.log +3 -3
- package/.turbo/turbo-test.log +132 -139
- package/CHANGELOG.md +12 -0
- package/package.json +6 -6
- package/src/pages/api/graphql.ts +23 -19
- package/src/utils/trustedForwardedHost.ts +50 -0
- package/test/utils/trustedForwardedHost.test.ts +105 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@4.9.3-dev.
|
|
2
|
+
> @faststore/core@4.9.3-dev.1 generate /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> pnpm run gen-types && pnpm run cache-graphql
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @faststore/core@4.9.3-dev.
|
|
6
|
+
> @faststore/core@4.9.3-dev.1 gen-types /home/runner/work/faststore/faststore/packages/core
|
|
7
7
|
> node ../cli/bin/run generate-types .
|
|
8
8
|
|
|
9
9
|
[33m[STARTED][39m Parse Configuration
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
[32m[COMPLETED][39m Generate to @generated/
|
|
20
20
|
[32m[COMPLETED][39m Generate outputs
|
|
21
21
|
|
|
22
|
-
> @faststore/core@4.9.3-dev.
|
|
22
|
+
> @faststore/core@4.9.3-dev.1 cache-graphql /home/runner/work/faststore/faststore/packages/core
|
|
23
23
|
> node ../cli/bin/run cache-graphql --config=./discovery.config.default.js --queries=./@generated/persisted-documents.json
|
|
24
24
|
|
|
25
25
|
[Info] - Config file location: /home/runner/work/faststore/faststore/packages/core/discovery.config.default.js
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@4.9.3-dev.
|
|
2
|
+
> @faststore/core@4.9.3-dev.1 test /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> vitest run
|
|
4
4
|
|
|
5
5
|
|
|
@@ -7,33 +7,27 @@
|
|
|
7
7
|
|
|
8
8
|
Not implemented: navigation to another Document
|
|
9
9
|
Not implemented: navigation to another Document
|
|
10
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/ui/useScrollRestoration.browser.test.ts [2m([22m[2m43 tests[22m[2m)[22m[33m 1198[2mms[22m[39m
|
|
11
10
|
Browserslist: browsers data (caniuse-lite) is 8 months old. Please run:
|
|
12
11
|
npx update-browserslist-db@latest
|
|
13
12
|
Why you should do it regularly: https://github.com/browserslist/update-db#readme
|
|
14
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
15
|
-
|
|
16
|
-
[33m[2m✓[22m[39m
|
|
17
|
-
[33m[2m✓[22m[39m
|
|
18
|
-
|
|
19
|
-
[33m[2m✓[22m[39m
|
|
20
|
-
[33m[2m✓[22m[39m
|
|
21
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/
|
|
22
|
-
[33m[2m✓[22m[39m
|
|
23
|
-
[33m[2m✓[22m[39m
|
|
24
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
[33m[2m✓[22m[39m
|
|
28
|
-
|
|
29
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/localization/useBindingSelector.browser.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[32m
|
|
30
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
31
|
-
|
|
32
|
-
[33m[2m✓[22m[39m opens the contract switcher and returns to the menu on back [33m 367[2mms[22m[39m
|
|
33
|
-
[33m[2m✓[22m[39m resets to the menu when the drawer closes [33m 329[2mms[22m[39m
|
|
34
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 20[2mms[22m[39m
|
|
35
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/ui/ProductGallery/GalleryPageHeightLock.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 99[2mms[22m[39m
|
|
36
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/recommendations/useRecommendationShelf.browser.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[32m 71[2mms[22m[39m
|
|
13
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/ui/useScrollRestoration.browser.test.ts [2m([22m[2m43 tests[22m[2m)[22m[33m 1011[2mms[22m[39m
|
|
14
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/ContractSwitcher.browser.test.tsx [2m([22m[2m22 tests[22m[2m)[22m[33m 2790[2mms[22m[39m
|
|
15
|
+
[33m[2m✓[22m[39m shows an error state when the list fails to load [33m 760[2mms[22m[39m
|
|
16
|
+
[33m[2m✓[22m[39m requires selecting a contract before Confirm is enabled, then switches (REQ-03) [33m 308[2mms[22m[39m
|
|
17
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/cards/MyAccountListCards.browser.test.tsx [2m([22m[2m16 tests[22m[2m)[22m[33m 3127[2mms[22m[39m
|
|
18
|
+
[33m[2m✓[22m[39m shows the tab bar and renders Personal cards by default [33m 1504[2mms[22m[39m
|
|
19
|
+
[33m[2m✓[22m[39m paginates when there are more than 25 cards [33m 504[2mms[22m[39m
|
|
20
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/BuyingPolicyAlert.browser.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[33m 2487[2mms[22m[39m
|
|
21
|
+
[33m[2m✓[22m[39m opens the reject confirmation modal with the default English copy [33m 805[2mms[22m[39m
|
|
22
|
+
[33m[2m✓[22m[39m opens the reject confirmation modal with CMS-provided labels [33m 387[2mms[22m[39m
|
|
23
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/CartRecommendationShelf/CartRecommendationShelf.browser.test.tsx [2m([22m[2m13 tests[22m[2m)[22m[33m 457[2mms[22m[39m
|
|
24
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 22[2mms[22m[39m
|
|
25
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawer.browser.test.tsx [2m([22m[2m10 tests[22m[2m)[22m[33m 1931[2mms[22m[39m
|
|
26
|
+
[33m[2m✓[22m[39m renders the menu view with contract details and manage footer [33m 1038[2mms[22m[39m
|
|
27
|
+
[33m[2m✓[22m[39m opens the contract switcher and returns to the menu on back [33m 359[2mms[22m[39m
|
|
28
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/localization/useBindingSelector.browser.test.tsx [2m([22m[2m9 tests[22m[2m)[22m[32m 121[2mms[22m[39m
|
|
29
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/ui/ProductGallery/GalleryPageHeightLock.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 83[2mms[22m[39m
|
|
30
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/recommendations/useRecommendationShelf.browser.test.tsx [2m([22m[2m12 tests[22m[2m)[22m[32m 92[2mms[22m[39m
|
|
37
31
|
[90mstderr[2m | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx
|
|
38
32
|
[22m[39mError in optimistic validation: TypeError: Failed to parse URL from /api/graphql?operationName=ValidateCartMutation&operationHash=3c71b0d3fc2bade14df68abfa271858beb361b12
|
|
39
33
|
[90m at node:internal/deps/undici/undici:16416:13[39m
|
|
@@ -63,11 +57,10 @@ Browserslist: browsers data (caniuse-lite) is 8 months old. Please run:
|
|
|
63
57
|
[90mstderr[2m | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx[2m > [22m[2mRecommendationShelf[2m > [22m[2mrenders nothing when there is an error
|
|
64
58
|
[22m[39mError fetching recommendations [90mundefined[39m boom for campaign vrn:recommendations:acc:rec-top-items-v2:campaign-1
|
|
65
59
|
|
|
66
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
67
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
68
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/
|
|
69
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
70
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/navigation/Navbar.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 92[2mms[22m[39m
|
|
60
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 119[2mms[22m[39m
|
|
61
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/getInitialSession.browser.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 9[2mms[22m[39m
|
|
62
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/CartSidebar/CartSidebar.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 83[2mms[22m[39m
|
|
63
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountOrderDetails.browser.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 69[2mms[22m[39m
|
|
71
64
|
[90mstderr[2m | test/pages/password-protection.browser.test.tsx[2m > [22m[2mPasswordProtectionLogin[2m > [22m[2mposts the password and redirects to the requested return path
|
|
72
65
|
[22m[39mWarning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
|
|
73
66
|
|
|
@@ -153,6 +146,8 @@ act(() => {
|
|
|
153
146
|
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
|
|
154
147
|
at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
|
|
155
148
|
|
|
149
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/navigation/Navbar.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 100[2mms[22m[39m
|
|
150
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerFooter.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[33m 508[2mms[22m[39m
|
|
156
151
|
[90mstderr[2m | test/pages/password-protection.browser.test.tsx[2m > [22m[2mPasswordProtectionLogin[2m > [22m[2muses the fallback invalid-password message when API omits an error
|
|
157
152
|
[22m[39mWarning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
|
|
158
153
|
|
|
@@ -249,7 +244,6 @@ act(() => {
|
|
|
249
244
|
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
|
|
250
245
|
at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
|
|
251
246
|
|
|
252
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerFooter.browser.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[33m 545[2mms[22m[39m
|
|
253
247
|
[90mstderr[2m | test/pages/password-protection.browser.test.tsx[2m > [22m[2mPasswordProtectionLogin[2m > [22m[2mshows service unavailable when the login request fails
|
|
254
248
|
[22m[39mWarning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
|
|
255
249
|
|
|
@@ -298,8 +292,8 @@ act(() => {
|
|
|
298
292
|
This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act
|
|
299
293
|
at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
|
|
300
294
|
|
|
301
|
-
[32m✓[39m [30m[46m browser [49m[39m test/pages/password-protection.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m
|
|
302
|
-
[33m[2m✓[22m[39m renders the password protection form [33m
|
|
295
|
+
[32m✓[39m [30m[46m browser [49m[39m test/pages/password-protection.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 983[2mms[22m[39m
|
|
296
|
+
[33m[2m✓[22m[39m renders the password protection form [33m 410[2mms[22m[39m
|
|
303
297
|
[90mstderr[2m | test/components/cms/RenderSections.browser.test.tsx
|
|
304
298
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
305
299
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -308,9 +302,9 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
308
302
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:357:23)
|
|
309
303
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
310
304
|
|
|
311
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useSwitchContract.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
312
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/navigation/NavbarSlider.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
313
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/cms/RenderSections.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
305
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useSwitchContract.browser.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 56[2mms[22m[39m
|
|
306
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/navigation/NavbarSlider.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 42[2mms[22m[39m
|
|
307
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/cms/RenderSections.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 92[2mms[22m[39m
|
|
314
308
|
[90mstderr[2m | test/sdk/localization/store-url.browser.test.ts
|
|
315
309
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
316
310
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -320,14 +314,14 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
320
314
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
321
315
|
|
|
322
316
|
[32m✓[39m [30m[46m browser [49m[39m test/sdk/localization/store-url.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
323
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/Menu.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m
|
|
324
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useAvailableContracts.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
325
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/templates/SearchPage/SearchWrapper.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
326
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/recommendations/useRecommendationShelf.sessionFallback.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
327
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountListQuotes.browser.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
328
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/navigation/NavbarAccountArea.browser.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
329
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
330
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
317
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/Menu.browser.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[33m 385[2mms[22m[39m
|
|
318
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/useAvailableContracts.browser.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 42[2mms[22m[39m
|
|
319
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/templates/SearchPage/SearchWrapper.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 35[2mms[22m[39m
|
|
320
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/recommendations/useRecommendationShelf.sessionFallback.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 128[2mms[22m[39m
|
|
321
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountListQuotes.browser.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 135[2mms[22m[39m
|
|
322
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/navigation/NavbarAccountArea.browser.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 78[2mms[22m[39m
|
|
323
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/changeContractToken.browser.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 22[2mms[22m[39m
|
|
324
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/CartRecommendationShelf/CartRecommendationProductCard.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 54[2mms[22m[39m
|
|
331
325
|
[90mstderr[2m | test/components/account/doLogout.browser.test.ts
|
|
332
326
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
333
327
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -336,9 +330,9 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
336
330
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:357:23)
|
|
337
331
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
338
332
|
|
|
339
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/doLogout.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
340
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/ui/LocalizationButton.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
341
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerHeader.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m
|
|
333
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/doLogout.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 39[2mms[22m[39m
|
|
334
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/ui/LocalizationButton.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 48[2mms[22m[39m
|
|
335
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationDrawerHeader.browser.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[33m 359[2mms[22m[39m
|
|
342
336
|
[90mstderr[2m | test/sdk/account/clearPersistedSessionState.browser.test.ts
|
|
343
337
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
344
338
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -347,14 +341,14 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
347
341
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:357:23)
|
|
348
342
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
349
343
|
|
|
350
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/clearPersistedSessionState.browser.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
351
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountOrderDelivery.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
352
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryOptionAccordion.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
353
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountOrderStatus.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
354
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/region/useRegion.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
355
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountListCards.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
356
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountOrdersList.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
357
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/SummaryCard.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
344
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/clearPersistedSessionState.browser.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 19[2mms[22m[39m
|
|
345
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountOrderDelivery.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 102[2mms[22m[39m
|
|
346
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryOptionAccordion.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 104[2mms[22m[39m
|
|
347
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountOrderStatus.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 144[2mms[22m[39m
|
|
348
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/region/useRegion.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 17[2mms[22m[39m
|
|
349
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountListCards.browser.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 92[2mms[22m[39m
|
|
350
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/sections/Account/AccountOrdersList.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 30[2mms[22m[39m
|
|
351
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/SummaryCard.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 105[2mms[22m[39m
|
|
358
352
|
[90mstderr[2m | test/sdk/session/sessionStore.browser.test.ts
|
|
359
353
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
360
354
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -363,9 +357,9 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
363
357
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:357:23)
|
|
364
358
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
365
359
|
|
|
366
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
367
|
-
[32m✓[39m [30m[46m browser [49m[39m test/
|
|
368
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryOptionAccordionDeliveryInfo.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
360
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/sessionStore.browser.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
361
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/OrganizationSignInButton.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 270[2mms[22m[39m
|
|
362
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryOptionAccordionDeliveryInfo.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
369
363
|
[90mstderr[2m | test/sdk/session/validateSession.browser.test.ts
|
|
370
364
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
371
365
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -375,13 +369,13 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
375
369
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
376
370
|
|
|
377
371
|
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/validateSession.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
378
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/StatusCard.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
379
|
-
[32m✓[39m [30m[46m browser [49m[39m test/utils/isLocalHost.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
380
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
381
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryCard.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
382
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryOptionAccordionProducts.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
383
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/skeletons/ProductGridSkeleton.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
384
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/bindingPaths.test.ts [2m([22m[2m71 tests[22m[2m)[22m[32m
|
|
372
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/StatusCard.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 107[2mms[22m[39m
|
|
373
|
+
[32m✓[39m [30m[46m browser [49m[39m test/utils/isLocalHost.browser.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
374
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
375
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryCard.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m 63[2mms[22m[39m
|
|
376
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/DeliveryOptionAccordionProducts.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m 51[2mms[22m[39m
|
|
377
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/skeletons/ProductGridSkeleton.browser.test.tsx [2m([22m[2m2 tests[22m[2m)[22m[32m 45[2mms[22m[39m
|
|
378
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/bindingPaths.test.ts [2m([22m[2m71 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
385
379
|
[90mstderr[2m | test/sdk/account/refreshToken.browser.test.ts
|
|
386
380
|
[22m[39mError in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
|
|
387
381
|
at waitForSessionValidated [90m(/home/runner/work/faststore/faststore/packages/core/[39msrc/sdk/cart/waitForSessionValidated.ts:16:32[90m)[39m
|
|
@@ -390,13 +384,14 @@ This ensures that you're testing the behavior the user would see in the browser.
|
|
|
390
384
|
at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:357:23)
|
|
391
385
|
[90m at processTicksAndRejections (node:internal/process/task_queues:103:5)[39m
|
|
392
386
|
|
|
393
|
-
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/refreshToken.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
394
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/password-protection-service.test.ts [2m([22m[2m22 tests[22m[2m)[22m[32m
|
|
395
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/switch-contract.test.ts [2m([22m[2m25 tests[22m[2m)[22m[32m
|
|
396
|
-
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/FilterFacetPendingApproval.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
397
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/match-url.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
387
|
+
[32m✓[39m [30m[46m browser [49m[39m test/sdk/account/refreshToken.browser.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
388
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/password-protection-service.test.ts [2m([22m[2m22 tests[22m[2m)[22m[32m 37[2mms[22m[39m
|
|
389
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/switch-contract.test.ts [2m([22m[2m25 tests[22m[2m)[22m[32m 92[2mms[22m[39m
|
|
390
|
+
[32m✓[39m [30m[46m browser [49m[39m test/components/account/orders/FilterFacetPendingApproval.browser.test.tsx [2m([22m[2m1 test[22m[2m)[22m[32m 230[2mms[22m[39m
|
|
391
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/match-url.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 9[2mms[22m[39m
|
|
398
392
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/useBindingSelector.test.tsx [2m([22m[2m22 tests[22m[2m)[22m[32m 15[2mms[22m[39m
|
|
399
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/unlock.test.ts [2m([22m[2m15 tests[22m[2m)[22m[32m
|
|
393
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/unlock.test.ts [2m([22m[2m15 tests[22m[2m)[22m[32m 141[2mms[22m[39m
|
|
394
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/session/syncSalesChannelFromOrderForm.test.ts [2m([22m[2m14 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
400
395
|
[90mstderr[2m | test/components/search/SearchInputComponent.test.tsx
|
|
401
396
|
[22m[39mWarning: forwardRef render functions accept exactly two parameters: props and ref. Did you forget to use the ref parameter?
|
|
402
397
|
|
|
@@ -460,25 +455,24 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
460
455
|
at Suspense
|
|
461
456
|
at Wrapper (/home/runner/work/faststore/faststore/packages/core/test/components/search/SearchInputComponent.test.tsx:106:20)
|
|
462
457
|
|
|
463
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/
|
|
464
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInputComponent.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
465
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
466
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
467
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/search/useSearchHistory.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m 50[2mms[22m[39m
|
|
458
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/bindingSelector.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
459
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInputComponent.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 94[2mms[22m[39m
|
|
460
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotesTable.test.tsx [2m([22m[2m15 tests[22m[2m)[22m[33m 474[2mms[22m[39m
|
|
461
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/search/useSearchHistory.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m 48[2mms[22m[39m
|
|
468
462
|
[90mstderr[2m | test/pages/pvt/account/cards/index.test.ts[2m > [22m[2mCards page getServerSideProps[2m > [22m[2mredirects to /pvt/account/403 when the query fails with 401/403
|
|
469
463
|
[22m[39m{ extensions: { status: [33m401[39m } }
|
|
470
464
|
|
|
471
465
|
[90mstderr[2m | test/pages/pvt/account/cards/index.test.ts[2m > [22m[2mCards page getServerSideProps[2m > [22m[2mrenders the error state (no redirect) when the query fails with a non-auth status
|
|
472
466
|
[22m[39m{ extensions: { status: [33m502[39m } }
|
|
473
467
|
|
|
474
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/pvt/account/cards/index.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
475
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotes.test.tsx [2m([22m[2m11 tests[22m[2m)[22m[33m
|
|
476
|
-
[33m[2m✓[22m[39m navigates with the search term on blur [33m
|
|
468
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/pvt/account/cards/index.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 11[2mms[22m[39m
|
|
469
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountListQuotes.test.tsx [2m([22m[2m11 tests[22m[2m)[22m[33m 832[2mms[22m[39m
|
|
470
|
+
[33m[2m✓[22m[39m navigates with the search term on blur [33m 358[2mms[22m[39m
|
|
477
471
|
[33m[2m✓[22m[39m navigates without a label param when the search is cleared [33m 360[2mms[22m[39m
|
|
478
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
479
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
480
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/
|
|
481
|
-
[32m✓[39m [30m[43m node [49m[39m test/experimental/myAccountCmsServerSideProps.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
472
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/quoteFilters.test.ts [2m([22m[2m26 tests[22m[2m)[22m[32m 29[2mms[22m[39m
|
|
473
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/productJsonLd.test.ts [2m([22m[2m36 tests[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
474
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/cookieCacheBusting.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 17[2mms[22m[39m
|
|
475
|
+
[32m✓[39m [30m[43m node [49m[39m test/experimental/myAccountCmsServerSideProps.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 22[2mms[22m[39m
|
|
482
476
|
[90mstderr[2m | test/pages/api/graphql.test.ts[2m > [22m[2m/api/graphql error status propagation[2m > [22m[2mpropagates the upstream 400 from a wrapped BadRequestError instead of 500
|
|
483
477
|
[22m[39mGraphql execution returned with error: [
|
|
484
478
|
{
|
|
@@ -588,74 +582,73 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
|
|
|
588
582
|
at trace (file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/vitest@4.0.18_@opentelemetry+api@1.9.0_@types+node@20.19.13_jiti@2.6.1_jsdom@27.4.0_sas_13be941c57d55f08f06eeaf1c180ddfe/node_modules/[4mvitest[24m/dist/chunks/test.B8ej_ZHS.js:239:21)
|
|
589
583
|
at runTest (file:///home/runner/work/faststore/faststore/node_modules/[4m.pnpm[24m/@vitest+runner@4.0.18/node_modules/[4m@vitest/runner[24m/dist/index.js:1653:12)
|
|
590
584
|
|
|
591
|
-
[32m✓[39m [30m[43m node [49m[39m test/pages/api/graphql.test.ts [2m([22m[2m19 tests[22m[2m)[22m[32m
|
|
592
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/clearCookies.test.ts [2m([22m[2m20 tests[22m[2m)[22m[32m
|
|
593
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/multipleTemplates.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
585
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/graphql.test.ts [2m([22m[2m19 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
586
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/clearCookies.test.ts [2m([22m[2m20 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
|
587
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/multipleTemplates.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
594
588
|
[90mstderr[2m | test/sdk/account/useSetPassword.test.ts[2m > [22m[2museSetPassword[2m > [22m[2mmaps wrongcredentials error responses to the existing message
|
|
595
589
|
[22m[39mSet password request failed: Bad Request
|
|
596
590
|
|
|
597
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/useSetPassword.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
598
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryOperation.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
599
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/localizeRedirectDestination.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m
|
|
600
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesFilterSlider.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
601
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesStatusSelector.test.tsx [2m([22m[2m14 tests[22m[2m)[22m[32m
|
|
591
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/useSetPassword.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
592
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryOperation.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 43[2mms[22m[39m
|
|
593
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/localizeRedirectDestination.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
594
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesFilterSlider.test.tsx [2m([22m[2m8 tests[22m[2m)[22m[32m 226[2mms[22m[39m
|
|
595
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesStatusSelector.test.tsx [2m([22m[2m14 tests[22m[2m)[22m[32m 190[2mms[22m[39m
|
|
602
596
|
[32m✓[39m [30m[43m node [49m[39m test/utils/localization/hreflang.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
603
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getMyAccountRoutes.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m
|
|
604
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesSelectedTags.test.tsx [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
605
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/redirects/index.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m
|
|
606
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryUpload.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
607
|
-
[32m✓[39m [30m[43m node [49m[39m test/proxy.localization.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
608
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntry.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m
|
|
609
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/getDeliveryOptionLabel.test.ts [2m([22m[2m21 tests[22m[2m)[22m[32m
|
|
610
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/graphql/retryPolicy.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m
|
|
611
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/cms/myAccountDefaultSections.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m
|
|
612
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/productJsonLdRendering.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m
|
|
613
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
614
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
615
|
-
[32m✓[39m [30m[43m node [49m[39m test/proxy.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
616
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/webops-api.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m
|
|
617
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/StatusCard.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 19[2mms[22m[39m
|
|
597
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getMyAccountRoutes.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
598
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuotesSelectedTags.test.tsx [2m([22m[2m10 tests[22m[2m)[22m[32m 124[2mms[22m[39m
|
|
599
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/redirects/index.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 51[2mms[22m[39m
|
|
600
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntryUpload.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 58[2mms[22m[39m
|
|
601
|
+
[32m✓[39m [30m[43m node [49m[39m test/proxy.localization.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 35[2mms[22m[39m
|
|
602
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderEntry.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 49[2mms[22m[39m
|
|
603
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/getDeliveryOptionLabel.test.ts [2m([22m[2m21 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
604
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/graphql/retryPolicy.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m 23[2mms[22m[39m
|
|
605
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/cms/myAccountDefaultSections.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
606
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/productJsonLdRendering.test.tsx [2m([22m[2m5 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
607
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/trustedForwardedHost.test.ts [2m([22m[2m27 tests[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
608
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/index.test.ts [2m([22m[2m7 tests[22m[2m)[22m[33m 746[2mms[22m[39m
|
|
609
|
+
[32m✓[39m [30m[43m node [49m[39m test/proxy.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 23[2mms[22m[39m
|
|
610
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/webops-api.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 14[2mms[22m[39m
|
|
618
611
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/localization/store-url.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
619
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/
|
|
620
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
621
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/
|
|
622
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
623
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/
|
|
624
|
-
[32m✓[39m [30m[43m node [49m[39m test/server/
|
|
612
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/useStartRecommendationSession.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 77[2mms[22m[39m
|
|
613
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/StatusCard.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 32[2mms[22m[39m
|
|
614
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/orderEntry/useOrderFormItems.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 41[2mms[22m[39m
|
|
615
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/cart/waitForSessionValidated.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 13[2mms[22m[39m
|
|
616
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/refreshToken.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 12[2mms[22m[39m
|
|
617
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/content/service.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
618
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/cms/global.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
619
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/auth/useAuth.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 44[2mms[22m[39m
|
|
625
620
|
[32m✓[39m [30m[43m node [49m[39m test/utils/getRequestHostname.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
626
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
627
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
628
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
629
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
630
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
631
|
-
[33m[2m✓[22m[39m should return a valid merged GraphQL schema [33m 302[2mms[22m[39m
|
|
632
|
-
[33m[2m✓[22m[39m should handle options and execute [33m 4558[2mms[22m[39m
|
|
621
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/Layout.test.tsx [2m([22m[2m6 tests[22m[2m)[22m[32m 77[2mms[22m[39m
|
|
622
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/rootSpan.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 48[2mms[22m[39m
|
|
623
|
+
[32m✓[39m [30m[43m node [49m[39m test/pages/api/preview.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 9[2mms[22m[39m
|
|
624
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/search/SearchInput.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 13[2mms[22m[39m
|
|
625
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/validateSessionRefreshToken.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
633
626
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/vrn.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
634
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/region/useRegion.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
635
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
636
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
637
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getB2BSessionClaims.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
638
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
639
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
627
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/region/useRegion.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 24[2mms[22m[39m
|
|
628
|
+
[32m✓[39m [30m[43m node [49m[39m test/server/cms/index.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
629
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/retry.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 17[2mms[22m[39m
|
|
630
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/getB2BSessionClaims.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 7[2mms[22m[39m
|
|
631
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/useRecommendationUserId.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 194[2mms[22m[39m
|
|
632
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/userOrderStatus.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
640
633
|
[32m✓[39m [30m[43m node [49m[39m test/utils/unlockResponse.test.ts [2m([22m[2m11 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
641
634
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/recommendations/useRecommendations.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 6[2mms[22m[39m
|
|
642
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/account/OrganizationDrawerBody.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
643
|
-
[32m✓[39m [30m[43m node [49m[39m test/utils/isLocalHost.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m
|
|
635
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/OrganizationDrawerBody.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 43[2mms[22m[39m
|
|
636
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/isLocalHost.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
644
637
|
[32m✓[39m [30m[43m node [49m[39m test/sdk/session/toSessionInput.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
645
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuoteStatusBadge.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
646
|
-
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/getOrderTotalLabel.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
638
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/quotes/MyAccountQuoteStatusBadge.test.tsx [2m([22m[2m4 tests[22m[2m)[22m[32m 49[2mms[22m[39m
|
|
639
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/getOrderTotalLabel.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
647
640
|
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/listOrdersLabels.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
648
641
|
[32m✓[39m [30m[43m node [49m[39m test/utils/getCookie.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
649
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/session/isSignInAreaResolved.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
650
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
651
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
652
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
653
|
-
[32m✓[39m [30m[43m node [49m[39m test/
|
|
642
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/session/isSignInAreaResolved.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
643
|
+
[32m✓[39m [30m[43m node [49m[39m test/utils/filterChannel.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
644
|
+
[32m✓[39m [30m[43m node [49m[39m test/components/auth/ProfileChallenge.test.tsx [2m([22m[2m3 tests[22m[2m)[22m[32m 43[2mms[22m[39m
|
|
645
|
+
[32m✓[39m [30m[43m node [49m[39m test/instrumentation.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 5[2mms[22m[39m
|
|
646
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/analytics/utils.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 3[2mms[22m[39m
|
|
654
647
|
[32m✓[39m [30m[43m node [49m[39m test/components/account/orders/orderDetailsLabels.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 4[2mms[22m[39m
|
|
655
|
-
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/clearPersistedSessionState.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
648
|
+
[32m✓[39m [30m[43m node [49m[39m test/sdk/account/clearPersistedSessionState.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 8[2mms[22m[39m
|
|
656
649
|
|
|
657
|
-
[2m Test Files [22m [1m[
|
|
658
|
-
[2m Tests [22m [1m[
|
|
659
|
-
[2m Start at [22m
|
|
660
|
-
[2m Duration [22m
|
|
650
|
+
[2m Test Files [22m [1m[32m130 passed[39m[22m[90m (130)[39m
|
|
651
|
+
[2m Tests [22m [1m[32m1032 passed[39m[22m[90m (1032)[39m
|
|
652
|
+
[2m Start at [22m 00:35:08
|
|
653
|
+
[2m Duration [22m 62.92s[2m (transform 13.32s, setup 0ms, import 56.50s, tests 21.42s, environment 78.13s)[22m
|
|
661
654
|
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [4.9.3-dev.2](https://github.com/vtex/faststore/compare/v4.9.3-dev.1...v4.9.3-dev.2) (2026-10-07)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- address security & functional concerns from dk review ([d0b6106](https://github.com/vtex/faststore/commit/d0b610688ec551d8105c74750927be4ab1af7224))
|
|
11
|
+
- **core:** harden x-forwarded-host handling and drop orderNumber fallback ([c1faa35](https://github.com/vtex/faststore/commit/c1faa35fe070ff8b51d4f07a5f1f33da4b17d836)), closes [#3178](https://github.com/vtex/faststore/issues/3178)
|
|
12
|
+
- **core:** ignore multi-value x-forwarded-host and cover port and case ([b81d5d9](https://github.com/vtex/faststore/commit/b81d5d91721f9f8205251ad39e607b094386083c))
|
|
13
|
+
- **core:** log ignored x-forwarded-host and cover CR/LF hostnames ([adaa816](https://github.com/vtex/faststore/commit/adaa81608b7e72759272e1d6d23ca6257b9a4d59))
|
|
14
|
+
- **core:** make preview cookies host-only instead of rewriting their domain ([8e4901e](https://github.com/vtex/faststore/commit/8e4901ec7d127336bc27c0ae8e52c9cadea1a5a3))
|
|
15
|
+
- **core:** reject hostnames that would inject Set-Cookie attributes ([059a437](https://github.com/vtex/faststore/commit/059a4377c3b1b8f66aeed2b73ce130e1ab827f77))
|
|
16
|
+
- resolve ValidateCartMutation infinite loop in preview environments (SFS-3034) ([1cc9a5e](https://github.com/vtex/faststore/commit/1cc9a5efb1617f3d032623c4ee5f687ad5e2ccd9)), closes [#3178](https://github.com/vtex/faststore/issues/3178) [#3178](https://github.com/vtex/faststore/issues/3178) [#3190](https://github.com/vtex/faststore/issues/3190) [#3188](https://github.com/vtex/faststore/issues/3188) [#1467584](https://github.com/vtex/faststore/issues/1467584)
|
|
17
|
+
|
|
6
18
|
## [4.9.3-dev.1](https://github.com/vtex/faststore/compare/v4.9.3-dev.0...v4.9.3-dev.1) (2026-10-06)
|
|
7
19
|
|
|
8
20
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "4.9.3-dev.
|
|
3
|
+
"version": "4.9.3-dev.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -71,11 +71,11 @@
|
|
|
71
71
|
"style-loader": "^3.3.1",
|
|
72
72
|
"swr": "^2.2.5",
|
|
73
73
|
"use-sync-external-store": "^1.6.0",
|
|
74
|
-
"@faststore/api": "4.9.3-dev.
|
|
75
|
-
"@faststore/diagnostics": "4.9.3-dev.
|
|
76
|
-
"@faststore/lighthouse": "4.9.3-dev.
|
|
77
|
-
"@faststore/sdk": "4.9.3-dev.
|
|
78
|
-
"@faststore/ui": "4.9.3-dev.
|
|
74
|
+
"@faststore/api": "4.9.3-dev.2",
|
|
75
|
+
"@faststore/diagnostics": "4.9.3-dev.2",
|
|
76
|
+
"@faststore/lighthouse": "4.9.3-dev.2",
|
|
77
|
+
"@faststore/sdk": "4.9.3-dev.2",
|
|
78
|
+
"@faststore/ui": "4.9.3-dev.2"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@cypress/code-coverage": "^3.12.1",
|
package/src/pages/api/graphql.ts
CHANGED
|
@@ -11,6 +11,11 @@ import discoveryConfig from 'discovery.config'
|
|
|
11
11
|
import { getJWTAutCookie } from 'src/utils/getCookie'
|
|
12
12
|
import { getRequestHostname } from 'src/utils/getRequestHostname'
|
|
13
13
|
import { isLocalHost } from 'src/utils/isLocalHost'
|
|
14
|
+
import {
|
|
15
|
+
isHostAllowed,
|
|
16
|
+
removeCookieDomain,
|
|
17
|
+
singleForwardedHost,
|
|
18
|
+
} from 'src/utils/trustedForwardedHost'
|
|
14
19
|
import { shouldForceRefreshTokenForValidateSession } from 'src/utils/validateSessionRefreshToken'
|
|
15
20
|
import { execute } from '../../server'
|
|
16
21
|
import { logger } from '@faststore/diagnostics'
|
|
@@ -56,22 +61,10 @@ const shouldReplaceCookieDomain = ({
|
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
/**
|
|
59
|
-
*
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
allowList,
|
|
64
|
-
}: {
|
|
65
|
-
host: string
|
|
66
|
-
allowList: string[]
|
|
67
|
-
}) => {
|
|
68
|
-
const normalizedHost = host.toLowerCase()
|
|
69
|
-
|
|
70
|
-
return allowList.some((suffix) => normalizedHost.endsWith(suffix))
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Ensure the cookie domain matches the current host so the browser can store it.
|
|
64
|
+
* On allowlisted hosts (previews, localhost) the upstream cookie domain does not
|
|
65
|
+
* match the browser host, so the Domain attribute is dropped and the cookie
|
|
66
|
+
* becomes host-only. The host is never written into the cookie, so a forged
|
|
67
|
+
* x-forwarded-host cannot choose the cookie scope.
|
|
75
68
|
*/
|
|
76
69
|
const normalizeSetCookieDomain = ({
|
|
77
70
|
request,
|
|
@@ -85,20 +78,31 @@ const normalizeSetCookieDomain = ({
|
|
|
85
78
|
return setCookie
|
|
86
79
|
}
|
|
87
80
|
|
|
88
|
-
|
|
81
|
+
// The preview ingress forwards a client-supplied x-forwarded-host as is, so
|
|
82
|
+
// it only decides whether the Domain is dropped, never which domain is used.
|
|
83
|
+
const forwardedHeader = request.headers['x-forwarded-host']
|
|
84
|
+
const forwardedHost = getRequestHostname(singleForwardedHost(forwardedHeader))
|
|
85
|
+
if (forwardedHeader && !forwardedHost) {
|
|
86
|
+
// The value is client-controllable, so it is not logged.
|
|
87
|
+
OTELLogger('warn', 'Ignoring multi-value or malformed x-forwarded-host')
|
|
88
|
+
}
|
|
89
|
+
const host =
|
|
90
|
+
forwardedHost && isHostAllowed(forwardedHost, ALLOWED_HOST_SUFFIXES)
|
|
91
|
+
? forwardedHost
|
|
92
|
+
: getRequestHostname(request.headers.host)
|
|
89
93
|
if (!host) {
|
|
90
94
|
return setCookie
|
|
91
95
|
}
|
|
92
96
|
const cookieDomain = domainMatch[1]
|
|
93
97
|
|
|
94
98
|
if (
|
|
95
|
-
!
|
|
99
|
+
!isHostAllowed(host, ALLOWED_HOST_SUFFIXES) ||
|
|
96
100
|
!shouldReplaceCookieDomain({ cookieDomain, host })
|
|
97
101
|
) {
|
|
98
102
|
return setCookie
|
|
99
103
|
}
|
|
100
104
|
|
|
101
|
-
return setCookie
|
|
105
|
+
return removeCookieDomain(setCookie)
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
const parseRequest = (request: NextApiRequest) => {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// The result is written verbatim into a Set-Cookie Domain attribute, so
|
|
2
|
+
// characters such as ";" or spaces would inject cookie attributes.
|
|
3
|
+
const HOSTNAME_PATTERN = /^[a-z0-9.-]+$/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* An entry starting with "." matches subdomains only; any other entry matches
|
|
7
|
+
* the host itself and its subdomains. Matching is anchored on a label boundary,
|
|
8
|
+
* so "evil-localhost" never matches "localhost".
|
|
9
|
+
*/
|
|
10
|
+
export function isHostAllowed(host: string, allowList: string[]) {
|
|
11
|
+
const normalizedHost = host.toLowerCase()
|
|
12
|
+
|
|
13
|
+
if (!HOSTNAME_PATTERN.test(normalizedHost)) {
|
|
14
|
+
return false
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return allowList.some((entry) =>
|
|
18
|
+
entry.startsWith('.')
|
|
19
|
+
? normalizedHost.endsWith(entry)
|
|
20
|
+
: normalizedHost === entry || normalizedHost.endsWith(`.${entry}`)
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns the `x-forwarded-host` value only when exactly one is present.
|
|
26
|
+
*
|
|
27
|
+
* Which hop of a proxy chain is trustworthy is not known here: with several
|
|
28
|
+
* values the leftmost one is whatever the client sent. So a multi-value header
|
|
29
|
+
* (comma-joined by Node, or an array) is ignored and the caller falls back to
|
|
30
|
+
* `host`. A single value still assumes the ingress overwrites the header.
|
|
31
|
+
*/
|
|
32
|
+
export function singleForwardedHost(
|
|
33
|
+
header: string | string[] | undefined
|
|
34
|
+
): string | undefined {
|
|
35
|
+
if (Array.isArray(header)) {
|
|
36
|
+
return header.length === 1 ? singleForwardedHost(header[0]) : undefined
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const value = header?.trim()
|
|
40
|
+
|
|
41
|
+
return value && !value.includes(',') ? value : undefined
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Drops every Domain attribute so the cookie becomes host-only: the browser
|
|
46
|
+
* scopes it to the exact host it requested, whatever header picked this path.
|
|
47
|
+
*/
|
|
48
|
+
export function removeCookieDomain(setCookie: string): string {
|
|
49
|
+
return setCookie.replaceAll(/;\s*domain=[^;]*/gi, '')
|
|
50
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
singleForwardedHost,
|
|
5
|
+
isHostAllowed,
|
|
6
|
+
removeCookieDomain,
|
|
7
|
+
} from '../../src/utils/trustedForwardedHost'
|
|
8
|
+
|
|
9
|
+
const ALLOW_LIST = ['localhost', '.vtex.app', '.localhost']
|
|
10
|
+
|
|
11
|
+
describe('isHostAllowed', () => {
|
|
12
|
+
it.each([
|
|
13
|
+
'localhost',
|
|
14
|
+
'store.vtex.app',
|
|
15
|
+
'sfj-1--acc.preview.vtex.app',
|
|
16
|
+
'a.localhost',
|
|
17
|
+
])('allows %s', (host) => {
|
|
18
|
+
expect(isHostAllowed(host, ALLOW_LIST)).toBe(true)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it.each([
|
|
22
|
+
'evil-localhost',
|
|
23
|
+
'notlocalhost',
|
|
24
|
+
'evil-vtex.app',
|
|
25
|
+
'vtex.app.evil.com',
|
|
26
|
+
'evil.com',
|
|
27
|
+
])('rejects %s', (host) => {
|
|
28
|
+
expect(isHostAllowed(host, ALLOW_LIST)).toBe(false)
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
describe('isHostAllowed normalization', () => {
|
|
33
|
+
it('is case-insensitive', () => {
|
|
34
|
+
expect(isHostAllowed('Store.VTEX.app', ALLOW_LIST)).toBe(true)
|
|
35
|
+
expect(isHostAllowed('LOCALHOST', ALLOW_LIST)).toBe(true)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it.each([
|
|
39
|
+
'x;max-age=0;y.vtex.app',
|
|
40
|
+
'a b.vtex.app',
|
|
41
|
+
'x"y.vtex.app',
|
|
42
|
+
'x=y.vtex.app',
|
|
43
|
+
'x,y.vtex.app',
|
|
44
|
+
'x\r\nSet-Cookie: evil=1.vtex.app',
|
|
45
|
+
'x\ny.vtex.app',
|
|
46
|
+
'x\ry.vtex.app',
|
|
47
|
+
])('rejects %s, which would inject cookie attributes', (host) => {
|
|
48
|
+
expect(isHostAllowed(host, ALLOW_LIST)).toBe(false)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('accepts punycode hostnames', () => {
|
|
52
|
+
expect(isHostAllowed('xn--lja-bma.vtex.app', ALLOW_LIST)).toBe(true)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('expects a hostname: a port is not stripped here', () => {
|
|
56
|
+
expect(isHostAllowed('store.vtex.app:8080', ALLOW_LIST)).toBe(false)
|
|
57
|
+
expect(isHostAllowed('evil.com:vtex.app', ALLOW_LIST)).toBe(false)
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe('singleForwardedHost', () => {
|
|
62
|
+
it('returns the value when there is exactly one', () => {
|
|
63
|
+
expect(singleForwardedHost('a.vtex.app')).toBe('a.vtex.app')
|
|
64
|
+
expect(singleForwardedHost(' a.vtex.app ')).toBe('a.vtex.app')
|
|
65
|
+
expect(singleForwardedHost(['a.vtex.app'])).toBe('a.vtex.app')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('returns undefined when missing or empty', () => {
|
|
69
|
+
expect(singleForwardedHost(undefined)).toBeUndefined()
|
|
70
|
+
expect(singleForwardedHost('')).toBeUndefined()
|
|
71
|
+
expect(singleForwardedHost([])).toBeUndefined()
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('ignores multi-value headers instead of picking one', () => {
|
|
75
|
+
expect(singleForwardedHost('a.vtex.app, evil.com')).toBeUndefined()
|
|
76
|
+
expect(singleForwardedHost('evil.com, a.vtex.app')).toBeUndefined()
|
|
77
|
+
expect(singleForwardedHost(['a.vtex.app', 'evil.com'])).toBeUndefined()
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
describe('removeCookieDomain', () => {
|
|
82
|
+
it('drops the Domain attribute and keeps the rest', () => {
|
|
83
|
+
expect(
|
|
84
|
+
removeCookieDomain(
|
|
85
|
+
'checkout.vtex.com=__ofid=abc; expires=Sun, 04 Apr 2027 18:31:26 GMT; domain=acc.vtexcommercestable.com.br; path=/; secure; samesite=lax; httponly'
|
|
86
|
+
)
|
|
87
|
+
).toBe(
|
|
88
|
+
'checkout.vtex.com=__ofid=abc; expires=Sun, 04 Apr 2027 18:31:26 GMT; path=/; secure; samesite=lax; httponly'
|
|
89
|
+
)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('is case-insensitive and removes repeated Domain attributes', () => {
|
|
93
|
+
expect(removeCookieDomain('a=1; Domain=x.com; DOMAIN=y.com; Path=/')).toBe(
|
|
94
|
+
'a=1; Path=/'
|
|
95
|
+
)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('does not touch a cookie whose name is domain', () => {
|
|
99
|
+
expect(removeCookieDomain('domain=1; path=/')).toBe('domain=1; path=/')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('keeps cookies without a Domain attribute unchanged', () => {
|
|
103
|
+
expect(removeCookieDomain('a=1; path=/')).toBe('a=1; path=/')
|
|
104
|
+
})
|
|
105
|
+
})
|