@faststore/core 4.4.0-dev.3 → 4.4.0-dev.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/.turbo/turbo-generate.log +3 -3
  2. package/.turbo/turbo-test.log +49 -44
  3. package/CHANGELOG.md +12 -0
  4. package/README.md +15 -0
  5. package/package.json +6 -6
  6. package/src/components/account/Drawer/OrganizationDrawer/OrganizationDrawerBody.tsx +1 -1
  7. package/src/components/account/Menu/Menu.tsx +2 -1
  8. package/src/components/account/orders/ListOrders/FilterSlider/FilterSlider.tsx +5 -1
  9. package/src/components/account/orders/ListOrders/ListOrders.tsx +8 -3
  10. package/src/components/account/orders/ListOrders/ListOrdersTable/ListOrdersTable.tsx +6 -3
  11. package/src/components/account/orders/ListOrders/SelectedTags/SelectedTags.tsx +2 -2
  12. package/src/components/account/orders/OrderDetails/OrderDetailsHeader.tsx +6 -1
  13. package/src/components/account/utils/useFormatPrice.ts +3 -2
  14. package/src/components/ui/Link/Link.tsx +6 -0
  15. package/src/experimental/index.ts +3 -0
  16. package/src/experimental/myAccountServerSideProps.ts +6 -2
  17. package/src/pages/pvt/account/404.tsx +5 -1
  18. package/src/pages/pvt/account/[...unknown].tsx +6 -2
  19. package/src/pages/pvt/account/index.tsx +5 -4
  20. package/src/pages/pvt/account/profile.tsx +2 -1
  21. package/src/pages/pvt/account/user-details.tsx +4 -3
  22. package/src/proxy.ts +36 -0
  23. package/src/sdk/session/index.ts +9 -6
  24. package/src/sdk/session/initialSession.ts +31 -46
  25. package/src/utils/localization/localizeRedirectDestination.ts +66 -0
  26. package/src/utils/localization/withLocaleValidation.ts +0 -6
  27. package/test/proxy.localization.test.ts +122 -0
  28. package/test/sdk/session/reconcileSessionLocale.browser.test.ts +199 -0
  29. package/test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts +38 -0
  30. package/test/utils/localization/localizeRedirectDestination.test.ts +176 -0
  31. package/test/sdk/session/installLocaleCorrector.browser.test.ts +0 -208
@@ -1,9 +1,9 @@
1
1
 
2
- > @faststore/core@4.4.0-dev.2 generate /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@4.4.0-dev.4 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.4.0-dev.2 gen-types /home/runner/work/faststore/faststore/packages/core
6
+ > @faststore/core@4.4.0-dev.4 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.4.0-dev.2 cache-graphql /home/runner/work/faststore/faststore/packages/core
22
+ > @faststore/core@4.4.0-dev.4 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,18 +1,18 @@
1
1
 
2
- > @faststore/core@4.4.0-dev.2 test /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@4.4.0-dev.4 test /home/runner/work/faststore/faststore/packages/core
3
3
  > vitest run
4
4
 
5
5
 
6
6
   RUN  v4.0.7 /home/runner/work/faststore/faststore/packages/core
7
7
 
8
- ✓  browser  test/sdk/session/getInitialSession.browser.test.ts (6 tests) 32ms
9
- ✓  browser  test/sdk/session/installLocaleCorrector.browser.test.ts (7 tests) 74ms
10
- ✓  browser  test/utils/isLocalHost.browser.test.ts (3 tests) 14ms
8
+ ✓  browser  test/sdk/session/getInitialSession.browser.test.ts (6 tests) 26ms
9
+ ✓  browser  test/sdk/session/reconcileSessionLocale.browser.test.ts (5 tests) 34ms
10
+ ✓  browser  test/utils/isLocalHost.browser.test.ts (3 tests) 10ms
11
11
  stderr | test/sdk/localization/store-url.browser.test.ts
12
12
  Error in optimistic validation: TypeError: Cannot read properties of undefined (reading 'read')
13
13
  at validateCart (/home/runner/work/faststore/faststore/packages/core/src/sdk/cart/index.ts:119:27)
14
14
  at onValidate (/home/runner/work/faststore/faststore/packages/core/src/sdk/useStore.ts:18:20)
15
- at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:353:23)
15
+ at a (/home/runner/work/faststore/faststore/packages/sdk/dist/es/index.mjs:354:23)
16
16
   at processTicksAndRejections (node:internal/process/task_queues:103:5)
17
17
 
18
18
  stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > posts the password and redirects to the requested return path
