@faststore/core 3.90.1 → 3.91.0

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 (93) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +23 -23
  3. package/.next/cache/.tsbuildinfo +1 -1
  4. package/.next/cache/config.json +3 -3
  5. package/.next/cache/webpack/client-production/0.pack +0 -0
  6. package/.next/cache/webpack/client-production/index.pack +0 -0
  7. package/.next/cache/webpack/server-production/0.pack +0 -0
  8. package/.next/cache/webpack/server-production/index.pack +0 -0
  9. package/.next/prerender-manifest.js +1 -1
  10. package/.next/prerender-manifest.json +1 -1
  11. package/.next/react-loadable-manifest.json +6 -6
  12. package/.next/routes-manifest.json +1 -1
  13. package/.next/server/chunks/4168.js +1 -1
  14. package/.next/server/chunks/870.js +1 -1
  15. package/.next/server/chunks/9563.js +3 -3
  16. package/.next/server/chunks/9630.js +3 -3
  17. package/.next/server/functions-config-manifest.json +1 -1
  18. package/.next/server/middleware-build-manifest.js +1 -1
  19. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  20. package/.next/server/pages/404.js.nft.json +1 -1
  21. package/.next/server/pages/500.js.nft.json +1 -1
  22. package/.next/server/pages/[...slug].js.nft.json +1 -1
  23. package/.next/server/pages/[slug]/p.js.nft.json +1 -1
  24. package/.next/server/pages/_app.js.nft.json +1 -1
  25. package/.next/server/pages/_document.js.nft.json +1 -1
  26. package/.next/server/pages/_error.js.nft.json +1 -1
  27. package/.next/server/pages/api/graphql.js +3 -3
  28. package/.next/server/pages/api/graphql.js.nft.json +1 -1
  29. package/.next/server/pages/api/health/live.js.nft.json +1 -1
  30. package/.next/server/pages/api/health/ready.js.nft.json +1 -1
  31. package/.next/server/pages/api/preview.js.nft.json +1 -1
  32. package/.next/server/pages/checkout.js.nft.json +1 -1
  33. package/.next/server/pages/en-US/404.html +1 -1
  34. package/.next/server/pages/en-US/500.html +1 -1
  35. package/.next/server/pages/en-US/checkout.html +1 -1
  36. package/.next/server/pages/en-US/login.html +1 -1
  37. package/.next/server/pages/en-US/s.html +1 -1
  38. package/.next/server/pages/en-US.html +1 -1
  39. package/.next/server/pages/index.js.nft.json +1 -1
  40. package/.next/server/pages/login.js.nft.json +1 -1
  41. package/.next/server/pages/pvt/account/403.js +1 -1
  42. package/.next/server/pages/pvt/account/403.js.nft.json +1 -1
  43. package/.next/server/pages/pvt/account/404.js +1 -1
  44. package/.next/server/pages/pvt/account/404.js.nft.json +1 -1
  45. package/.next/server/pages/pvt/account/[...unknown].js.nft.json +1 -1
  46. package/.next/server/pages/pvt/account/orders/[id].js +1 -1
  47. package/.next/server/pages/pvt/account/orders/[id].js.nft.json +1 -1
  48. package/.next/server/pages/pvt/account/orders.js +1 -1
  49. package/.next/server/pages/pvt/account/orders.js.nft.json +1 -1
  50. package/.next/server/pages/pvt/account/profile.js +1 -1
  51. package/.next/server/pages/pvt/account/profile.js.nft.json +1 -1
  52. package/.next/server/pages/pvt/account/security.js +1 -1
  53. package/.next/server/pages/pvt/account/security.js.nft.json +1 -1
  54. package/.next/server/pages/pvt/account/user-details.js +1 -1
  55. package/.next/server/pages/pvt/account/user-details.js.nft.json +1 -1
  56. package/.next/server/pages/pvt/account.js +1 -1
  57. package/.next/server/pages/pvt/account.js.nft.json +1 -1
  58. package/.next/server/pages/s.js.nft.json +1 -1
  59. package/.next/server/pages-manifest.json +1 -1
  60. package/.next/static/{1G1fFBbTvq0WaZ-0pahJG → FslBA_VdamNtaqLHejDIJ}/_buildManifest.js +1 -1
  61. package/.next/static/chunks/{2927.23bae2c79f0ac0f3.js → 2927.5a79877943a6bf7c.js} +1 -1
  62. package/.next/static/chunks/{UIToast.3a8d6b20848b20e2.js → UIToast.5b849b0ef95e25ce.js} +1 -1
  63. package/.next/static/chunks/pages/_app-43bcb55c76e1d67e.js +1 -0
  64. package/.next/static/chunks/pages/pvt/account/403-91597100f8956385.js +1 -0
  65. package/.next/static/chunks/{webpack-7a160aaa24e51946.js → webpack-083c0d59a2221fa9.js} +1 -1
  66. package/.next/trace +138 -138
  67. package/.turbo/turbo-build.log +10 -10
  68. package/.turbo/turbo-test.log +5 -5
  69. package/@generated/schema.graphql +18 -16
  70. package/CHANGELOG.md +6 -0
  71. package/discovery.config.default.js +1 -1
  72. package/package.json +3 -3
  73. package/src/experimental/{myAccountSeverSideProps.ts → myAccountServerSideProps.ts} +18 -6
  74. package/src/pages/api/graphql.ts +20 -11
  75. package/src/pages/pvt/account/403.tsx +67 -48
  76. package/src/pages/pvt/account/404.tsx +16 -12
  77. package/src/pages/pvt/account/[...unknown].tsx +1 -1
  78. package/src/pages/pvt/account/index.tsx +0 -12
  79. package/src/pages/pvt/account/orders/[id].tsx +8 -15
  80. package/src/pages/pvt/account/orders/index.tsx +9 -15
  81. package/src/pages/pvt/account/profile.tsx +14 -21
  82. package/src/pages/pvt/account/security.tsx +7 -14
  83. package/src/pages/pvt/account/user-details.tsx +7 -14
  84. package/src/sdk/account/getMyAccountRoutes.ts +3 -2
  85. package/src/sdk/account/refreshToken.ts +50 -0
  86. package/src/sdk/account/useRefreshToken.ts +67 -0
  87. package/src/sdk/account/validateUser.ts +56 -12
  88. package/src/sdk/session/index.ts +6 -37
  89. package/src/server/index.ts +7 -1
  90. package/.next/server/chunks/7947.js +0 -1
  91. package/.next/static/chunks/pages/_app-494fa821daae1608.js +0 -1
  92. package/.next/static/chunks/pages/pvt/account/403-f2858569fde3873b.js +0 -1
  93. /package/.next/static/{1G1fFBbTvq0WaZ-0pahJG → FslBA_VdamNtaqLHejDIJ}/_ssgManifest.js +0 -0
