@faststore/core 4.6.0-dev.1 → 4.6.0-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.
@@ -1,9 +1,9 @@
1
1
 
2
- > @faststore/core@4.6.0-dev.0 generate /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@4.6.0-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.6.0-dev.0 gen-types /home/runner/work/faststore/faststore/packages/core
6
+ > @faststore/core@4.6.0-dev.1 gen-types /home/runner/work/faststore/faststore/packages/core
7
7
  > node ../cli/bin/run generate-types .
8
8
 
9
9
  [STARTED] Parse Configuration
@@ -19,7 +19,7 @@
19
19
  [COMPLETED] Generate to /home/runner/work/faststore/faststore/packages/core/@generated/
20
20
  [COMPLETED] Generate outputs
21
21
 
22
- > @faststore/core@4.6.0-dev.0 cache-graphql /home/runner/work/faststore/faststore/packages/core
22
+ > @faststore/core@4.6.0-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
@@ -1,5 +1,5 @@
1
1
 
2
- > @faststore/core@4.6.0-dev.0 test /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@4.6.0-dev.1 test /home/runner/work/faststore/faststore/packages/core
3
3
  > vitest run
4
4
 
5
5
 
@@ -7,14 +7,15 @@
7
7
 
8
8
  Not implemented: navigation to another Document
9
9
  Not implemented: navigation to another Document
10
+ ✓  browser  test/sdk/ui/useScrollRestoration.browser.test.ts (43 tests) 763ms
10
11
  stderr | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx
11
- Error in optimistic validation: TypeError: Failed to parse URL from /api/graphql?operationName=ValidateCartMutation&operationHash=8199d03debb0a6751ec53d8ee8987b78d0292acb
12
+ Error in optimistic validation: TypeError: Failed to parse URL from /api/graphql?operationName=ValidateCartMutation&operationHash=3c71b0d3fc2bade14df68abfa271858beb361b12
12
13
   at node:internal/deps/undici/undici:16416:13
13
14
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
14
15
  at baseRequest (/home/runner/work/faststore/faststore/packages/core/src/sdk/graphql/request.ts:42:20)
15
16
  at GraphqlRequest (/home/runner/work/faststore/faststore/packages/core/src/sdk/graphql/request.ts:130:20)
16
17
  at request (/home/runner/work/faststore/faststore/packages/core/src/sdk/graphql/request.ts:154:5)
17
- at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:117:46)
18
+ at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:122:46)
18
19
  at onValidate (/home/runner/work/faststore/faststore/packages/core/src/sdk/useStore.ts:18:14)
19
20
  at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:17) {
20
21
  [cause]: TypeError: Invalid URL
@@ -29,25 +30,21 @@ Not implemented: navigation to another Document
29
30
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
30
31
  at GraphqlRequest (/home/runner/work/faststore/faststore/packages/core/src/sdk/graphql/request.ts:130:20) {
31
32
  code: 'ERR_INVALID_URL',
32
- input: '/api/graphql?operationName=ValidateCartMutation&operationHash=8199d03debb0a6751ec53d8ee8987b78d0292acb'
33
+ input: '/api/graphql?operationName=ValidateCartMutation&operationHash=3c71b0d3fc2bade14df68abfa271858beb361b12'
33
34
  }
34
35
  }
35
36
 
36
37
  Browserslist: browsers data (caniuse-lite) is 6 months old. Please run:
37
38
  npx update-browserslist-db@latest
38
39
  Why you should do it regularly: https://github.com/browserslist/update-db#readme
39
- ✓  browser  test/sdk/ui/useScrollRestoration.browser.test.ts (43 tests) 1055ms
40
+ ✓  browser  test/components/account/ContractSwitcher.browser.test.tsx (13 tests) 1389ms
40
41
  stderr | test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx > RecommendationShelf > renders nothing when there is an error
41
42
  Error fetching recommendations undefined boom for campaign vrn:recommendations:acc:rec-top-items-v2:campaign-1
42
43
 
43
- ✓  browser  test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx (8 tests) 209ms
44
- ✓  browser  test/components/account/ContractSwitcher.browser.test.tsx (13 tests) 2760ms
45
- ✓ shows an error state when the list fails to load  743ms
46
- ✓ requires selecting a contract before Confirm is enabled, then switches (REQ-03)  391ms
47
- ✓ does not reload when the switch returns false  308ms
48
- ✓  browser  test/sdk/session/reconcileSessionLocale.browser.test.ts (5 tests) 63ms
49
- ✓  browser  test/components/ui/ProductGallery/GalleryPageHeightLock.browser.test.tsx (8 tests) 252ms
50
- ✓  browser  test/sdk/session/getInitialSession.browser.test.ts (6 tests) 26ms
44
+ ✓  browser  test/components/RecommendationShelf/RecommendationShelf.browser.test.tsx (8 tests) 169ms
45
+ ✓  browser  test/components/ui/ProductGallery/GalleryPageHeightLock.browser.test.tsx (8 tests) 112ms
46
+ ✓  browser  test/sdk/session/reconcileSessionLocale.browser.test.ts (5 tests) 14ms
47
+ ✓  browser  test/sdk/session/getInitialSession.browser.test.ts (6 tests) 19ms
51
48
  stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > posts the password and redirects to the requested return path
52
49
  Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
53
50
 
@@ -277,57 +274,61 @@ act(() => {
277
274
  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
278
275
  at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
279
276
 
280
- ✓  browser  test/pages/password-protection.browser.test.tsx (6 tests) 1700ms
281
- ✓ renders the password protection form  845ms
282
- ✓  browser  test/components/account/OrganizationDrawer.browser.test.tsx (5 tests) 1546ms
283
- ✓ renders the menu view with contract details and manage footer  853ms
284
- ✓  browser  test/sdk/account/changeContractToken.browser.test.ts (9 tests) 112ms
277
+ ✓  browser  test/pages/password-protection.browser.test.tsx (6 tests) 1159ms
278
+ ✓ renders the password protection form  515ms
279
+ ✓  browser  test/sdk/account/changeContractToken.browser.test.ts (9 tests) 31ms
280
+ ✓  browser  test/components/account/OrganizationDrawer.browser.test.tsx (5 tests) 1172ms
281
+ ✓ renders the menu view with contract details and manage footer  744ms
285
282
  stderr | test/sdk/localization/store-url.browser.test.ts
286
283
  Error in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
287
- at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:121:27)
284
+ at waitForSessionValidated (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/waitForSessionValidated.ts:16:32)
285
+ at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:120:9)
288
286
  at onValidate (/home/runner/work/faststore/faststore/packages/core/src/sdk/useStore.ts:18:20)
289
287
  at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
290
288
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
291
289
 
292
- ✓  browser  test/sdk/localization/store-url.browser.test.ts (3 tests) 10ms
293
- ✓  browser  test/sdk/account/useAvailableContracts.browser.test.ts (6 tests) 41ms
294
- ✓  browser  test/components/templates/SearchPage/SearchWrapper.browser.test.tsx (3 tests) 38ms
295
- ✓  browser  test/sdk/account/useSwitchContract.browser.test.ts (4 tests) 43ms
290
+ ✓  browser  test/sdk/localization/store-url.browser.test.ts (3 tests) 7ms
291
+ ✓  browser  test/sdk/account/useAvailableContracts.browser.test.ts (6 tests) 31ms
292
+ ✓  browser  test/components/templates/SearchPage/SearchWrapper.browser.test.tsx (3 tests) 21ms
293
+ ✓  browser  test/sdk/account/useSwitchContract.browser.test.ts (4 tests) 36ms
296
294
  stderr | test/components/account/doLogout.browser.test.ts