@@ -100,7 +100,6 @@ act(() => {
100
100
  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
101
101
  at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
102
102
 
103
- ✓  node  test/utils/localization/bindingPaths.test.ts (71 tests) 38ms
104
103
  stderr | test/pages/password-protection.browser.test.tsx > PasswordProtectionLogin > uses the fallback invalid-password message when API omits an error
105
104
  Warning: An update to PasswordProtectionLogin inside a test was not wrapped in act(...).
106
105
 
@@ -245,14 +244,17 @@ act(() => {
245
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
246
245
  at PasswordProtectionLogin (/home/runner/work/faststore/faststore/packages/core/src/pages/password-protection/index.tsx:19:69)
247
246
 
248
- ✓  browser  test/pages/password-protection.browser.test.tsx (6 tests) 1502ms
249
- ✓ renders the password protection form  667ms
250
- ✓  browser  test/sdk/localization/store-url.browser.test.ts (3 tests) 22ms
251
- ✓  node  test/utils/match-url.test.ts (10 tests) 34ms
252
- ✓  node  test/server/password-protection-service.test.ts (22 tests) 145ms
253
- ✓  node  test/sdk/localization/bindingSelector.test.ts (18 tests) 34ms
254
- ✓  node  test/pages/api/unlock.test.ts (15 tests) 790ms
255
- ✓ returns 405 for non-POST requests  528ms
247
+ ✓  browser  test/pages/password-protection.browser.test.tsx (6 tests) 1906ms
248
+ ✓ renders the password protection form  799ms
249
+ ✓ posts the password and redirects to the requested return path  317ms
250
+ ✓  browser  test/sdk/localization/store-url.browser.test.ts (3 tests) 12ms
251
+ ✓  browser  test/sdk/session/reconcileSessionLocale.disabled.browser.test.ts (1 test) 11ms
252
+ ✓  node  test/utils/localization/bindingPaths.test.ts (71 tests) 74ms
253
+ ✓  node  test/utils/match-url.test.ts (10 tests) 39ms
254
+ ✓  node  test/server/password-protection-service.test.ts (22 tests) 140ms
255
+ ✓  node  test/sdk/localization/bindingSelector.test.ts (18 tests) 36ms
256
+ ✓  node  test/pages/api/unlock.test.ts (15 tests) 675ms
257
+ ✓ returns 405 for non-POST requests  477ms
256
258
  stderr | test/components/search/SearchInputComponent.test.tsx
257
259
  Warning: forwardRef render functions accept exactly two parameters: props and ref. Did you forget to use the ref parameter?
258
260
 
@@ -316,17 +318,18 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
316
318
  at Suspense
317
319
  at Wrapper (/home/runner/work/faststore/faststore/packages/core/test/components/search/SearchInputComponent.test.tsx:106:20)
318
320
 
319
- ✓  node  test/components/search/SearchInputComponent.test.tsx (6 tests) 198ms
320
- ✓  node  test/utils/cookieCacheBusting.test.ts (10 tests) 40ms
321
+ ✓  node  test/components/search/SearchInputComponent.test.tsx (6 tests) 248ms
322
+ ✓  node  test/utils/cookieCacheBusting.test.ts (10 tests) 71ms
321
323
  ✓  node  test/sdk/localization/useBindingSelector.test.tsx (12 tests) 37ms
322
- ✓  node  test/sdk/search/useSearchHistory.test.ts (13 tests) 218ms
323
- ✓  node  test/utils/clearCookies.test.ts (20 tests) 99ms
324
- ✓  node  test/utils/multipleTemplates.test.ts (8 tests) 17ms
324
+ ✓  node  test/sdk/search/useSearchHistory.test.ts (13 tests) 203ms
325
+ ✓  node  test/utils/clearCookies.test.ts (20 tests) 59ms
326
+ ✓  node  test/utils/multipleTemplates.test.ts (8 tests) 8ms
327
+ ✓  node  test/utils/localization/localizeRedirectDestination.test.ts (11 tests) 11ms
328
+ ✓  node  test/sdk/orderEntry/useOrderEntryOperation.test.ts (8 tests) 55ms
325
329
  stderr | test/sdk/account/useSetPassword.test.ts > useSetPassword > maps wrongcredentials error responses to the existing message
326
330
  Set password request failed: Bad Request
327
331
 
328
- ✓  node  test/sdk/account/useSetPassword.test.ts (6 tests) 48ms
329
- ✓  node  test/sdk/orderEntry/useOrderEntryOperation.test.ts (8 tests) 73ms
332
+ ✓  node  test/sdk/account/useSetPassword.test.ts (6 tests) 44ms
330
333
  stderr | test/pages/api/graphql.test.ts > /api/graphql error status propagation > propagates the upstream 400 from a wrapped BadRequestError instead of 500
331
334
  Graphql execution returned with error: [
332
335
  {
@@ -373,29 +376,31 @@ Warning: React does not recognize the `providerProps` prop on a DOM element. If
373
376
  { message: 'bad', status: 400, type: 'BadRequestError' }
374
377
  ]
375
378
 
376
- ✓  node  test/pages/api/graphql.test.ts (10 tests) 22ms
377
- ✓  node  test/sdk/orderEntry/useOrderEntryUpload.test.ts (8 tests) 59ms
378
- ✓  node  test/sdk/orderEntry/useOrderEntry.test.ts (8 tests) 37ms
379
- ✓  node  test/proxy.test.ts (4 tests) 50ms
380
- ✓  node  test/sdk/orderEntry/useOrderFormItems.test.ts (7 tests) 52ms
381
- ✓  node  test/server/webops-api.test.ts (9 tests) 18ms
382
- ✓  node  test/server/index.test.ts (7 tests) 667ms
383
- ✓  node  test/server/cms/global.test.ts (3 tests) 7ms
384
- ✓  node  test/sdk/localization/store-url.test.ts (1 test) 4ms
385
- ✓  node  test/server/content/service.test.ts (5 tests) 4ms
386
- ✓  node  test/utils/getRequestHostname.test.ts (12 tests) 7ms
387
- ✓  node  test/sdk/auth/useAuth.test.ts (5 tests) 32ms
388
- ✓  node  test/pages/api/preview.test.ts (2 tests) 6ms
389
- ✓  node  test/utils/validateSessionRefreshToken.test.ts (6 tests) 4ms
390
- ✓  node  test/utils/unlockResponse.test.ts (11 tests) 5ms
391
- ✓  node  test/components/search/SearchInput.test.ts (6 tests) 7ms
392
- ✓  node  test/server/cms/index.test.ts (2 tests) 6ms
393
- ✓  node  test/utils/isLocalHost.test.ts (7 tests) 7ms
379
+ ✓  node  test/pages/api/graphql.test.ts (10 tests) 27ms
380
+ ✓  node  test/sdk/orderEntry/useOrderEntryUpload.test.ts (8 tests) 51ms
381
+ ✓  node  test/proxy.localization.test.ts (5 tests) 55ms
382
+ ✓  node  test/sdk/orderEntry/useOrderEntry.test.ts (8 tests) 42ms
383
+ ✓  node  test/proxy.test.ts (4 tests) 29ms
384
+ ✓  node  test/sdk/orderEntry/useOrderFormItems.test.ts (7 tests) 33ms
385
+ ✓  node  test/server/index.test.ts (7 tests) 921ms
386
+ ✓ should handle options and execute  464ms
387
+ ✓  node  test/server/webops-api.test.ts (9 tests) 16ms
388
+ ✓  node  test/server/cms/global.test.ts (3 tests) 6ms
389
+ ✓  node  test/sdk/localization/store-url.test.ts (1 test) 9ms
390
+ ✓  node  test/server/content/service.test.ts (5 tests) 6ms
391
+ ✓  node  test/utils/getRequestHostname.test.ts (12 tests) 8ms
392
+ ✓  node  test/sdk/auth/useAuth.test.ts (5 tests) 31ms
393
+ ✓  node  test/pages/api/preview.test.ts (2 tests) 9ms
394
+ ✓  node  test/utils/validateSessionRefreshToken.test.ts (6 tests) 5ms
395
+ ✓  node  test/components/search/SearchInput.test.ts (6 tests) 8ms
396
+ ✓  node  test/utils/unlockResponse.test.ts (11 tests) 6ms
397
+ ✓  node  test/server/cms/index.test.ts (2 tests) 7ms
398
+ ✓  node  test/utils/isLocalHost.test.ts (7 tests) 5ms
394
399
  ✓  node  test/utils/userOrderStatus.test.ts (3 tests) 3ms
395
- ✓  node  test/components/auth/ProfileChallenge.test.tsx (3 tests) 25ms
400
+ ✓  node  test/components/auth/ProfileChallenge.test.tsx (3 tests) 26ms
396
401
 
397
-  Test Files  38 passed (38)
398
-  Tests  363 passed (363)
399
-  Start at  13:16:14
400
-  Duration  23.17s (transform 6.25s, setup 0ms, collect 17.58s, tests 4.44s, environment 28.99s, prepare 945ms)
402
+  Test Files  41 passed (41)
403
+  Tests  378 passed (378)
404
+  Start at  14:13:54
405
+  Duration  25.97s (transform 6.84s, setup 0ms, collect 19.27s, tests 5.00s, environment 35.56s, prepare 1.21s)
401
406
 
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.4.0-dev.5](https://github.com/vtex/faststore/compare/v4.4.0-dev.4...v4.4.0-dev.5) (2026-07-01)
7
+
8
+ ### Features
9
+
10
+ - make cms-sync content-source aware (CMS + CP) ([#3406](https://github.com/vtex/faststore/issues/3406)) ([8e4e4ca](https://github.com/vtex/faststore/commit/8e4e4cab61b6e6fec05b8ae014e4ed2298028b92)), closes [#5c1a1](https://github.com/vtex/faststore/issues/5c1a1) [#ff6b6](https://github.com/vtex/faststore/issues/ff6b6) [#3a0d0](https://github.com/vtex/faststore/issues/3a0d0) [#ff6b6](https://github.com/vtex/faststore/issues/ff6b6) [#10391](https://github.com/vtex/faststore/issues/10391) [#3ddc84](https://github.com/vtex/faststore/issues/3ddc84) [#1](https://github.com/vtex/faststore/issues/1) [#14](https://github.com/vtex/faststore/issues/14) [#15](https://github.com/vtex/faststore/issues/15) [#18](https://github.com/vtex/faststore/issues/18)
11
+
12
+ # [4.4.0-dev.4](https://github.com/vtex/faststore/compare/v4.4.0-dev.3...v4.4.0-dev.4) (2026-06-30)
13
+
14
+ ### Features
15
+
16
+ - add i18n support for /pvt/account navigation ([#3400](https://github.com/vtex/faststore/issues/3400)) ([695dd0e](https://github.com/vtex/faststore/commit/695dd0ee8e06e32ad76c23925c5e095740430f0f))
17
+
6
18
  # [4.4.0-dev.3](https://github.com/vtex/faststore/compare/v4.4.0-dev.2...v4.4.0-dev.3) (2026-06-29)
7
19
 
8
20
  ### Bug Fixes
package/README.md CHANGED
@@ -124,6 +124,21 @@ vtex content split-content-types -i cms/faststore/content-types.json -s cms/fast
124
124
  ```
125
125
 
126
126
  IMPORTANT: The Faststore Core Team is the only one that needs to add the -l base.jsonc to the output. Merchants will automatically use the base from the Schema Registry.
127
+
128
+ **Store developers:** set `contentSource: { type: 'CP' }` in `discovery.config.js`, place custom schemas under `cms/faststore/components/` and/or `cms/faststore/pages/`, then run:
129
+
130
+ ```sh
131
+ yarn cms-sync
132
+ ```
133
+
134
+ `cms-sync` detects the content source automatically — in CP mode it generates the schema from your customizations and uploads it to the Schema Registry. Use `--dry-run` to generate locally without uploading.
135
+
136
+ Before running anything in CP mode, `cms-sync` checks that the `vtex` toolbelt is installed and that you are logged into your store's account (`api.storeId` in `discovery.config.js`); otherwise it stops with a hint to run `vtex login <account>` / `vtex switch <account>`. The toolbelt is interactive: `generate-schema` asks you to confirm when one of your definitions overrides a base one, and `upload-schema` asks for the version to publish — answer the prompts in your terminal.
137
+
138
+ If `experimental.enableFaststoreMyAccount` is enabled, `cms-sync` also merges the core My Account schemas (shipped in `@faststore/core`) into the generated schema. These schemas are intentionally excluded from the published base schema (so they are not in the Schema Registry). The command performs a file-level merge of the core My Account JSONC with your own `cms/faststore/{components,pages}` into a temporary staging directory under your store's `.faststore/` (your files override core on name collision), runs a single `generate-schema`/`upload-schema` over it, announces the merge, and removes the staging directory afterwards.
139
+
140
+ **FastStore Core team** (publishing the base schema with the core layer):
141
+
127
142
  2. Generate the schema:
128
143
  ```sh
129
144
  vtex content generate-schema cms/faststore/components cms/faststore/pages -l cms/faststore/base.jsonc -o cms/faststore/schema.json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "4.4.0-dev.3",
3
+ "version": "4.4.0-dev.5",
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.4.0-dev.3",
75
- "@faststore/diagnostics": "4.4.0-dev.3",
76
- "@faststore/sdk": "4.4.0-dev.3",
77
- "@faststore/lighthouse": "4.4.0-dev.3",
78
- "@faststore/ui": "4.4.0-dev.3"
74
+ "@faststore/api": "4.4.0-dev.5",
75
+ "@faststore/diagnostics": "4.4.0-dev.5",
76
+ "@faststore/lighthouse": "4.4.0-dev.5",
77
+ "@faststore/ui": "4.4.0-dev.5",
78
+ "@faststore/sdk": "4.4.0-dev.5"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@cypress/code-coverage": "^3.12.1",
@@ -1,4 +1,4 @@
1
- import { Link } from '@faststore/ui'
1
+ import Link from 'src/components/ui/Link'
2
2
 
3
3
  import menuRoutes from 'src/customizations/src/myAccount/navigation'
4
4
  import { useAccountNavigationLabels } from 'src/sdk/account/accountPageContext'
@@ -1,6 +1,7 @@
1
- import { Button, Link } from '@faststore/ui'
1
+ import { Button } from '@faststore/ui'
2
2
  import { useRouter } from 'next/router'
3
3
 
4
+ import Link from 'src/components/ui/Link'
4
5
  import styles from '../section.module.scss'
5
6
 
6
7
  import { useAccountNavigationLabels } from 'src/sdk/account/accountPageContext'
@@ -8,6 +8,7 @@ import {
8
8
  } from '@faststore/ui'
9
9
 
10
10
  import { type MutableRefObject, useRef, useState } from 'react'
11
+ import { useLink } from 'src/sdk/ui/useLink'
11
12
  import type {
12
13
  MyAccountFilter_FacetsFragment,
13
14
  useMyAccountFilter,
@@ -61,6 +62,7 @@ function FilterSlider({
61
62
  toLabel,
62
63
  invalidDateRangeLabel,
63
64
  }: FilterSliderProps & ReturnType<typeof useMyAccountFilter>) {
65
+ const { resolveLink } = useLink()
64
66
  const dateRangeInputRef = useRef<{
65
67
  clear: () => void
66
68
  getDataRangeFacet: () => {
@@ -121,7 +123,9 @@ function FilterSlider({
121
123
  }
122
124
  })
123
125
 
124
- window.location.href = `/pvt/account/orders?${params.toString()}`
126
+ const ordersHref =
127
+ resolveLink('/pvt/account/orders') ?? '/pvt/account/orders'
128
+ window.location.href = `${ordersHref}?${params.toString()}`
125
129
  }
126
130
 
127
131
  return (
@@ -20,6 +20,7 @@ import {
20
20
  type MyAccountFilter_FacetsFragment,
21
21
  type SelectedFacet,
22
22
  } from 'src/sdk/search/useMyAccountFilter'
23
+ import { useLink } from 'src/sdk/ui/useLink'
23
24
  import useScreenResize from 'src/sdk/ui/useScreenResize'
24
25
  import { FastStoreOrderStatus } from 'src/utils/userOrderStatus'
25
26
  import AccountHeader from '../../components/Header'
@@ -32,6 +33,8 @@ import ListOrdersTable, { Pagination } from './ListOrdersTable/ListOrdersTable'
32
33
  import SelectedFiltersTags from './SelectedTags/SelectedTags'
33
34
  import styles from './styles.module.scss'
34
35
 
36
+ const ORDERS_PATH = '/pvt/account/orders'
37
+
35
38
  export type ListOrdersProps = {
36
39
  listOrders: ServerListOrdersQueryQuery['listUserOrders']
37
40
  total: number
@@ -145,6 +148,8 @@ export default function ListOrders({
145
148
  }: ListOrdersProps) {
146
149
  const labels = resolveListOrdersLabels(labelsProp)
147
150
  const router = useRouter()
151
+ const { resolveLink } = useLink()
152
+ const ordersHref = resolveLink(ORDERS_PATH) ?? ORDERS_PATH
148
153
  const { isDesktop } = useScreenResize()
149
154
  const searchInputRef = useRef(null) as MutableRefObject<SearchInputFieldRef>
150
155
 
@@ -179,7 +184,7 @@ export default function ListOrders({
179
184
  params.set('text', value)
180
185
  }
181
186
 
182
- window.location.href = `/pvt/account/orders?${params.toString()}`
187
+ window.location.href = `${ordersHref}?${params.toString()}`
183
188
  }
184
189
  },
185
190
  300,
@@ -263,7 +268,7 @@ export default function ListOrders({
263
268
  pendingMyApproval: filters.pendingMyApproval,
264
269
  }}
265
270
  onClearAll={() => {
266
- window.location.href = '/pvt/account/orders'
271
+ window.location.href = ordersHref
267
272
  }}
268
273
  onRemoveFilter={(key, value) => {
269
274
  const { page, clientEmail, ...updatedFilters } = { ...filters }
@@ -289,7 +294,7 @@ export default function ListOrders({
289
294
  const params = new URLSearchParams(
290
295
  filteredQuery as Record<string, string>
291
296
  )
292
- window.location.href = `/pvt/account/orders?${params.toString()}`
297
+ window.location.href = `${ordersHref}?${params.toString()}`
293
298
  }}
294
299
  />
295
300
 
@@ -1,10 +1,11 @@
1
1
  import { Icon, IconButton } from '@faststore/ui'
2
2
 
3
+ import { useRouter } from 'next/router'
3
4
  import { useState } from 'react'
4
5
 
5
6
  import StatusBadge from 'src/components/account/components/StatusBadge'
6
7
  import { useFormatPrice } from 'src/components/account/utils/useFormatPrice'
7
- import { useSession } from 'src/sdk/session'
8
+ import { useLink } from 'src/sdk/ui/useLink'
8
9
  import useScreenResize from 'src/sdk/ui/useScreenResize'
9
10
  import { ExpandButton } from './ExpandButton/ExpandButton'
10
11
 
@@ -53,6 +54,8 @@ export function Pagination({
53
54
  labels?: ListOrdersSectionLabels
54
55
  }) {
55
56
  const labels = resolveListOrdersLabels(labelsProp)
57
+ const { resolveLink } = useLink()
58
+ const ordersHref = resolveLink('/pvt/account/orders') ?? '/pvt/account/orders'
56
59
  const totalPages = Math.ceil(total / perPage)
57
60
  const firstIndexLabel = page === 1 ? 1 : (page - 1) * perPage + 1
58
61
  const lastIndexLabel =
@@ -67,7 +70,7 @@ export function Pagination({
67
70
  } else {
68
71
  params.set('page', String(newPage))
69
72
  }
70
- window.location.href = `/pvt/account/orders${params.toString() ? `?${params}` : ''}`
73
+ window.location.href = `${ordersHref}${params.toString() ? `?${params}` : ''}`
71
74
  }
72
75
 
73
76
  return (
@@ -105,7 +108,7 @@ export default function ListOrdersTable({
105
108
  const labels = resolveListOrdersLabels(labelsProp)
106
109
  const statusLabels = pickOrderStatusCmsLabels(labels)
107
110
  const { isDesktop } = useScreenResize()
108
- const { locale } = useSession()
111
+ const { locale } = useRouter()
109
112
  const formatPrice = useFormatPrice()
110
113
 
111
114
  const [expandedRows, setExpandedRows] = useState<
@@ -1,5 +1,5 @@
1
1
  import { Button } from '@faststore/ui'
2
- import { useSession } from 'src/sdk/session'
2
+ import { useRouter } from 'next/router'
3
3
  import {
4
4
  type ListOrdersSectionLabels,
5
5
  getStatusDisplayLabels,
@@ -48,7 +48,7 @@ function Tags({
48
48
  }: Pick<SelectedTagsProps, 'filters' | 'onRemoveFilter' | 'labels'>) {
49
49
  const labels = resolveListOrdersLabels(labelsProp)
50
50
  const statusDisplayLabels = getStatusDisplayLabels(labels)
51
- const { locale } = useSession()
51
+ const { locale } = useRouter()
52
52
  const { dateInitial, dateFinal, status, pendingMyApproval } = filters
53
53
 
54
54
  const formattedDateInitial = dateInitial
@@ -1,6 +1,7 @@
1
1
  import { Icon as UIIcon, IconButton as UIIconButton } from '@faststore/ui'
2
2
  import type { PropsWithChildren } from 'react'
3
3
  import type { ServerOrderDetailsQueryQuery } from '@generated/graphql'
4
+ import { useLink } from 'src/sdk/ui/useLink'
4
5
  import type { OrderStatusCmsLabels } from 'src/utils/userOrderStatus'
5
6
  import StatusBadge from '../../components/StatusBadge'
6
7
  import BuyingPolicyAlert from './BuyingPolicyAlert'
@@ -12,6 +13,8 @@ import {
12
13
  } from './orderDetailsLabels'
13
14
  import styles from './section.module.scss'
14
15
 
16
+ const ORDERS_PATH = '/pvt/account/orders'
17
+
15
18
  export type OrderDetailsHeaderProps = {
16
19
  order: ServerOrderDetailsQueryQuery['userOrder']
17
20
  labels?: OrderDetailsHeaderLabels
@@ -24,12 +27,14 @@ export function OrderDetailsHeader({
24
27
  statusLabels,
25
28
  }: OrderDetailsHeaderProps) {
26
29
  const labels = resolveOrderDetailsHeaderLabels(labelsProp)
30
+ const { resolveLink } = useLink()
31
+ const ordersHref = resolveLink(ORDERS_PATH) ?? ORDERS_PATH
27
32
 
28
33
  return (
29
34
  <>
30
35
  <header data-fs-order-details-header>
31
36
  <div data-fs-order-details-header-title>
32
- <a href="/pvt/account/orders">
37
+ <a href={ordersHref}>
33
38
  <UIIconButton
34
39
  data-fs-order-details-header-back-button
35
40
  size="small"
@@ -1,9 +1,10 @@
1
- import { useSession } from 'src/sdk/session'
1
+ import { useRouter } from 'next/router'
2
2
  import { useCallback } from 'react'
3
3
 
4
4
  // Format price values according to the specified currency (converts cents to standard units)
5
5
  export const useFormatPrice = () => {
6
- const { locale } = useSession()
6
+ // get locale from router instead of using useSession to avoid SSR hydration issues
7
+ const { locale } = useRouter()
7
8
 
8
9
  return useCallback(
9
10
  (value: number, currencyCode: string) => {
@@ -45,6 +45,12 @@ const Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link<
45
45
  inverse={inverse}
46
46
  passHref
47
47
  href={finalHref}
48
+ // resolveLink already produces the fully localized href (custom path or
49
+ // explicit locale prefix), so NextLink must not add its own locale
50
+ // prefix on top of it. Otherwise SSR over-localizes (e.g.
51
+ // /it-IT/europe/it/...) while the client keeps /europe/it/..., causing
52
+ // a hydration mismatch.
53
+ locale={false}
48
54
  legacyBehavior={false}
49
55
  prefetch={prefetch}
50
56
  {...otherProps}
@@ -79,3 +79,6 @@ export type {
79
79
  Locale,
80
80
  } from '../sdk/localization/types'
81
81
  export type { UseBindingSelectorReturn } from '../sdk/localization/useBindingSelector'
82
+ export { useLink as useLink_unstable } from '../sdk/ui/useLink'
83
+ export { default as Link_unstable } from '../components/ui/Link'
84
+ export { localizeRedirectDestination as localizeRedirectDestination_unstable } from '../utils/localization/localizeRedirectDestination'
@@ -15,6 +15,7 @@ import { execute } from 'src/server'
15
15
 
16
16
  import { validateUser } from 'src/sdk/account/validateUser'
17
17
  import { injectGlobalSections } from 'src/server/cms/global'
18
+ import { localizeRedirectDestination } from 'src/utils/localization/localizeRedirectDestination'
18
19
  import { withLocaleValidationSSR } from 'src/utils/localization/withLocaleValidation'
19
20
  import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
20
21
  import storeConfig from '../../discovery.config'
@@ -48,7 +49,7 @@ const getServerSidePropsBase: GetServerSideProps<
48
49
  if (!validationResult.isValid && !validationResult.needsRefresh) {
49
50
  return {
50
51
  redirect: {
51
- destination: '/login',
52
+ destination: localizeRedirectDestination('/login', context),
52
53
  permanent: false,
53
54
  },
54
55
  }
@@ -59,7 +60,10 @@ const getServerSidePropsBase: GetServerSideProps<
59
60
  const currentPath = context.req.url || '/pvt/account'
60
61
  return {
61
62
  redirect: {
62
- destination: `/pvt/account/403?from=${encodeURIComponent(currentPath)}`,
63
+ destination: localizeRedirectDestination(
64
+ `/pvt/account/403?from=${encodeURIComponent(currentPath)}`,
65
+ context
66
+ ),
63
67
  permanent: false,
64
68
  },
65
69
  }
@@ -24,6 +24,7 @@ import PageProvider from 'src/sdk/overrides/PageProvider'
24
24
  import { execute } from 'src/server'
25
25
  import { type PageContentType, getPage } from 'src/server/cms'
26
26
  import { injectGlobalSections } from 'src/server/cms/global'
27
+ import { localizeRedirectDestination } from 'src/utils/localization/localizeRedirectDestination'
27
28
  import { withLocaleValidationSSR } from 'src/utils/localization/withLocaleValidation'
28
29
  import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
29
30
 
@@ -128,7 +129,10 @@ const getServerSidePropsBase: GetServerSideProps<
128
129
  if (statusCode === 401 || statusCode === 403) {
129
130
  return {
130
131
  redirect: {
131
- destination: `/pvt/account/403?from=${encodeURIComponent('/pvt/account/404')}`,
132
+ destination: localizeRedirectDestination(
133
+ `/pvt/account/403?from=${encodeURIComponent('/pvt/account/404')}`,
134
+ context
135
+ ),
132
136
  permanent: false,
133
137
  },
134
138
  }
@@ -2,6 +2,7 @@ import type { Locator } from '@vtex/client-cms'
2
2
  import type { GetStaticPaths, GetStaticProps } from 'next'
3
3
 
4
4
  import type { MyAccountProps } from 'src/experimental/myAccountServerSideProps'
5
+ import { localizeRedirectDestination } from 'src/utils/localization/localizeRedirectDestination'
5
6
  import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
6
7
 
7
8
  export default function Page() {
@@ -12,7 +13,7 @@ export const getStaticProps: GetStaticProps<
12
13
  MyAccountProps,
13
14
  Record<string, string>,
14
15
  Locator
15
- > = async () => {
16
+ > = async ({ locale, defaultLocale }) => {
16
17
  const { isFaststoreMyAccountEnabled, redirect } = getMyAccountRedirect({
17
18
  query: {},
18
19
  })
@@ -23,7 +24,10 @@ export const getStaticProps: GetStaticProps<
23
24
 
24
25
  return {
25
26
  redirect: {
26
- destination: '/pvt/account/404',
27
+ destination: localizeRedirectDestination('/pvt/account/404', {
28
+ locale,
29
+ defaultLocale,
30
+ }),
27
31
  permanent: false,
28
32
  },
29
33
  }
@@ -1,14 +1,15 @@
1
1
  import type { GetServerSideProps, NextPage } from 'next'
2
- import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
2
+ import { localizeRedirectDestination } from 'src/utils/localization/localizeRedirectDestination'
3
3
  import { withLocaleValidationSSR } from 'src/utils/localization/withLocaleValidation'
4
+ import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
4
5
 
5
6
  const MyAccountRedirectPage: NextPage = () => {
6
7
  return null
7
8
  }
8
9
 
9
- const getServerSidePropsBase: GetServerSideProps = async ({ query, req }) => {
10
+ const getServerSidePropsBase: GetServerSideProps = async (context) => {
10
11
  const { isFaststoreMyAccountEnabled, redirect } = getMyAccountRedirect({
11
- query,
12
+ query: context.query,
12
13
  })
13
14
 
14
15
  if (!isFaststoreMyAccountEnabled) {
@@ -17,7 +18,7 @@ const getServerSidePropsBase: GetServerSideProps = async ({ query, req }) => {
17
18
 
18
19
  return {
19
20
  redirect: {
20
- destination: '/pvt/account/profile',
21
+ destination: localizeRedirectDestination('/pvt/account/profile', context),
21
22
  permanent: false,
22
23
  },
23
24
  }
@@ -27,6 +27,7 @@ import { injectGlobalSections } from 'src/server/cms/global'
27
27
  import { extractAccountNavigationData } from 'src/server/cms/myAccountDefaultSections'
28
28
  import { fetchMyAccountPageContent } from 'src/server/cms/fetchMyAccountPageContent'
29
29
  import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
30
+ import { localizeRedirectDestination } from 'src/utils/localization/localizeRedirectDestination'
30
31
  import { withLocaleValidationSSR } from 'src/utils/localization/withLocaleValidation'
31
32
 
32
33
  import storeConfig from 'discovery.config'
@@ -157,7 +158,7 @@ const getServerSidePropsBase: GetServerSideProps<
157
158
 
158
159
  return {
159
160
  redirect: {
160
- destination,
161
+ destination: localizeRedirectDestination(destination, context),
161
162
  permanent: false,
162
163
  },
163
164
  }
@@ -27,8 +27,9 @@ import { getIsRepresentative } from 'src/sdk/account/getIsRepresentative'
27
27
  import PageProvider from 'src/sdk/overrides/PageProvider'
28
28
  import { execute } from 'src/server'
29
29
  import { injectGlobalSections } from 'src/server/cms/global'
30
- import { extractAccountNavigationData } from 'src/server/cms/myAccountDefaultSections'
31
30
  import { fetchMyAccountPageContent } from 'src/server/cms/fetchMyAccountPageContent'
31
+ import { extractAccountNavigationData } from 'src/server/cms/myAccountDefaultSections'
32
+ import { localizeRedirectDestination } from 'src/utils/localization/localizeRedirectDestination'
32
33
  import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
33
34
  import { withLocaleValidationSSR } from 'src/utils/localization/withLocaleValidation'
34
35
 
@@ -119,7 +120,7 @@ const getServerSidePropsBase: GetServerSideProps<
119
120
  if (!isRepresentative) {
120
121
  return {
121
122
  redirect: {
122
- destination: '/pvt/account',
123
+ destination: localizeRedirectDestination('/pvt/account', context),
123
124
  permanent: false,
124
125
  },
125
126
  }
@@ -175,7 +176,7 @@ const getServerSidePropsBase: GetServerSideProps<
175
176
 
176
177
  return {
177
178
  redirect: {
178
- destination,
179
+ destination: localizeRedirectDestination(destination, context),
179
180
  permanent: false,
180
181
  },
181
182
  }