@@ -1,23 +1,23 @@
1
1
 
2
- > @faststore/core@3.90.0 prebuild /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@3.90.1 prebuild /home/runner/work/faststore/faststore/packages/core
3
3
  > na run partytown && na run generate
4
4
 
5
5
 
6
- > @faststore/core@3.90.0 partytown /home/runner/work/faststore/faststore/packages/core
6
+ > @faststore/core@3.90.1 partytown /home/runner/work/faststore/faststore/packages/core
7
7
  > partytown copylib ./public/~partytown
8
8
 
9
9
  Partytown lib copied to: /home/runner/work/faststore/faststore/packages/core/public/~partytown
10
10
 
11
- > @faststore/core@3.90.0 generate /home/runner/work/faststore/faststore/packages/core
11
+ > @faststore/core@3.90.1 generate /home/runner/work/faststore/faststore/packages/core
12
12
  > na run generate:schema && na run generate:codegen && na run format:generated
13
13
 
14
14
 
15
- > @faststore/core@3.90.0 generate:schema /home/runner/work/faststore/faststore/packages/core
15
+ > @faststore/core@3.90.1 generate:schema /home/runner/work/faststore/faststore/packages/core
16
16
  > tsx src/server/generator/generateGraphQLSchemaFile.ts
17
17
 
18
18
  Schema GraphQL file generated successfully
19
19
 
20
- > @faststore/core@3.90.0 generate:codegen /home/runner/work/faststore/faststore/packages/core
20
+ > @faststore/core@3.90.1 generate:codegen /home/runner/work/faststore/faststore/packages/core
21
21
  > graphql-codegen
22
22
 
23
23
  [STARTED] Parse Configuration
@@ -37,11 +37,11 @@ Running lifecycle hook "afterStart" scripts...
37
37
  [CLI] Loading Documents
38
38
  [CLI] Generating output
39
39
 
40
- > @faststore/core@3.90.0 format:generated /home/runner/work/faststore/faststore/packages/core
40
+ > @faststore/core@3.90.1 format:generated /home/runner/work/faststore/faststore/packages/core
41
41
  > prettier --write "@generated/**/*.{ts,js,tsx,jsx,json}" --loglevel error
42
42
 
43
43
 
44
- > @faststore/core@3.90.0 build /home/runner/work/faststore/faststore/packages/core
44
+ > @faststore/core@3.90.1 build /home/runner/work/faststore/faststore/packages/core
45
45
  > next build