297
295
  Error in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
298
- at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:121:27)
296
+ at waitForSessionValidated (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/waitForSessionValidated.ts:16:32)
297
+ at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:120:9)
299
298
  at onValidate (/home/runner/work/faststore/faststore/packages/core/src/sdk/useStore.ts:18:20)
300
299
  at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
301
300
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
302
301
 
303
- ✓  browser  test/components/account/doLogout.browser.test.ts (1 test) 18ms
304
- ✓  browser  test/components/account/OrganizationDrawerHeader.browser.test.tsx (3 tests) 295ms
302
+ ✓  browser  test/components/account/doLogout.browser.test.ts (1 test) 14ms
303
+ ✓  browser  test/components/account/OrganizationDrawerHeader.browser.test.tsx (3 tests) 186ms
305
304
  stderr | test/sdk/account/clearPersistedSessionState.browser.test.ts
306
305
  Error in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
307
- at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:121:27)
306
+ at waitForSessionValidated (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/waitForSessionValidated.ts:16:32)
307
+ at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:120:9)
308
308
  at onValidate (/home/runner/work/faststore/faststore/packages/core/src/sdk/useStore.ts:18:20)
309
309
  at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
310
310
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
311
311
 
312
- ✓  browser  test/sdk/account/clearPersistedSessionState.browser.test.ts (1 test) 8ms
313
- ✓  browser  test/components/account/OrganizationDrawerFooter.browser.test.tsx (3 tests) 255ms
314
- ✓  browser  test/utils/isLocalHost.browser.test.ts (3 tests) 5ms
315
- ✓  browser  test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts (1 test) 3ms
316
- ✓  node  test/utils/localization/bindingPaths.test.ts (71 tests) 29ms
312
+ ✓  browser  test/sdk/account/clearPersistedSessionState.browser.test.ts (1 test) 14ms
313
+ ✓  browser  test/components/account/OrganizationDrawerFooter.browser.test.tsx (3 tests) 239ms
314
+ ✓  browser  test/utils/isLocalHost.browser.test.ts (3 tests) 4ms
315
+ ✓  browser  test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts (1 test) 2ms
316
+ ✓  node  test/utils/localization/bindingPaths.test.ts (71 tests) 21ms
317
+ ✓  browser  test/components/skeletons/ProductGridSkeleton.browser.test.tsx (2 tests) 29ms
318
+ ✓  node  test/server/password-protection-service.test.ts (22 tests) 25ms
317
319
  stderr | test/sdk/account/refreshToken.browser.test.ts
318
320
  Error in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
319
- at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:121:27)
321
+ at waitForSessionValidated (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/waitForSessionValidated.ts:16:32)
322
+ at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:120:9)
320
323
  at onValidate (/home/runner/work/faststore/faststore/packages/core/src/sdk/useStore.ts:18:20)
321
324
  at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
322
325
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
323
326
 
327
+ ✓  node  test/utils/match-url.test.ts (10 tests) 5ms
324
328
  ✓  browser  test/sdk/account/refreshToken.browser.test.ts (1 test) 4ms
325
- ✓  browser  test/components/skeletons/ProductGridSkeleton.browser.test.tsx (2 tests) 48ms
326
- ✓  node  test/server/password-protection-service.test.ts (22 tests) 38ms
327
- ✓  node  test/utils/match-url.test.ts (10 tests) 10ms
328
- ✓  node  test/sdk/localization/useBindingSelector.test.tsx (22 tests) 14ms
329
- ✓  node  test/pages/api/unlock.test.ts (15 tests) 284ms
330
- ✓  node  test/sdk/localization/bindingSelector.test.ts (18 tests) 11ms
329
+ ✓  node  test/sdk/localization/useBindingSelector.test.tsx (22 tests) 11ms
330
+ ✓  node  test/pages/api/unlock.test.ts (15 tests) 118ms
331
+ ✓  node  test/sdk/localization/bindingSelector.test.ts (18 tests) 8ms
331
332
  stderr | test/components/search/SearchInputComponent.test.tsx
332
333
  Warning: forwardRef render functions accept exactly two parameters: props and ref. Did you forget to use the ref parameter?
333
334
 
@@ -391,11 +392,11 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
391
392
  at Suspense
392
393
  at Wrapper (/home/runner/work/faststore/faststore/packages/core/test/components/search/SearchInputComponent.test.tsx:106:20)
393
394
 
394
- ✓  node  test/components/search/SearchInputComponent.test.tsx (6 tests) 63ms
395
- ✓  node  test/utils/cookieCacheBusting.test.ts (10 tests) 11ms
396
- ✓  node  test/sdk/search/useSearchHistory.test.ts (13 tests) 63ms
397
- ✓  node  test/experimental/myAccountCmsServerSideProps.test.ts (5 tests) 11ms
398
- ✓  node  test/utils/clearCookies.test.ts (20 tests) 23ms
395
+ ✓  node  test/components/search/SearchInputComponent.test.tsx (6 tests) 58ms
396
+ ✓  node  test/utils/cookieCacheBusting.test.ts (10 tests) 10ms
397
+ ✓  node  test/sdk/search/useSearchHistory.test.ts (13 tests) 44ms
398
+ ✓  node  test/experimental/myAccountCmsServerSideProps.test.ts (5 tests) 8ms
399
+ ✓  node  test/utils/clearCookies.test.ts (20 tests) 19ms
399
400
  stderr | test/pages/api/graphql.test.ts > /api/graphql error status propagation > propagates the upstream 400 from a wrapped BadRequestError instead of 500