46
46
 
47
47
  ⚠ No build cache found. Please configure build caching for faster rebuilds. Read more: https://nextjs.org/docs/messages/no-cache
@@ -89,7 +89,7 @@ Route (pages) Size First Load JS
89
89
  ├ ● /login 1.7 kB 140 kB
90
90
  ├ λ /pvt/account 247 B 108 kB
91
91
  ├ ● /pvt/account/[...unknown] 287 B 108 kB
92
- ├ λ /pvt/account/403 2.49 kB 141 kB
92
+ ├ λ /pvt/account/403 2.98 kB 141 kB
93
93
  ├ └ css/c53b17b6fa994508.css 4.66 kB
94
94
  ├ λ /pvt/account/404 2.18 kB 140 kB
95
95
  ├ └ css/ceb410a7062740d1.css 4.72 kB
@@ -107,8 +107,8 @@ Route (pages) Size First Load JS
107
107
  + First Load JS shared by all 111 kB
108
108
  ├ chunks/framework-d514426edf885c68.js 45.4 kB
109
109
  ├ chunks/main-595f5e3b626b9fff.js 33.2 kB
110
- ├ chunks/pages/_app-494fa821daae1608.js 25 kB
111
- ├ chunks/webpack-7a160aaa24e51946.js 3.84 kB
110
+ ├ chunks/pages/_app-43bcb55c76e1d67e.js 25 kB
111
+ ├ chunks/webpack-083c0d59a2221fa9.js 3.84 kB
112
112
  └ css/24a5e8f6808266fe.css 3.53 kB
113
113
 
114
114
  λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
@@ -1,14 +1,14 @@
1
1
 
2
- > @faststore/core@3.90.0 test /home/runner/work/faststore/faststore/packages/core
2
+ > @faststore/core@3.90.1 test /home/runner/work/faststore/faststore/packages/core
3
3
  > jest
4
4
 
5
- PASS test/server/cms/global.test.ts (27.025 s)
6
- PASS test/utils/multipleTemplates.test.ts (27.238 s)
5
+ PASS test/utils/multipleTemplates.test.ts (27.219 s)
6
+ PASS test/server/cms/global.test.ts (27.394 s)
7
7
  PASS test/server/cms/index.test.ts
8
- PASS test/server/index.test.ts (30.022 s)
8
+ PASS test/server/index.test.ts (30.582 s)
9
9
 
10
10
  Test Suites: 4 passed, 4 total
11
11
  Tests: 22 passed, 22 total
12
12
  Snapshots: 0 total
13
- Time: 31.191 s
13
+ Time: 31.91 s
14
14
  Ran all test suites.
@@ -5,6 +5,8 @@ schema {
5
5
 
6
6
  directive @cacheControl(sMaxAge: Int, staleWhileRevalidate: Int, scope: String) on FIELD_DEFINITION
7
7
 
8
+ directive @auth on FIELD_DEFINITION
9
+
8
10
  """Address information."""
9
11
  type Address {
10
12
  """Address postal code"""
@@ -948,12 +950,12 @@ type Query {
948
950
  product(
949
951
  """An array of selected search facets."""
950
952
  locator: [IStoreSelectedFacet!]!
951
- ): StoreProduct! @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
953
+ ): StoreProduct! @cacheControl(scope: "public", sMaxAge: 300, staleWhileRevalidate: 3600)
952
954
  """Returns the details of a collection based on the collection slug."""
953
955
  collection(
954
956
  """Collection slug."""
955
957
  slug: String!
956
- ): StoreCollection! @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
958
+ ): StoreCollection! @cacheControl(scope: "public", sMaxAge: 300, staleWhileRevalidate: 3600)
957
959
  """Returns the result of a product, facet, or suggestion search."""
958
960
  search(
959
961
  """Search pagination argument, indicating how many results should be returned from the complete result list."""
@@ -968,23 +970,23 @@ type Query {
968
970
  selectedFacets: [IStoreSelectedFacet!]
969
971
  """Search advertisement products return in result."""
970
972
  sponsoredCount: Int
971
- ): StoreSearchResult! @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
973
+ ): StoreSearchResult! @cacheControl(scope: "public", sMaxAge: 300, staleWhileRevalidate: 3600)
972
974
  """Returns information about all products."""
973
975
  allProducts(
974
976
  """Product pagination argument, indicating how many items should be returned from the complete result list."""
975
977
  first: Int!
976
978
  """Product pagination argument, indicating the cursor corresponding with the item after which the items should be fetched."""
977
979
  after: String
978
- ): StoreProductConnection! @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
980
+ ): StoreProductConnection! @cacheControl(scope: "public", sMaxAge: 300, staleWhileRevalidate: 3600)
979
981
  """Returns information about selected products."""
980
- products(productIds: [String!]!): [StoreProduct!]! @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
982
+ products(productIds: [String!]!): [StoreProduct!]! @cacheControl(scope: "public", sMaxAge: 300, staleWhileRevalidate: 3600)
981
983
  """Returns information about all collections."""
982
984
  allCollections(
983
985
  """Collection pagination argument, indicating how many items should be returned from the complete result list."""
984
986
  first: Int!
985
987
  """Collection pagination argument, indicating the cursor corresponding with the item after which the items should be fetched."""
986
988
  after: String
987
- ): StoreCollectionConnection! @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
989
+ ): StoreCollectionConnection! @cacheControl(scope: "public", sMaxAge: 300, staleWhileRevalidate: 3600)
988
990
  """Returns information about shipping simulation."""
989
991
  shipping(
990
992
  """List of SKU products"""
@@ -993,7 +995,7 @@ type Query {
993
995
  postalCode: String!
994
996
  """Country of postal code"""
995
997
  country: String!
996
- ): ShippingData @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
998
+ ): ShippingData @cacheControl(scope: "public", sMaxAge: 300, staleWhileRevalidate: 3600)
997
999
  """Returns if there's a redirect for a search."""
998
1000
  redirect(
999
1001
  """Search term."""
@@ -1011,22 +1013,22 @@ type Query {
1011
1013
  country: String!
1012
1014
  """Sales channel of the navigation"""
1013
1015
  salesChannel: String
1014
- ): SellersData @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
1016
+ ): SellersData @cacheControl(scope: "public", sMaxAge: 300, staleWhileRevalidate: 3600)
1015
1017
  """Returns information about the profile."""
1016
1018
  profile(
1017
1019
  """Identifier for user."""
1018
1020
  id: String!
1019
- ): Profile @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
1021
+ ): Profile @cacheControl(scope: "public", sMaxAge: 300, staleWhileRevalidate: 3600)
1020
1022
  """Returns the total product count information based on a specific location accessible through the VTEX segment cookie."""
1021
1023
  productCount(
1022
1024
  """Search term."""
1023
1025
  term: String
1024
- ): ProductCountResult @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
1026
+ ): ProductCountResult @cacheControl(scope: "public", sMaxAge: 300, staleWhileRevalidate: 3600)
1025
1027
  """Returns information about the Details of an User Order."""
1026
1028
  userOrder(
1027
1029
  """Identifier for the order."""
1028
1030
  orderId: String!
1029
- ): UserOrderResult @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
1031
+ ): UserOrderResult @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
1030
1032
  """Returns information about the list of Orders that the User can view."""
1031
1033
  listUserOrders(
1032
1034
  """Page number of the list of orders."""
@@ -1043,18 +1045,18 @@ type Query {
1043
1045
  text: String
1044
1046
  """Client email used to filter of the list of orders."""
1045
1047
  clientEmail: String
1046
- ): UserOrderListMinimalResult @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
1048
+ ): UserOrderListMinimalResult @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
1047
1049
  """Returns information about the current user details."""
1048
- userDetails: StoreUserDetails! @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
1050
+ userDetails: StoreUserDetails! @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
1049
1051
  """Returns the account profile information for the current authenticated user (b2b or b2c user)."""
1050
- accountProfile: StoreAccountProfile! @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
1052
+ accountProfile: StoreAccountProfile! @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
1051
1053
  """Returns information about the user validation."""
1052
- validateUser: ValidateUserData @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
1054
+ validateUser: ValidateUserData @auth @cacheControl(scope: "private", sMaxAge: 300, staleWhileRevalidate: 3600)
1053
1055
  """Returns a list of pickup points near to the given geo coordinates."""
1054
1056
  pickupPoints(
1055
1057
  """Geo coordinates input."""
1056
1058
  geoCoordinates: IStoreGeoCoordinates
1057
- ): PickupPoints @cacheControl(scope: "public", sMaxAge: 120, staleWhileRevalidate: 3600)
1059
+ ): PickupPoints @cacheControl(scope: "public", sMaxAge: 300, staleWhileRevalidate: 3600)
1058
1060
  }
1059
1061
 