400
401
  Graphql execution returned with error: [
401
402
  {
@@ -444,7 +445,7 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
444
445
 
445
446
  stderr | test/pages/api/graphql.test.ts > /api/graphql request handling > maps BadRequestError thrown by execute to its status
446
447
  Something unexpected occurred querying Graphql endpoint:
447
- _ [FastStoreError]: malformed
448
+ T [FastStoreError]: malformed
448
449
  at /home/runner/work/faststore/faststore/packages/core/test/pages/api/graphql.test.ts:190:31
449
450
  at /home/runner/work/faststore/faststore/packages/core/test/pages/api/graphql.test.ts:196:39
450
451
  at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1024:60
@@ -460,7 +461,7 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
460
461
 
461
462
  stderr | test/pages/api/graphql.test.ts > /api/graphql request handling > maps UnauthorizedError thrown by execute to its status
462
463
  Something unexpected occurred querying Graphql endpoint:
463
- te [FastStoreError]: expired
464
+ re [FastStoreError]: expired
464
465
  at /home/runner/work/faststore/faststore/packages/core/test/pages/api/graphql.test.ts:191:33
465
466
  at /home/runner/work/faststore/faststore/packages/core/test/pages/api/graphql.test.ts:196:39
466
467
  at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1024:60
@@ -488,62 +489,64 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
488
489
  at file:///home/runner/work/faststore/faststore/node_modules/.pnpm/@vitest+runner@4.0.18/node_modules/@vitest/runner/dist/index.js:1653:37
489
490
  at Traces.$ (file:///home/runner/work/faststore/faststore/node_modules/.pnpm/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/vitest/dist/chunks/traces.CCmnQaNT.js:142:27)
490
491
 
491
- ✓  node  test/pages/api/graphql.test.ts (17 tests) 39ms
492
- ✓  node  test/components/quotes/MyAccountListQuotesTable.test.tsx (12 tests) 424ms
493
- ✓  node  test/components/quotes/MyAccountListQuotes.test.tsx (9 tests) 847ms
494
- ✓ navigates with the search term on blur  363ms
495
- ✓ navigates without a label param when the search is cleared  357ms
492
+ ✓  node  test/pages/api/graphql.test.ts (17 tests) 24ms
493
+ ✓  node  test/components/quotes/MyAccountListQuotesTable.test.tsx (12 tests) 323ms
496
494
  stderr | test/sdk/account/useSetPassword.test.ts > useSetPassword > maps wrongcredentials error responses to the existing message
497
495
  Set password request failed: Bad Request
498
496
 
499
- ✓  node  test/sdk/account/useSetPassword.test.ts (6 tests) 32ms
500
- ✓  node  test/sdk/orderEntry/useOrderEntryOperation.test.ts (8 tests) 41ms
501
- ✓  node  test/utils/multipleTemplates.test.ts (8 tests) 7ms
502
- ✓  node  test/components/quotes/quoteFilters.test.ts (23 tests) 28ms
503
- ✓  node  test/utils/localization/localizeRedirectDestination.test.ts (11 tests) 6ms
504
- ✓  node  test/sdk/orderEntry/useOrderEntryUpload.test.ts (8 tests) 54ms
505
- ✓  node  test/components/quotes/MyAccountQuotesFilterSlider.test.tsx (5 tests) 198ms
506
- ✓  node  test/sdk/analytics/useStartRecommendationSession.test.ts (6 tests) 51ms
507
- ✓  node  test/server/index.test.ts (7 tests) 809ms
508
- ✓ should return a valid merged GraphQL schema  315ms
509
- ✓  node  test/sdk/orderEntry/useOrderEntry.test.ts (8 tests) 42ms
510
- ✓  node  test/sdk/account/getMyAccountRoutes.test.ts (10 tests) 7ms
511
- ✓  node  test/proxy.localization.test.ts (5 tests) 49ms
512
- ✓  node  test/proxy.test.ts (4 tests) 21ms
513
- ✓  node  test/server/webops-api.test.ts (9 tests) 14ms
514
- ✓  node  test/server/content/service.test.ts (5 tests) 5ms
515
- ✓  node  test/sdk/orderEntry/useOrderFormItems.test.ts (7 tests) 46ms
516
- ✓  node  test/components/quotes/MyAccountQuotesSelectedTags.test.tsx (8 tests) 112ms
517
- ✓  node  test/sdk/account/refreshToken.test.ts (5 tests) 9ms
518
- ✓  node  test/server/cms/global.test.ts (3 tests) 6ms
519
- ✓  node  test/sdk/localization/store-url.test.ts (1 test) 4ms
520
- ✓  node  test/sdk/auth/useAuth.test.ts (5 tests) 29ms
497
+ ✓  node  test/sdk/account/useSetPassword.test.ts (6 tests) 20ms
498
+ ✓  node  test/sdk/orderEntry/useOrderEntryOperation.test.ts (8 tests) 24ms
499
+ ✓  node  test/components/quotes/MyAccountListQuotes.test.tsx (9 tests) 795ms
500
+ ✓ navigates with the search term on blur  360ms
501
+ ✓ navigates without a label param when the search is cleared  358ms
502
+ ✓  node  test/components/quotes/quoteFilters.test.ts (23 tests) 26ms
503
+ ✓  node  test/utils/multipleTemplates.test.ts (8 tests) 6ms
504
+ ✓  node  test/utils/localization/localizeRedirectDestination.test.ts (11 tests) 4ms
505
+ ✓  node  test/sdk/orderEntry/useOrderEntryUpload.test.ts (8 tests) 37ms
506
+ ✓  node  test/components/quotes/MyAccountQuotesFilterSlider.test.tsx (5 tests) 103ms
507
+ ✓  node  test/sdk/analytics/useStartRecommendationSession.test.ts (6 tests) 38ms
508
+ ✓  node  test/sdk/orderEntry/useOrderEntry.test.ts (8 tests) 30ms
509
+ ✓  node  test/proxy.localization.test.ts (5 tests) 28ms
510
+ ✓  node  test/sdk/account/getMyAccountRoutes.test.ts (10 tests) 5ms
511
+ ✓  node  test/sdk/session/syncSalesChannelFromOrderForm.test.ts (6 tests) 5ms
512
+ ✓  node  test/server/index.test.ts (7 tests) 946ms
513
+ ✓ should handle options and execute  513ms
514
+ ✓  node  test/proxy.test.ts (4 tests) 13ms
515
+ ✓  node  test/server/webops-api.test.ts (9 tests) 13ms
516
+ ✓  node  test/components/quotes/MyAccountQuotesSelectedTags.test.tsx (8 tests) 89ms
517
+ ✓  node  test/sdk/orderEntry/useOrderFormItems.test.ts (7 tests) 29ms
518
+ ✓  node  test/server/content/service.test.ts (5 tests) 4ms
519
+ ✓  node  test/sdk/cart/waitForSessionValidated.test.ts (5 tests) 9ms
520
+ ✓  node  test/sdk/account/refreshToken.test.ts (5 tests) 6ms
521
+ ✓  node  test/server/cms/global.test.ts (3 tests) 4ms
522
+ ✓  node  test/sdk/localization/store-url.test.ts (1 test) 2ms
523
+ ✓  node  test/sdk/auth/useAuth.test.ts (5 tests) 24ms
521
524
  ✓  node  test/sdk/analytics/hasEnabledRecommendationShelf.test.ts (6 tests) 4ms
522
- ✓  node  test/components/quotes/MyAccountQuotesStatusSelector.test.tsx (6 tests) 143ms
523
- ✓  node  test/utils/getRequestHostname.test.ts (12 tests) 8ms
524
- ✓  node  test/pages/api/preview.test.ts (2 tests) 11ms
525
+ ✓  node  test/components/quotes/MyAccountQuotesStatusSelector.test.tsx (6 tests) 92ms
526
+ ✓  node  test/utils/getRequestHostname.test.ts (12 tests) 3ms
527
+ ✓  node  test/pages/api/preview.test.ts (2 tests) 5ms
528
+ ✓  node  test/utils/validateSessionRefreshToken.test.ts (6 tests) 4ms
529
+ ✓  node  test/server/rootSpan.test.ts (4 tests) 38ms
525
530
  ✓  node  test/components/search/SearchInput.test.ts (6 tests) 6ms
526
- ✓  node  test/utils/validateSessionRefreshToken.test.ts (6 tests) 6ms
527
- ✓  node  test/server/rootSpan.test.ts (4 tests) 39ms
528
- ✓  node  test/components/RecommendationShelf/vrn.test.ts (5 tests) 7ms
529
- ✓  node  test/server/cms/index.test.ts (2 tests) 6ms
530
- ✓  node  test/utils/retry.test.ts (5 tests) 19ms
531
- ✓  node  test/components/account/Layout.test.tsx (4 tests) 42ms
532
- ✓  node  test/components/RecommendationShelf/useRecommendationUserId.test.ts (4 tests) 183ms
533
- ✓  node  test/utils/unlockResponse.test.ts (11 tests) 6ms
534
- ✓  node  test/server/cms/myAccountDefaultSections.test.ts (5 tests) 4ms
535
- ✓  node  test/components/RecommendationShelf/useRecommendations.test.ts (2 tests) 4ms
536
- ✓  node  test/utils/isLocalHost.test.ts (7 tests) 6ms
537
- ✓  node  test/components/account/OrganizationDrawerBody.test.tsx (3 tests) 42ms
538
- ✓  node  test/utils/userOrderStatus.test.ts (3 tests) 4ms
539
- ✓  node  test/sdk/analytics/utils.test.ts (2 tests) 4ms
540
- ✓  node  test/instrumentation.test.ts (3 tests) 7ms
541
- ✓  node  test/components/auth/ProfileChallenge.test.tsx (3 tests) 33ms
542
- ✓  node  test/sdk/account/clearPersistedSessionState.test.ts (1 test) 12ms
543
- ✓  node  test/components/quotes/MyAccountQuoteStatusBadge.test.tsx (2 tests) 25ms
544
-
545
-  Test Files  79 passed (79)
546
-  Tests  640 passed (640)
547
-  Start at  23:16:25
548
-  Duration  41.03s (transform 8.89s, setup 0ms, import 34.03s, tests 12.55s, environment 53.93s)
531
+ ✓  node  test/components/RecommendationShelf/vrn.test.ts (5 tests) 4ms
532
+ ✓  node  test/server/cms/index.test.ts (2 tests) 4ms
533
+ ✓  node  test/utils/retry.test.ts (5 tests) 12ms
534
+ ✓  node  test/components/account/Layout.test.tsx (4 tests) 29ms
535
+ ✓  node  test/components/RecommendationShelf/useRecommendationUserId.test.ts (4 tests) 185ms
536
+ ✓  node  test/utils/unlockResponse.test.ts (11 tests) 3ms
537
+ ✓  node  test/server/cms/myAccountDefaultSections.test.ts (5 tests) 5ms
538
+ ✓  node  test/components/RecommendationShelf/useRecommendations.test.ts (2 tests) 3ms
539
+ ✓  node  test/utils/isLocalHost.test.ts (7 tests) 4ms
540
+ ✓  node  test/utils/userOrderStatus.test.ts (3 tests) 3ms
541
+ ✓  node  test/components/account/OrganizationDrawerBody.test.tsx (3 tests) 33ms
542
+ ✓  node  test/sdk/analytics/utils.test.ts (2 tests) 3ms
543
+ ✓  node  test/instrumentation.test.ts (3 tests) 6ms
544
+ ✓  node  test/components/auth/ProfileChallenge.test.tsx (3 tests) 32ms
545
+ ✓  node  test/sdk/account/clearPersistedSessionState.test.ts (1 test) 13ms
546
+ ✓  node  test/components/quotes/MyAccountQuoteStatusBadge.test.tsx (2 tests) 18ms
547
+
548
+  Test Files  81 passed (81)
549
+  Tests  651 passed (651)
550
+  Start at  02:49:36
551
+  Duration  29.47s (transform 7.03s, setup 0ms, import 25.03s, tests 8.86s, environment 38.42s)
549
552
 
package/@generated/gql.ts CHANGED
@@ -45,7 +45,7 @@ type Documents = {
45
45
  "\n mutation ProcessOrderAuthorizationMutation($data: IProcessOrderAuthorization!) {\n processOrderAuthorization(data: $data) {\n isPendingForOtherAuthorizer\n ruleForAuthorization {\n orderAuthorizationId\n dimensionId\n rule {\n id\n name\n status\n doId\n authorizedEmails\n priority\n trigger {\n condition {\n conditionType\n description\n lessThan\n greatherThan\n expression\n }\n effect {\n description\n effectType\n funcPath\n }\n }\n timeout\n notification\n scoreInterval {\n accept\n deny\n }\n authorizationData {\n requireAllApprovals\n authorizers {\n id\n email\n type\n authorizationDate\n }\n }\n isUserAuthorized\n isUserNextAuthorizer\n }\n }\n }\n }\n": typeof types.ProcessOrderAuthorizationMutationDocument,
46
46
  "\n query ValidateUser {\n validateUser {\n isValid\n }\n }\n": typeof types.ValidateUserDocument,
47
47
  "\n mutation StartRecommendationSession {\n startRecommendationSession\n }\n": typeof types.StartRecommendationSessionDocument,
48
- "\n mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) {\n validateCart(cart: $cart, session: $session) {\n order {\n orderNumber\n acceptedOffer {\n ...CartItem\n }\n shouldSplitItem\n }\n messages {\n ...CartMessage\n }\n }\n }\n\n fragment CartMessage on StoreCartMessage {\n text\n status\n }\n\n fragment CartItem on StoreOffer {\n seller {\n identifier\n }\n quantity\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n isGift\n priceToken\n itemOffered {\n ...CartProductItem\n }\n }\n\n fragment CartProductItem on StoreProduct {\n sku\n name\n unitMultiplier\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n }\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n": typeof types.ValidateCartMutationDocument,
48
+ "\n mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) {\n validateCart(cart: $cart, session: $session) {\n order {\n orderNumber\n salesChannel\n acceptedOffer {\n ...CartItem\n }\n shouldSplitItem\n }\n messages {\n ...CartMessage\n }\n }\n }\n\n fragment CartMessage on StoreCartMessage {\n text\n status\n }\n\n fragment CartItem on StoreOffer {\n seller {\n identifier\n }\n quantity\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n isGift\n priceToken\n itemOffered {\n ...CartProductItem\n }\n }\n\n fragment CartProductItem on StoreProduct {\n sku\n name\n unitMultiplier\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n }\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n": typeof types.ValidateCartMutationDocument,
49
49
  "\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates) {\n pickupPointDistances {\n pickupId\n distance\n pickupName\n isActive\n address {\n city\n state\n number\n postalCode\n street\n }\n }\n }\n }\n": typeof types.ClientPickupPointsQueryDocument,
50
50
  "\n mutation SubscribeToNewsletter($data: IPersonNewsletter!) {\n subscribeToNewsletter(data: $data) {\n id\n }\n }\n": typeof types.SubscribeToNewsletterDocument,
51
51
  "\n mutation StartOrderEntryOperationMutation($data: IOrderEntryOperation!) {\n startOrderEntryOperation(data: $data) {\n operationId\n }\n }\n": typeof types.StartOrderEntryOperationMutationDocument,
@@ -97,7 +97,7 @@ const documents: Documents = {
97
97
  "\n mutation ProcessOrderAuthorizationMutation($data: IProcessOrderAuthorization!) {\n processOrderAuthorization(data: $data) {\n isPendingForOtherAuthorizer\n ruleForAuthorization {\n orderAuthorizationId\n dimensionId\n rule {\n id\n name\n status\n doId\n authorizedEmails\n priority\n trigger {\n condition {\n conditionType\n description\n lessThan\n greatherThan\n expression\n }\n effect {\n description\n effectType\n funcPath\n }\n }\n timeout\n notification\n scoreInterval {\n accept\n deny\n }\n authorizationData {\n requireAllApprovals\n authorizers {\n id\n email\n type\n authorizationDate\n }\n }\n isUserAuthorized\n isUserNextAuthorizer\n }\n }\n }\n }\n": types.ProcessOrderAuthorizationMutationDocument,
98
98
  "\n query ValidateUser {\n validateUser {\n isValid\n }\n }\n": types.ValidateUserDocument,
99
99
  "\n mutation StartRecommendationSession {\n startRecommendationSession\n }\n": types.StartRecommendationSessionDocument,
100
- "\n mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) {\n validateCart(cart: $cart, session: $session) {\n order {\n orderNumber\n acceptedOffer {\n ...CartItem\n }\n shouldSplitItem\n }\n messages {\n ...CartMessage\n }\n }\n }\n\n fragment CartMessage on StoreCartMessage {\n text\n status\n }\n\n fragment CartItem on StoreOffer {\n seller {\n identifier\n }\n quantity\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n isGift\n priceToken\n itemOffered {\n ...CartProductItem\n }\n }\n\n fragment CartProductItem on StoreProduct {\n sku\n name\n unitMultiplier\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n }\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n": types.ValidateCartMutationDocument,
100
+ "\n mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) {\n validateCart(cart: $cart, session: $session) {\n order {\n orderNumber\n salesChannel\n acceptedOffer {\n ...CartItem\n }\n shouldSplitItem\n }\n messages {\n ...CartMessage\n }\n }\n }\n\n fragment CartMessage on StoreCartMessage {\n text\n status\n }\n\n fragment CartItem on StoreOffer {\n seller {\n identifier\n }\n quantity\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n isGift\n priceToken\n itemOffered {\n ...CartProductItem\n }\n }\n\n fragment CartProductItem on StoreProduct {\n sku\n name\n unitMultiplier\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n }\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n": types.ValidateCartMutationDocument,
101
101
  "\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates) {\n pickupPointDistances {\n pickupId\n distance\n pickupName\n isActive\n address {\n city\n state\n number\n postalCode\n street\n }\n }\n }\n }\n": types.ClientPickupPointsQueryDocument,
102
102
  "\n mutation SubscribeToNewsletter($data: IPersonNewsletter!) {\n subscribeToNewsletter(data: $data) {\n id\n }\n }\n": types.SubscribeToNewsletterDocument,
103
103
  "\n mutation StartOrderEntryOperationMutation($data: IOrderEntryOperation!) {\n startOrderEntryOperation(data: $data) {\n operationId\n }\n }\n": types.StartOrderEntryOperationMutationDocument,
@@ -242,7 +242,7 @@ export function gql(source: "\n mutation StartRecommendationSession {\n star
242
242
  /**
243
243
  * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
244
244
  */
245
- export function gql(source: "\n mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) {\n validateCart(cart: $cart, session: $session) {\n order {\n orderNumber\n acceptedOffer {\n ...CartItem\n }\n shouldSplitItem\n }\n messages {\n ...CartMessage\n }\n }\n }\n\n fragment CartMessage on StoreCartMessage {\n text\n status\n }\n\n fragment CartItem on StoreOffer {\n seller {\n identifier\n }\n quantity\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n isGift\n priceToken\n itemOffered {\n ...CartProductItem\n }\n }\n\n fragment CartProductItem on StoreProduct {\n sku\n name\n unitMultiplier\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n }\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n"): typeof import('./graphql').ValidateCartMutationDocument;
245
+ export function gql(source: "\n mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) {\n validateCart(cart: $cart, session: $session) {\n order {\n orderNumber\n salesChannel\n acceptedOffer {\n ...CartItem\n }\n shouldSplitItem\n }\n messages {\n ...CartMessage\n }\n }\n }\n\n fragment CartMessage on StoreCartMessage {\n text\n status\n }\n\n fragment CartItem on StoreOffer {\n seller {\n identifier\n }\n quantity\n price\n priceWithTaxes\n listPrice\n listPriceWithTaxes\n isGift\n priceToken\n itemOffered {\n ...CartProductItem\n }\n }\n\n fragment CartProductItem on StoreProduct {\n sku\n name\n unitMultiplier\n image {\n url\n alternateName\n }\n brand {\n name\n }\n isVariantOf {\n productGroupID\n name\n skuVariants {\n activeVariations\n slugsMap\n availableVariations\n }\n }\n gtin\n additionalProperty {\n propertyID\n name\n value\n valueReference\n }\n }\n"): typeof import('./graphql').ValidateCartMutationDocument;
246
246
  /**
247
247
  * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
248
248
  */
@@ -1538,6 +1538,12 @@ export type StoreOrder = {
1538
1538
  acceptedOffer: Array<StoreOffer>;
1539
1539
  /** ID of the order in [VTEX order management](https://help.vtex.com/en/tutorial/license-manager-resources-oms--60QcBsvWeum02cFi3GjBzg#). */
1540
1540
  orderNumber: Scalars['String']['output'];
1541
+ /**
1542
+ * Sales channel of the underlying orderForm when FastStore adopted it because
1543
+ * the browser session was stale (e.g. after Quick Order). Clients should align
1544
+ * `session.channel` to this value. Null when no SC adoption happened.
1545
+ */
1546
+ salesChannel: Maybe<Scalars['String']['output']>;
1541
1547
  /** Indicates whether or not items with attachments should be split. */
1542
1548
  shouldSplitItem: Maybe<Scalars['Boolean']['output']>;
1543
1549
  };
@@ -2863,7 +2869,7 @@ export type ValidateCartMutationMutationVariables = Exact<{
2863
2869
  }>;
2864
2870
 
2865
2871
 
2866
- export type ValidateCartMutationMutation = { validateCart: { order: { orderNumber: string, shouldSplitItem: boolean | null, acceptedOffer: Array<{ quantity: number, price: number, priceWithTaxes: number, listPrice: number, listPriceWithTaxes: number, isGift: boolean | null, priceToken: string | null, seller: { identifier: string }, itemOffered: { sku: string, name: string, unitMultiplier: number | null, gtin: string, image: Array<{ url: string, alternateName: string }>, brand: { name: string }, isVariantOf: { productGroupID: string, name: string, skuVariants: { activeVariations: any | null, slugsMap: any | null, availableVariations: any | null } | null }, additionalProperty: Array<{ propertyID: string, name: string, value: any, valueReference: any }> } }> }, messages: Array<{ text: string, status: StoreStatus }> } | null };
2872
+ export type ValidateCartMutationMutation = { validateCart: { order: { orderNumber: string, salesChannel: string | null, shouldSplitItem: boolean | null, acceptedOffer: Array<{ quantity: number, price: number, priceWithTaxes: number, listPrice: number, listPriceWithTaxes: number, isGift: boolean | null, priceToken: string | null, seller: { identifier: string }, itemOffered: { sku: string, name: string, unitMultiplier: number | null, gtin: string, image: Array<{ url: string, alternateName: string }>, brand: { name: string }, isVariantOf: { productGroupID: string, name: string, skuVariants: { activeVariations: any | null, slugsMap: any | null, availableVariations: any | null } | null }, additionalProperty: Array<{ propertyID: string, name: string, value: any, valueReference: any }> } }> }, messages: Array<{ text: string, status: StoreStatus }> } | null };
2867
2873
 
2868
2874
  export type CartMessageFragment = { text: string, status: StoreStatus };
2869
2875
 
@@ -3565,7 +3571,7 @@ export const CancelOrderMutationDocument = {"__meta__":{"operationName":"CancelO
3565
3571
  export const ProcessOrderAuthorizationMutationDocument = {"__meta__":{"operationName":"ProcessOrderAuthorizationMutation","operationHash":"8c25d37c8d6e7c20ab21bb8a4f4e6a2fe320ea8d"}} as unknown as TypedDocumentString<ProcessOrderAuthorizationMutationMutation, ProcessOrderAuthorizationMutationMutationVariables>;
3566
3572
  export const ValidateUserDocument = {"__meta__":{"operationName":"ValidateUser","operationHash":"32f99c73c3de958b64d6bece1afe800469f54548"}} as unknown as TypedDocumentString<ValidateUserQuery, ValidateUserQueryVariables>;
3567
3573
  export const StartRecommendationSessionDocument = {"__meta__":{"operationName":"StartRecommendationSession","operationHash":"1def6438c0cd87b85002411ac7326c221f192583"}} as unknown as TypedDocumentString<StartRecommendationSessionMutation, StartRecommendationSessionMutationVariables>;
3568
- export const ValidateCartMutationDocument = {"__meta__":{"operationName":"ValidateCartMutation","operationHash":"8199d03debb0a6751ec53d8ee8987b78d0292acb"}} as unknown as TypedDocumentString<ValidateCartMutationMutation, ValidateCartMutationMutationVariables>;
3574
+ export const ValidateCartMutationDocument = {"__meta__":{"operationName":"ValidateCartMutation","operationHash":"3c71b0d3fc2bade14df68abfa271858beb361b12"}} as unknown as TypedDocumentString<ValidateCartMutationMutation, ValidateCartMutationMutationVariables>;
3569
3575
  export const ClientPickupPointsQueryDocument = {"__meta__":{"operationName":"ClientPickupPointsQuery","operationHash":"3fa04e88c811fcb5ece7206fd5aa745bdbc143a8"}} as unknown as TypedDocumentString<ClientPickupPointsQueryQuery, ClientPickupPointsQueryQueryVariables>;
3570
3576
  export const SubscribeToNewsletterDocument = {"__meta__":{"operationName":"SubscribeToNewsletter","operationHash":"feb7005103a859e2bc8cf2360d568806fd88deba"}} as unknown as TypedDocumentString<SubscribeToNewsletterMutation, SubscribeToNewsletterMutationVariables>;
3571
3577
  export const StartOrderEntryOperationMutationDocument = {"__meta__":{"operationName":"StartOrderEntryOperationMutation","operationHash":"78c50fbf9b85d03dbeac9b05b06405217f2ec440"}} as unknown as TypedDocumentString<StartOrderEntryOperationMutationMutation, StartOrderEntryOperationMutationMutationVariables>;
@@ -15,7 +15,7 @@
15
15
  "8c25d37c8d6e7c20ab21bb8a4f4e6a2fe320ea8d": "mutation ProcessOrderAuthorizationMutation($data: IProcessOrderAuthorization!) { processOrderAuthorization(data: $data) { isPendingForOtherAuthorizer ruleForAuthorization { dimensionId orderAuthorizationId rule { authorizationData { authorizers { authorizationDate email id type } requireAllApprovals } authorizedEmails doId id isUserAuthorized isUserNextAuthorizer name notification priority scoreInterval { accept deny } status timeout trigger { condition { conditionType description expression greatherThan lessThan } effect { description effectType funcPath } } } } } }",
16
16
  "32f99c73c3de958b64d6bece1afe800469f54548": "query ValidateUser { validateUser { isValid } }",
17
17
  "1def6438c0cd87b85002411ac7326c221f192583": "mutation StartRecommendationSession { startRecommendationSession }",
18
- "8199d03debb0a6751ec53d8ee8987b78d0292acb": "fragment CartItem on StoreOffer { isGift itemOffered { ...CartProductItem } listPrice listPriceWithTaxes price priceToken priceWithTaxes quantity seller { identifier } } fragment CartMessage on StoreCartMessage { status text } fragment CartProductItem on StoreProduct { additionalProperty { name propertyID value valueReference } brand { name } gtin image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations availableVariations slugsMap } } name sku unitMultiplier } mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) { validateCart(cart: $cart, session: $session) { messages { ...CartMessage } order { acceptedOffer { ...CartItem } orderNumber shouldSplitItem } } }",
18
+ "3c71b0d3fc2bade14df68abfa271858beb361b12": "fragment CartItem on StoreOffer { isGift itemOffered { ...CartProductItem } listPrice listPriceWithTaxes price priceToken priceWithTaxes quantity seller { identifier } } fragment CartMessage on StoreCartMessage { status text } fragment CartProductItem on StoreProduct { additionalProperty { name propertyID value valueReference } brand { name } gtin image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations availableVariations slugsMap } } name sku unitMultiplier } mutation ValidateCartMutation($cart: IStoreCart!, $session: IStoreSession!) { validateCart(cart: $cart, session: $session) { messages { ...CartMessage } order { acceptedOffer { ...CartItem } orderNumber salesChannel shouldSplitItem } } }",
19
19
  "3fa04e88c811fcb5ece7206fd5aa745bdbc143a8": "query ClientPickupPointsQuery($geoCoordinates: IStoreGeoCoordinates) { pickupPoints(geoCoordinates: $geoCoordinates) { pickupPointDistances { address { city number postalCode state street } distance isActive pickupId pickupName } } }",
20
20
  "feb7005103a859e2bc8cf2360d568806fd88deba": "mutation SubscribeToNewsletter($data: IPersonNewsletter!) { subscribeToNewsletter(data: $data) { id } }",
21
21
  "78c50fbf9b85d03dbeac9b05b06405217f2ec440": "mutation StartOrderEntryOperationMutation($data: IOrderEntryOperation!) { startOrderEntryOperation(data: $data) { operationId } }",
@@ -1538,6 +1538,12 @@ type StoreOrder {
1538
1538
  acceptedOffer: [StoreOffer!]!
1539
1539
  """Indicates whether or not items with attachments should be split."""
1540
1540
  shouldSplitItem: Boolean
1541
+ """
1542
+ Sales channel of the underlying orderForm when FastStore adopted it because
1543
+ the browser session was stale (e.g. after Quick Order). Clients should align
1544
+ `session.channel` to this value. Null when no SC adoption happened.
1545
+ """
1546
+ salesChannel: String
1541
1547
  }
1542
1548
 
1543
1549
  type StoreOrderEntryMissingItem {
package/CHANGELOG.md CHANGED
@@ -3,6 +3,15 @@
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.6.0-dev.2](https://github.com/vtex/faststore/compare/v4.6.0-dev.1...v4.6.0-dev.2) (2026-08-12)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **api:** address Sonar and harden session sales-channel sync ([5f6e8e9](https://github.com/vtex/faststore/commit/5f6e8e909def75f60c24cdaffae9303ed2c0a052))
11
+ - **api:** keep orderForm sales channel after stale validateCart sync ([09b051b](https://github.com/vtex/faststore/commit/09b051b80aaff7183adf7f5e86aece438bcd38f0))
12
+ - **api:** preserve orderForm sales channel in validateCart ([2336cda](https://github.com/vtex/faststore/commit/2336cda2c95970850dd0d29c1c18043ca8c9078a))
13
+ - **api:** sync adopted orderForm sales channel into session ([8943da7](https://github.com/vtex/faststore/commit/8943da7821f8abec08a39b7907a258bf156b05ee))
14
+
6
15
  # [4.6.0-dev.1](https://github.com/vtex/faststore/compare/v4.6.0-dev.0...v4.6.0-dev.1) (2026-08-11)
7
16
 
8
17
  ## [4.5.1](https://github.com/vtex/faststore/compare/v4.5.1-dev.4...v4.5.1) (2026-08-11)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "4.6.0-dev.1",
3
+ "version": "4.6.0-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.6.0-dev.1",
75
- "@faststore/ui": "4.6.0-dev.1",
76
- "@faststore/lighthouse": "4.6.0-dev.1",
77
- "@faststore/diagnostics": "4.6.0-dev.1",
78
- "@faststore/sdk": "4.6.0-dev.1"
74
+ "@faststore/diagnostics": "4.6.0-dev.2",
75
+ "@faststore/api": "4.6.0-dev.2",
76
+ "@faststore/lighthouse": "4.6.0-dev.2",
77
+ "@faststore/sdk": "4.6.0-dev.2",
78
+ "@faststore/ui": "4.6.0-dev.2"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@cypress/code-coverage": "^3.12.1",
@@ -13,8 +13,10 @@ import type {
13
13
 
14
14
  import storeConfig from '../../../discovery.config'
15
15
  import { request } from '../graphql/request'
16
- import { sessionStore } from '../session'
16
+ import { hasValidatedSessionStore, sessionStore } from '../session'
17
+ import { syncSalesChannelFromOrderForm } from '../session/syncSalesChannelFromOrderForm'
17
18
  import { createValidationStore, useStore } from '../useStore'
19
+ import { waitForSessionValidated } from './waitForSessionValidated'
18
20
 
19
21
  export interface CartItem
20
22
  extends SDKCartItem,
@@ -33,6 +35,7 @@ export const ValidateCartMutation = gql(`
33
35
  validateCart(cart: $cart, session: $session) {
34
36
  order {
35
37
  orderNumber
38
+ salesChannel
36
39
  acceptedOffer {
37
40
  ...CartItem
38
41
  }
@@ -114,6 +117,8 @@ const getItemId = (item: Pick<CartItem, 'itemOffered' | 'seller' | 'price'>) =>
114
117
  .join('::')
115
118
 
116
119
  const validateCart = async (cart: Cart): Promise<Cart | null> => {
120
+ await waitForSessionValidated(hasValidatedSessionStore)
121
+
117
122
  const { validateCart: validated = null } = await request<
118
123
  ValidateCartMutationMutation,
119
124
  ValidateCartMutationMutationVariables
@@ -151,6 +156,15 @@ const validateCart = async (cart: Cart): Promise<Cart | null> => {
151
156
  },
152
157
  })
153
158
 
159
+ const adoptedSalesChannel = validated?.order?.salesChannel
160
+ if (adoptedSalesChannel) {
161
+ syncSalesChannelFromOrderForm(
162
+ adoptedSalesChannel,
163
+ () => sessionStore.read(),
164
+ (session) => sessionStore.setSilent(session)
165
+ )
166
+ }
167
+
154
168
  return (
155
169
  validated && {
156
170
  id: validated.order.orderNumber,
@@ -0,0 +1,43 @@
1
+ import type { Store } from '@faststore/sdk'
2
+
3
+ /** Max time to wait for the first validateSession before validating the cart. */
4
+ export const SESSION_VALIDATION_WAIT_MS = 3_000
5
+
6
+ /**
7
+ * Defers cart validation until session has been validated at least once.
8
+ * This reduces first-paint races between Session and Cart; sales-channel
9
+ * correctness after external flows (e.g. Quick Order) is enforced in the API
10
+ * by preserving/adopting the orderForm SC.
11
+ */
12
+ export const waitForSessionValidated = async (
13
+ hasValidatedSessionStore: Store<boolean>,
14
+ waitMs = SESSION_VALIDATION_WAIT_MS
15
+ ): Promise<void> => {
16
+ if (hasValidatedSessionStore.read()) {
17
+ return
18
+ }
19
+
20
+ await new Promise<void>((resolve) => {
21
+ const timeoutId = setTimeout(() => {
22
+ unsubscribe()
23
+ resolve()
24
+ }, waitMs)
25
+
26
+ const unsubscribe = hasValidatedSessionStore.subscribe((validated) => {
27
+ if (!validated) {
28
+ return
29
+ }
30
+
31
+ clearTimeout(timeoutId)
32
+ unsubscribe()
33
+ resolve()
34
+ })
35
+
36
+ // Race: validation may have finished between read() and subscribe()
37
+ if (hasValidatedSessionStore.read()) {
38
+ clearTimeout(timeoutId)
39
+ unsubscribe()
40
+ resolve()
41
+ }
42
+ })
43
+ }
@@ -194,6 +194,9 @@ export const validateSession = async (session: Session) => {
194
194
  const [validationStore, onValidate, hasValidatedStore] =
195
195
  createValidationStore(validateSession)
196
196
 
197
+ /** True after at least one validateSession cycle finished (success or failure). */
198
+ export const hasValidatedSessionStore = hasValidatedStore
199
+
197
200
  const urlAwareInitialSession = getInitialSession()
198
201
  const defaultStore = createSessionStore(
199
202
  urlAwareInitialSession,
@@ -214,6 +217,17 @@ export const sessionStore = {
214
217
  // Trigger cart revalidation when session changes
215
218
  cartStore.set(cartStore.read())
216
219
  },
220
+ /**
221
+ * Updates session without revalidating the cart. Used when aligning
222
+ * `channel.salesChannel` to an orderForm SC adopted by `validateCart`.
223
+ * Still runs `validateSession` via the store's optimistic validator; that
224
+ * path keeps an explicit (non-default) client SC.
225
+ */
226
+ setSilent: (val: Session) => {
227
+ if (deepEqual(val, defaultStore.read()) === true) return
228
+
229
+ defaultStore.set(val)
230
+ },
217
231
  }
218
232
 
219
233
  export async function logoutAndClearSession(session: Session) {
@@ -0,0 +1,68 @@
1
+ import type { Session } from '@faststore/sdk'
2
+
3
+ function parseChannelRecord(
4
+ raw: string | null | undefined
5
+ ): Record<string, unknown> {
6
+ try {
7
+ const parsed: unknown = JSON.parse(raw || '{}')
8
+
9
+ if (
10
+ parsed !== null &&
11
+ typeof parsed === 'object' &&
12
+ !Array.isArray(parsed)
13
+ ) {
14
+ return parsed as Record<string, unknown>
15
+ }
16
+ } catch {
17
+ // Malformed channel — reset below.
18
+ }
19
+
20
+ return {}
21
+ }
22
+
23
+ function readSalesChannel(channel: Record<string, unknown>): string {
24
+ const value = channel.salesChannel
25
+
26
+ if (typeof value === 'string' || typeof value === 'number') {
27
+ return String(value)
28
+ }
29
+
30
+ return ''
31
+ }
32
+
33
+ /**
34
+ * Aligns `fs::session.channel` with a sales channel adopted from the orderForm
35
+ * (e.g. after Quick Order) without revalidating the cart.
36
+ *
37
+ * Uses `sessionStore.setSilent` so we do not trigger `cartStore.set` mid-flight
38
+ * (that race previously wiped SC-exclusive items). Marks the channel as
39
+ * explicit (`hasOnlyDefaultSalesChannel: false`) so `validateSession` keeps it.
40
+ */
41
+ export function syncSalesChannelFromOrderForm(
42
+ salesChannel: string | null | undefined,
43
+ readSession: () => Session,
44
+ setSilent: (session: Session) => void
45
+ ): boolean {
46
+ if (salesChannel == null || salesChannel === '') {
47
+ return false
48
+ }
49
+
50
+ const session = readSession()
51
+ const channel = parseChannelRecord(session.channel)
52
+ const nextSalesChannel = String(salesChannel)
53
+
54
+ if (readSalesChannel(channel) === nextSalesChannel) {
55
+ return false
56
+ }
57
+
58
+ setSilent({
59
+ ...session,
60
+ channel: JSON.stringify({
61
+ ...channel,
62
+ salesChannel: nextSalesChannel,
63
+ hasOnlyDefaultSalesChannel: false,
64
+ }),
65
+ })
66
+
67
+ return true
68
+ }
@@ -0,0 +1,96 @@
1
+ import { createBaseStore } from '@faststore/sdk'
2
+ import { afterEach, describe, expect, it, vi } from 'vitest'
3
+ import {
4
+ SESSION_VALIDATION_WAIT_MS,
5
+ waitForSessionValidated,
6
+ } from '../../../src/sdk/cart/waitForSessionValidated'
7
+
8
+ describe('waitForSessionValidated', () => {
9
+ afterEach(() => {
10
+ vi.useRealTimers()
11
+ })
12
+
13
+ it('resolves immediately when session was already validated', async () => {
14
+ const store = createBaseStore(true)
15
+
16
+ await expect(waitForSessionValidated(store)).resolves.toBeUndefined()
17
+ })
18
+
19
+ it('resolves when session becomes validated after subscribe', async () => {
20
+ const store = createBaseStore(false)
21
+
22
+ const pending = waitForSessionValidated(store, 5_000)
23
+ store.set(true)
24
+
25
+ await expect(pending).resolves.toBeUndefined()
26
+ })
27
+
28
+ it('ignores subscribe callbacks while validated is still false', async () => {
29
+ vi.useFakeTimers()
30
+ const listeners: Array<(value: boolean) => void> = []
31
+ const store = {
32
+ read: vi.fn(() => false),
33
+ readInitial: vi.fn(() => false),
34
+ subscribe: vi.fn((listener: (value: boolean) => void) => {
35
+ listeners.push(listener)
36
+ return () => {
37
+ const index = listeners.indexOf(listener)
38
+ if (index >= 0) {
39
+ listeners.splice(index, 1)
40
+ }
41
+ }
42
+ }),
43
+ set: vi.fn(),
44
+ }
45
+
46
+ const pending = waitForSessionValidated(store, SESSION_VALIDATION_WAIT_MS)
47
+
48
+ // Emit false — should not resolve yet
49
+ for (const listener of listeners) {
50
+ listener(false)
51
+ }
52
+
53
+ await vi.advanceTimersByTimeAsync(SESSION_VALIDATION_WAIT_MS)
54
+ await expect(pending).resolves.toBeUndefined()
55
+ })
56
+
57
+ it('resolves on timeout when session never validates', async () => {
58
+ vi.useFakeTimers()
59
+ const store = createBaseStore(false)
60
+
61
+ const pending = waitForSessionValidated(store, SESSION_VALIDATION_WAIT_MS)
62
+
63
+ await vi.advanceTimersByTimeAsync(SESSION_VALIDATION_WAIT_MS)
64
+
65
+ await expect(pending).resolves.toBeUndefined()
66
+ })
67
+
68
+ it('resolves the race when validation finishes between read and subscribe', async () => {
69
+ let current = false
70
+ const listeners: Array<(value: boolean) => void> = []
71
+
72
+ const store = {
73
+ read: vi.fn(() => {
74
+ // First read: not validated. Second read (post-subscribe): validated.
75
+ const value = current
76
+ current = true
77
+ return value
78
+ }),
79
+ readInitial: vi.fn(() => false),
80
+ subscribe: vi.fn((listener: (value: boolean) => void) => {
81
+ listeners.push(listener)
82
+ return () => {
83
+ const index = listeners.indexOf(listener)
84
+ if (index >= 0) {
85
+ listeners.splice(index, 1)
86
+ }
87
+ }
88
+ }),
89
+ set: vi.fn(),
90
+ }
91
+
92
+ await expect(waitForSessionValidated(store, 5_000)).resolves.toBeUndefined()
93
+ expect(store.subscribe).toHaveBeenCalledTimes(1)
94
+ expect(store.read).toHaveBeenCalledTimes(2)
95
+ })
96
+ })
@@ -0,0 +1,125 @@
1
+ import { describe, expect, it, vi } from 'vitest'
2
+ import type { Session } from '@faststore/sdk'
3
+ import { syncSalesChannelFromOrderForm } from '../../../src/sdk/session/syncSalesChannelFromOrderForm'
4
+
5
+ const baseSession = (
6
+ salesChannel: string,
7
+ explicit = true,
8
+ channelOverride?: string | null
9
+ ): Session => ({
10
+ currency: { code: 'BRL', symbol: 'R$' },
11
+ locale: 'pt-BR',
12
+ country: 'BRA',
13
+ channel:
14
+ channelOverride !== undefined
15
+ ? channelOverride
16
+ : JSON.stringify({
17
+ salesChannel,
18
+ regionId: '',
19
+ hasOnlyDefaultSalesChannel: !explicit,
20
+ }),
21
+ deliveryMode: null,
22
+ addressType: null,
23
+ city: null,
24
+ postalCode: null,
25
+ geoCoordinates: null,
26
+ person: null,
27
+ b2b: null,
28
+ marketingData: null,
29
+ refreshAfter: null,
30
+ })
31
+
32
+ describe('syncSalesChannelFromOrderForm', () => {
33
+ it('updates session channel silently when SC diverges', () => {
34
+ const setSilent = vi.fn()
35
+ const synced = syncSalesChannelFromOrderForm(
36
+ '2',
37
+ () => baseSession('1', false),
38
+ setSilent
39
+ )
40
+
41
+ expect(synced).toBe(true)
42
+ expect(setSilent).toHaveBeenCalledTimes(1)
43
+ const next = setSilent.mock.calls[0][0] as Session
44
+ expect(JSON.parse(next.channel ?? '{}')).toMatchObject({
45
+ salesChannel: '2',
46
+ hasOnlyDefaultSalesChannel: false,
47
+ })
48
+ })
49
+
50
+ it('is a no-op when SC already matches', () => {
51
+ const setSilent = vi.fn()
52
+ const synced = syncSalesChannelFromOrderForm(
53
+ '2',
54
+ () => baseSession('2'),
55
+ setSilent
56
+ )
57
+
58
+ expect(synced).toBe(false)
59
+ expect(setSilent).not.toHaveBeenCalled()
60
+ })
61
+
62
+ it('is a no-op when adopted SC is missing', () => {
63
+ const setSilent = vi.fn()
64
+ expect(
65
+ syncSalesChannelFromOrderForm(null, () => baseSession('1'), setSilent)
66
+ ).toBe(false)
67
+ expect(
68
+ syncSalesChannelFromOrderForm('', () => baseSession('1'), setSilent)
69
+ ).toBe(false)
70
+ expect(setSilent).not.toHaveBeenCalled()
71
+ })
72
+
73
+ it('resets non-object channel JSON before adopting SC', () => {
74
+ const setSilent = vi.fn()
75
+
76
+ for (const invalid of ['null', '[]', '"text"', '0', 'false']) {
77
+ setSilent.mockClear()
78
+ const synced = syncSalesChannelFromOrderForm(
79
+ '2',
80
+ () => baseSession('1', true, invalid),
81
+ setSilent
82
+ )
83
+
84
+ expect(synced).toBe(true)
85
+ expect(JSON.parse(setSilent.mock.calls[0][0].channel)).toMatchObject({
86
+ salesChannel: '2',
87
+ hasOnlyDefaultSalesChannel: false,
88
+ })
89
+ }
90
+ })
91
+
92
+ it('resets malformed channel JSON before adopting SC', () => {
93
+ const setSilent = vi.fn()
94
+ const synced = syncSalesChannelFromOrderForm(
95
+ '2',
96
+ () => baseSession('1', true, '{'),
97
+ setSilent
98
+ )
99
+
100
+ expect(synced).toBe(true)
101
+ expect(JSON.parse(setSilent.mock.calls[0][0].channel)).toMatchObject({
102
+ salesChannel: '2',
103
+ hasOnlyDefaultSalesChannel: false,
104
+ })
105
+ })
106
+
107
+ it('ignores object-valued salesChannel when comparing', () => {
108
+ const setSilent = vi.fn()
109
+ const synced = syncSalesChannelFromOrderForm(
110
+ '2',
111
+ () =>
112
+ baseSession(
113
+ '1',
114
+ true,
115
+ JSON.stringify({ salesChannel: { nested: true } })
116
+ ),
117
+ setSilent
118
+ )
119
+
120
+ expect(synced).toBe(true)
121
+ expect(JSON.parse(setSilent.mock.calls[0][0].channel).salesChannel).toBe(
122
+ '2'
123
+ )
124
+ })
125
+ })