1060
1062
  type ValidateUserData {
package/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
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
+ # [3.91.0](https://github.com/vtex/faststore/compare/v3.90.1...v3.91.0) (2025-10-24)
7
+
8
+ ### Features
9
+
10
+ - user validation improvements + refresh token SSR and api - SFS-2909 ([#3065](https://github.com/vtex/faststore/issues/3065)) ([97071ee](https://github.com/vtex/faststore/commit/97071ee21fcee0b038dfafa06633ef597136898e))
11
+
6
12
  ## [3.90.1](https://github.com/vtex/faststore/compare/v3.90.0...v3.90.1) (2025-10-20)
7
13
 
8
14
  ### Bug Fixes
@@ -149,7 +149,7 @@ module.exports = {
149
149
  enableVtexAssetsLoader: false,
150
150
  graphqlCacheControl: {
151
151
  maxAge: 0, // 0 disables cache, 5 * 60 enable cache control maxAge 5 minutes
152
- staleWhileRevalidate: 60,
152
+ staleWhileRevalidate: 60 * 60, // 1 hour
153
153
  },
154
154
  refreshToken: false,
155
155
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "3.90.1",
3
+ "version": "3.91.0",
4
4
  "license": "MIT",
5
5
  "repository": "vtex/faststore",
6
6
  "browserslist": "supports es6-module and not dead",
@@ -44,7 +44,7 @@
44
44
  "@envelop/graphql-jit": "^8.0.3",
45
45
  "@envelop/parser-cache": "^6.0.2",
46
46
  "@envelop/validation-cache": "^6.0.2",
47
- "@faststore/api": "^3.90.0",
47
+ "@faststore/api": "^3.91.0",
48
48
  "@faststore/graphql-utils": "^3.89.2",
49
49
  "@faststore/lighthouse": "^3.89.2",
50
50
  "@faststore/sdk": "^3.90.0",
@@ -116,5 +116,5 @@
116
116
  "ts-jest": "29.1.1",
117
117
  "typescript": "5.3.2"
118
118
  },
119
- "gitHead": "63c402037eecf654247a393ce446167169466558"
119
+ "gitHead": "2f215352aeeea0063ea89cf4eab34fc25f29c813"
120
120
  }
@@ -37,9 +37,10 @@ export const getServerSideProps: GetServerSideProps<
37
37
  Record<string, string>,
38
38
  Locator
39
39
  > = async (context) => {
40
- const isValid = await validateUser(context)
40
+ const validationResult = await validateUser(context)
41
41
 
42
- if (!isValid) {
42
+ // Guard clause: Early redirect to login if user is invalid and doesn't need refresh
43
+ if (!validationResult.isValid && !validationResult.needsRefresh) {
43
44
  return {
44
45
  redirect: {
45
46
  destination: '/login',
@@ -48,10 +49,16 @@ export const getServerSideProps: GetServerSideProps<
48
49
  }
49
50
  }
50
51
 
51
- const isRepresentative = getIsRepresentative({
52
- headers: context.req.headers as Record<string, string>,
53
- account: storeConfig.api.storeId,
54
- })
52
+ // Handle refresh token case with minimal props
53
+ if (!validationResult.isValid && validationResult.needsRefresh) {
54
+ const currentPath = context.req.url || '/pvt/account'
55
+ return {
56
+ redirect: {
57
+ destination: `/pvt/account/403?from=${encodeURIComponent(currentPath)}`,
58
+ permanent: false,
59
+ },
60
+ }
61
+ }
55
62
 
56
63
  const { isFaststoreMyAccountEnabled, redirect } = getMyAccountRedirect({
57
64
  query: context.query,
@@ -61,6 +68,11 @@ export const getServerSideProps: GetServerSideProps<
61
68
  return { redirect }
62
69
  }
63
70
 
71
+ const isRepresentative = getIsRepresentative({
72
+ headers: context.req.headers as Record<string, string>,
73
+ account: storeConfig.api.storeId,
74
+ })
75
+
64
76
  const [
65
77
  globalSectionsPromise,
66
78
  globalSectionsHeaderPromise,
@@ -10,7 +10,8 @@ import discoveryConfig from 'discovery.config'
10
10
  import { getJWTAutCookie, isExpired } from 'src/utils/getCookie'
11
11
  import { execute } from '../../server'
12
12
 
13
- const ONE_MINUTE = 60
13
+ const DEFAULT_MAX_AGE = 5 * 60 // 5 minutes
14
+ const DEFAULT_STALE_WHILE_REVALIDATE = 60 * 60 // 1 hour
14
15
 
15
16
  /**
16
17
  * This function replaces the setCookie domain so that we can use localhost in dev environment.
@@ -144,26 +145,34 @@ const handler: NextApiHandler = async (request, response) => {
144
145
  return
145
146
  }
146
147
 
147
- const cacheControl =
148
- !hasErrors && extensions.cacheControl
149
- ? stringifyCacheControl(extensions.cacheControl)
150
- : 'no-cache, no-store'
151
-
152
- if (
148
+ if (extensions.cacheControl) {
149
+ const cacheControl = stringifyCacheControl(extensions.cacheControl)
150
+ response.setHeader('cache-control', cacheControl)
151
+ } else if (
153
152
  request.method === 'GET' &&
154
- discoveryConfig?.experimental?.graphqlCacheControl?.maxAge
153
+ operation.__meta__.operationName?.toLowerCase()?.endsWith('query')
155
154
  ) {
156
- const maxAge = discoveryConfig.experimental.graphqlCacheControl.maxAge
155
+ const maxAge =
156
+ discoveryConfig?.experimental?.graphqlCacheControl?.maxAge &&
157
+ discoveryConfig?.experimental?.graphqlCacheControl?.maxAge > 0
158
+ ? discoveryConfig.experimental.graphqlCacheControl.maxAge
159
+ : DEFAULT_MAX_AGE // 5 minutes
160
+
157
161
  const staleWhileRevalidate =
158
162
  discoveryConfig?.experimental?.graphqlCacheControl
159
- ?.staleWhileRevalidate ?? ONE_MINUTE
163
+ ?.staleWhileRevalidate &&
164
+ discoveryConfig?.experimental?.graphqlCacheControl
165
+ ?.staleWhileRevalidate > 0
166
+ ? discoveryConfig.experimental.graphqlCacheControl
167
+ .staleWhileRevalidate
168
+ : DEFAULT_STALE_WHILE_REVALIDATE // 1 hour
160
169
 
161
170
  response.setHeader(
162
171
  'cache-control',
163
172
  `public, s-maxage=${maxAge}, stale-while-revalidate=${staleWhileRevalidate}`
164
173
  )
165
174
  } else {
166
- response.setHeader('cache-control', cacheControl)
175
+ response.setHeader('cache-control', 'no-cache, no-store')
167
176
  }
168
177
 
169
178
  const setCookieValues = Array.from(extensions.cookies.values())
@@ -19,13 +19,14 @@ import RenderSections from 'src/components/cms/RenderSections'
19
19
  import { OverriddenDefaultEmptyState as EmptyState } from 'src/components/sections/EmptyState/OverriddenDefaultEmptyState'
20
20
  import CUSTOM_COMPONENTS from 'src/customizations/src/components'
21
21
  import PLUGINS_COMPONENTS from 'src/plugins'
22
- import { validateUser } from 'src/sdk/account/validateUser'
22
+ import { useRefreshToken } from 'src/sdk/account/useRefreshToken'
23
23
  import PageProvider from 'src/sdk/overrides/PageProvider'
24
24
  import { execute } from 'src/server'
25
- import { type PageContentType, getPage } from 'src/server/cms'
26
25
  import { injectGlobalSections } from 'src/server/cms/global'
27
26
  import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
28
27
 
28
+ import storeConfig from 'discovery.config'
29
+
29
30
  /* A list of components that can be used in the CMS. */
30
31
  const COMPONENTS: Record<string, ComponentType<any>> = {
31
32
  ...GLOBAL_COMPONENTS,
@@ -34,14 +35,31 @@ const COMPONENTS: Record<string, ComponentType<any>> = {
34
35
  }
35
36
 
36
37
  type Props = {
37
- globalSections: GlobalSectionsData
38
- accountName: ServerAccountPageQueryQuery['accountProfile']['name']
38
+ globalSections?: GlobalSectionsData
39
+ accountName?: ServerAccountPageQueryQuery['accountProfile']['name']
40
+ needsRefreshToken?: boolean
41
+ fromPage?: string
39
42
  }
40
43
 
41
- function Page({ globalSections: globalSectionsProp, accountName }: Props) {
44
+ function Page({
45
+ globalSections: globalSectionsProp,
46
+ accountName,
47
+ needsRefreshToken,
48
+ fromPage,
49
+ }: Props) {
42
50
  const { sections: globalSections, settings: globalSettings } =
43
- globalSectionsProp ?? {}
51
+ globalSectionsProp ?? { sections: [], settings: {} }
52
+
53
+ // Use the new hook to handle refresh token with session management
54
+ const { shouldShow403 } = useRefreshToken(needsRefreshToken, fromPage)
44
55
 
56
+ // Handle refresh token case - show loading while attempting refresh
57
+ if (needsRefreshToken && !shouldShow403) {
58
+ console.info('Refreshing authentication...')
59
+ return <></>
60
+ }
61
+
62
+ // Show 403 page if refresh failed or if we don't need refresh token
45
63
  return (
46
64
  <PageProvider context={{ globalSettings }}>
47
65
  <RenderSections globalSections={globalSections} components={COMPONENTS}>
@@ -77,13 +95,50 @@ export const getServerSideProps: GetServerSideProps<
77
95
  Record<string, string>,
78
96
  Locator
79
97
  > = async (context) => {
80
- const isValid = await validateUser(context)
98
+ const [
99
+ globalSectionsPromise,
100
+ globalSectionsHeaderPromise,
101
+ globalSectionsFooterPromise,
102
+ ] = getGlobalSectionsData(context.previewData)
103
+
104
+ const [account, globalSections, globalSectionsHeader, globalSectionsFooter] =
105
+ await Promise.all([
106
+ execute<
107
+ ServerAccountPageQueryQueryVariables,
108
+ ServerAccountPageQueryQuery
109
+ >(
110
+ {
111
+ variables: {},
112
+ operation: query,
113
+ },
114
+ { headers: { ...context.req.headers } }
115
+ ),
116
+ globalSectionsPromise,
117
+ globalSectionsHeaderPromise,
118
+ globalSectionsFooterPromise,
119
+ ])
120
+
121
+ const globalSectionsResult = injectGlobalSections({
122
+ globalSections,
123
+ globalSectionsHeader,
124
+ globalSectionsFooter,
125
+ })
126
+
127
+ if (account.errors) {
128
+ console.error(...account.errors)
129
+
130
+ const statusCode: number = (account.errors[0] as any)?.extensions?.status
131
+
132
+ const fromPage =
133
+ typeof context.query.from === 'string' ? context.query.from : ''
81
134
 
82
- if (!isValid) {
83
135
  return {
84
- redirect: {
85
- destination: '/login',
86
- permanent: false,
136
+ props: {
137
+ globalSections: globalSectionsResult,
138
+ needsRefreshToken:
139
+ (statusCode === 401 || statusCode === 403) &&
140
+ storeConfig.experimental?.refreshToken,
141
+ fromPage,
87
142
  },
88
143
  }
89
144
  }
@@ -96,47 +151,11 @@ export const getServerSideProps: GetServerSideProps<
96
151
  return { redirect }
97
152
  }
98
153
 
99
- const [
100
- globalSectionsPromise,
101
- globalSectionsHeaderPromise,
102
- globalSectionsFooterPromise,
103
- ] = getGlobalSectionsData(context.previewData)
104
-
105
- const [
106
- page,
107
- account,
108
- globalSections,
109
- globalSectionsHeader,
110
- globalSectionsFooter,
111
- ] = await Promise.all([
112
- getPage<PageContentType>({
113
- ...(context.previewData?.contentType === '403' && context.previewData),
114
- contentType: '403',
115
- }),
116
- execute<ServerAccountPageQueryQueryVariables, ServerAccountPageQueryQuery>(
117
- {
118
- variables: {},
119
- operation: query,
120
- },
121
- { headers: { ...context.req.headers } }
122
- ),
123
- globalSectionsPromise,
124
- globalSectionsHeaderPromise,
125
- globalSectionsFooterPromise,
126
- ])
127
-
128
- const globalSectionsResult = injectGlobalSections({
129
- globalSections,
130
- globalSectionsHeader,
131
- globalSectionsFooter,
132
- })
133
-
134
154
  return {
135
155
  props: {
136
156
  // The sections from the CMS page are not utilized here for the My Account page.
137
- // page,
138
157
  globalSections: globalSectionsResult,
139
- accountName: account.data.accountProfile.name,
158
+ accountName: account?.data?.accountProfile?.name ?? '',
140
159
  },
141
160
  }
142
161
  }
@@ -20,7 +20,6 @@ import RenderSections, {
20
20
  import { OverriddenDefaultEmptyState as EmptyState } from 'src/components/sections/EmptyState/OverriddenDefaultEmptyState'
21
21
  import CUSTOM_COMPONENTS from 'src/customizations/src/components'
22
22
  import PLUGINS_COMPONENTS from 'src/plugins'
23
- import { validateUser } from 'src/sdk/account/validateUser'
24
23
  import PageProvider from 'src/sdk/overrides/PageProvider'
25
24
  import { execute } from 'src/server'
26
25
  import { type PageContentType, getPage } from 'src/server/cms'
@@ -77,17 +76,6 @@ export const getServerSideProps: GetServerSideProps<
77
76
  Record<string, string>,
78
77
  Locator
79
78
  > = async (context) => {
80
- const isValid = await validateUser(context)
81
-
82
- if (!isValid) {
83
- return {
84
- redirect: {
85
- destination: '/login',
86
- permanent: false,
87
- },
88
- }
89
- }
90
-
91
79
  const { isFaststoreMyAccountEnabled, redirect } = getMyAccountRedirect({
92
80
  query: context.query,
93
81
  })
@@ -125,6 +113,22 @@ export const getServerSideProps: GetServerSideProps<
125
113
  globalSectionsFooterPromise,
126
114
  ])
127
115
 
116
+ if (account.errors) {
117
+ console.error(...account.errors)
118
+
119
+ const statusCode: number = (account.errors[0] as any)?.extensions?.status
120
+
121
+ // Redirect to 403 for authentication errors (401/403) to handle token refresh
122
+ if (statusCode === 401 || statusCode === 403) {
123
+ return {
124
+ redirect: {
125
+ destination: `/pvt/account/403?from=${encodeURIComponent('/pvt/account/404')}`,
126
+ permanent: false,
127
+ },
128
+ }
129
+ }
130
+ }
131
+
128
132
  const globalSectionsResult = injectGlobalSections({
129
133
  globalSections,
130
134
  globalSectionsHeader,
@@ -1,7 +1,7 @@
1
1
  import type { Locator } from '@vtex/client-cms'
2
2
  import type { GetStaticPaths, GetStaticProps } from 'next'
3
3
 
4
- import type { MyAccountProps } from 'src/experimental/myAccountSeverSideProps'
4
+ import type { MyAccountProps } from 'src/experimental/myAccountServerSideProps'
5
5
  import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
6
6
 
7
7
  export default function Page() {
@@ -1,5 +1,4 @@
1
1
  import type { GetServerSideProps, NextPage } from 'next'
2
- import { validateUser } from 'src/sdk/account/validateUser'
3
2
  import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
4
3
 
5
4
  const MyAccountRedirectPage: NextPage = () => {
@@ -10,17 +9,6 @@ export const getServerSideProps: GetServerSideProps = async ({
10
9
  query,
11
10
  req,
12
11
  }) => {
13
- const isValid = await validateUser({ query, req } as any)
14
-
15
- if (!isValid) {
16
- return {
17
- redirect: {
18
- destination: '/login',
19
- permanent: false,
20
- },
21
- }
22
- }
23
-
24
12
  const { isFaststoreMyAccountEnabled, redirect } = getMyAccountRedirect({
25
13
  query,
26
14
  })
@@ -7,8 +7,7 @@ import MyAccountOrderDetails from 'src/components/account/orders/MyAccountOrderD
7
7
  import RenderSections from 'src/components/cms/RenderSections'
8
8
  import { default as GLOBAL_COMPONENTS } from 'src/components/cms/global/Components'
9
9
  import CUSTOM_COMPONENTS from 'src/customizations/src/components'
10
- import type { MyAccountProps } from 'src/experimental/myAccountSeverSideProps'
11
- import { validateUser } from 'src/sdk/account/validateUser'
10
+ import type { MyAccountProps } from 'src/experimental/myAccountServerSideProps'
12
11
 
13
12
  import { gql } from '@generated'
14
13
  import type {
@@ -268,17 +267,6 @@ export const getServerSideProps: GetServerSideProps<
268
267
  Record<string, string>,
269
268
  Locator
270
269
  > = async (context) => {
271
- const isValid = await validateUser(context)
272
-
273
- if (!isValid) {
274
- return {
275
- redirect: {
276
- destination: '/login',
277
- permanent: false,
278
- },
279
- }
280
- }
281
-
282
270
  const isRepresentative = getIsRepresentative({
283
271
  headers: context.req.headers as Record<string, string>,
284
272
  account: storeConfig.api.storeId,
@@ -328,11 +316,16 @@ export const getServerSideProps: GetServerSideProps<
328
316
  console.error(...orderDetails.errors)
329
317
  const status = extractStatusFromError(orderDetails.errors?.[0])
330
318
 
331
- const isForbidden = status === 403 || status === 401
319
+ // Redirect to 403 for authentication errors (401/403) to handle token refresh
320
+ // Redirect to 404 for other errors
321
+ const destination =
322
+ status === 403 || status === 401
323
+ ? `/pvt/account/403?from=${encodeURIComponent(`/pvt/account/orders/${context.params?.id}`)}`
324
+ : '/pvt/account/404'
332
325
 
333
326
  return {
334
327
  redirect: {
335
- destination: isForbidden ? '/pvt/account/403' : '/pvt/account/404',
328
+ destination,
336
329
  permanent: false,
337
330
  },
338
331
  }