@faststore/core 3.90.0 → 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.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +25 -25
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/cache/config.json +3 -3
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/prerender-manifest.js +1 -1
- package/.next/prerender-manifest.json +1 -1
- package/.next/react-loadable-manifest.json +7 -7
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/4168.js +1 -1
- package/.next/server/chunks/7098.js +2 -2
- package/.next/server/chunks/870.js +1 -1
- package/.next/server/chunks/9563.js +3 -3
- package/.next/server/chunks/9630.js +3 -3
- package/.next/server/functions-config-manifest.json +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/404.js.nft.json +1 -1
- package/.next/server/pages/500.js.nft.json +1 -1
- package/.next/server/pages/[...slug].js.nft.json +1 -1
- package/.next/server/pages/[slug]/p.js.nft.json +1 -1
- package/.next/server/pages/_app.js.nft.json +1 -1
- package/.next/server/pages/_document.js.nft.json +1 -1
- package/.next/server/pages/_error.js.nft.json +1 -1
- package/.next/server/pages/api/graphql.js +3 -3
- package/.next/server/pages/api/graphql.js.nft.json +1 -1
- package/.next/server/pages/api/health/live.js.nft.json +1 -1
- package/.next/server/pages/api/health/ready.js.nft.json +1 -1
- package/.next/server/pages/api/preview.js.nft.json +1 -1
- package/.next/server/pages/checkout.js.nft.json +1 -1
- package/.next/server/pages/en-US/404.html +1 -1
- package/.next/server/pages/en-US/404.json +1 -1
- package/.next/server/pages/en-US/500.html +1 -1
- package/.next/server/pages/en-US/500.json +1 -1
- package/.next/server/pages/en-US/checkout.html +1 -1
- package/.next/server/pages/en-US/checkout.json +1 -1
- package/.next/server/pages/en-US/login.html +1 -1
- package/.next/server/pages/en-US/login.json +1 -1
- package/.next/server/pages/en-US/s.html +1 -1
- package/.next/server/pages/en-US/s.json +1 -1
- package/.next/server/pages/en-US.html +1 -1
- package/.next/server/pages/en-US.json +1 -1
- package/.next/server/pages/index.js +1 -1
- package/.next/server/pages/index.js.nft.json +1 -1
- package/.next/server/pages/login.js.nft.json +1 -1
- package/.next/server/pages/pvt/account/403.js +1 -1
- package/.next/server/pages/pvt/account/403.js.nft.json +1 -1
- package/.next/server/pages/pvt/account/404.js +1 -1
- package/.next/server/pages/pvt/account/404.js.nft.json +1 -1
- package/.next/server/pages/pvt/account/[...unknown].js.nft.json +1 -1
- package/.next/server/pages/pvt/account/orders/[id].js +1 -1
- package/.next/server/pages/pvt/account/orders/[id].js.nft.json +1 -1
- package/.next/server/pages/pvt/account/orders.js +1 -1
- package/.next/server/pages/pvt/account/orders.js.nft.json +1 -1
- package/.next/server/pages/pvt/account/profile.js +1 -1
- package/.next/server/pages/pvt/account/profile.js.nft.json +1 -1
- package/.next/server/pages/pvt/account/security.js +1 -1
- package/.next/server/pages/pvt/account/security.js.nft.json +1 -1
- package/.next/server/pages/pvt/account/user-details.js +1 -1
- package/.next/server/pages/pvt/account/user-details.js.nft.json +1 -1
- package/.next/server/pages/pvt/account.js +1 -1
- package/.next/server/pages/pvt/account.js.nft.json +1 -1
- package/.next/server/pages/s.js.nft.json +1 -1
- package/.next/server/pages-manifest.json +1 -1
- package/.next/static/{g8OBiuzAGVQYHn1HPDL_Y → FslBA_VdamNtaqLHejDIJ}/_buildManifest.js +1 -1
- package/.next/static/chunks/{2500.e2623cac49e0ccb8.js → 2500.fa0f80184d3cde4f.js} +1 -1
- package/.next/static/chunks/5859.0b4ee873dc86bef7.js +1 -0
- package/.next/static/chunks/ProductShelf.24f22900bc10896e.js +1 -0
- package/.next/static/chunks/pages/[slug]/p-323813ea2a7455fb.js +1 -0
- package/.next/static/chunks/pages/_app-43bcb55c76e1d67e.js +1 -0
- package/.next/static/chunks/pages/index-5c3eb58eefd7cb0f.js +1 -0
- package/.next/static/chunks/pages/pvt/account/403-91597100f8956385.js +1 -0
- package/.next/static/chunks/{webpack-27e109703d78aaaa.js → webpack-083c0d59a2221fa9.js} +1 -1
- package/.next/trace +138 -138
- package/.turbo/turbo-build.log +12 -12
- package/.turbo/turbo-test.log +5 -5
- package/@generated/schema.graphql +18 -16
- package/CHANGELOG.md +12 -0
- package/discovery.config.default.js +1 -1
- package/package.json +3 -3
- package/src/components/sections/ProductTiles/ProductTiles.tsx +4 -7
- package/src/components/ui/ProductShelf/ProductShelf.tsx +7 -6
- package/src/experimental/{myAccountSeverSideProps.ts → myAccountServerSideProps.ts} +18 -6
- package/src/pages/api/graphql.ts +20 -11
- package/src/pages/pvt/account/403.tsx +67 -48
- package/src/pages/pvt/account/404.tsx +16 -12
- package/src/pages/pvt/account/[...unknown].tsx +1 -1
- package/src/pages/pvt/account/index.tsx +0 -12
- package/src/pages/pvt/account/orders/[id].tsx +8 -15
- package/src/pages/pvt/account/orders/index.tsx +9 -15
- package/src/pages/pvt/account/profile.tsx +14 -21
- package/src/pages/pvt/account/security.tsx +7 -14
- package/src/pages/pvt/account/user-details.tsx +7 -14
- package/src/sdk/account/getMyAccountRoutes.ts +3 -2
- package/src/sdk/account/refreshToken.ts +50 -0
- package/src/sdk/account/useRefreshToken.ts +67 -0
- package/src/sdk/account/validateUser.ts +56 -12
- package/src/sdk/deliveryPromise/useDeliveryPromiseFacets.ts +25 -0
- package/src/sdk/session/index.ts +6 -37
- package/src/server/index.ts +7 -1
- package/src/utils/utilities.ts +0 -7
- package/.next/server/chunks/7947.js +0 -1
- package/.next/static/chunks/5859.cf66c492751f5680.js +0 -1
- package/.next/static/chunks/ProductShelf.319b97d6c822340b.js +0 -1
- package/.next/static/chunks/pages/[slug]/p-49a7aaba6898f796.js +0 -1
- package/.next/static/chunks/pages/_app-04e8430b2da487f2.js +0 -1
- package/.next/static/chunks/pages/index-7a9bc631c89fd3f2.js +0 -1
- package/.next/static/chunks/pages/pvt/account/403-f2858569fde3873b.js +0 -1
- /package/.next/static/{g8OBiuzAGVQYHn1HPDL_Y → FslBA_VdamNtaqLHejDIJ}/_ssgManifest.js +0 -0
|
@@ -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/
|
|
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
|
-
|
|
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
|
|
328
|
+
destination,
|
|
336
329
|
permanent: false,
|
|
337
330
|
},
|
|
338
331
|
}
|
|
@@ -16,7 +16,7 @@ import type {
|
|
|
16
16
|
} from '@generated/graphql'
|
|
17
17
|
import { default as AfterSection } from 'src/customizations/src/myAccount/extensions/orders/after'
|
|
18
18
|
import { default as BeforeSection } from 'src/customizations/src/myAccount/extensions/orders/before'
|
|
19
|
-
import type { MyAccountProps } from 'src/experimental/
|
|
19
|
+
import type { MyAccountProps } from 'src/experimental/myAccountServerSideProps'
|
|
20
20
|
import { execute } from 'src/server'
|
|
21
21
|
import { injectGlobalSections } from 'src/server/cms/global'
|
|
22
22
|
import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
|
|
@@ -25,7 +25,6 @@ import { groupOrderStatusByLabel } from 'src/utils/userOrderStatus'
|
|
|
25
25
|
import storeConfig from 'discovery.config'
|
|
26
26
|
import { MyAccountListOrders } from 'src/components/account/orders/MyAccountListOrders'
|
|
27
27
|
import { getIsRepresentative } from 'src/sdk/account/getIsRepresentative'
|
|
28
|
-
import { validateUser } from 'src/sdk/account/validateUser'
|
|
29
28
|
import PageProvider from 'src/sdk/overrides/PageProvider'
|
|
30
29
|
import { extractStatusFromError } from 'src/utils/utilities'
|
|
31
30
|
|
|
@@ -131,17 +130,6 @@ export const getServerSideProps: GetServerSideProps<
|
|
|
131
130
|
Record<string, string>,
|
|
132
131
|
Locator
|
|
133
132
|
> = async (context) => {
|
|
134
|
-
const isValid = await validateUser(context)
|
|
135
|
-
|
|
136
|
-
if (!isValid) {
|
|
137
|
-
return {
|
|
138
|
-
redirect: {
|
|
139
|
-
destination: '/login',
|
|
140
|
-
permanent: false,
|
|
141
|
-
},
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
133
|
const isRepresentative = getIsRepresentative({
|
|
146
134
|
headers: context.req.headers as Record<string, string>,
|
|
147
135
|
account: storeConfig.api.storeId,
|
|
@@ -225,11 +213,17 @@ export const getServerSideProps: GetServerSideProps<
|
|
|
225
213
|
console.error(...listOrders.errors)
|
|
226
214
|
|
|
227
215
|
const status = extractStatusFromError(listOrders.errors[0])
|
|
228
|
-
|
|
216
|
+
|
|
217
|
+
// Redirect to 403 for authentication errors (401/403) to handle token refresh
|
|
218
|
+
// Redirect to 404 for other errors
|
|
219
|
+
const destination =
|
|
220
|
+
status === 403 || status === 401
|
|
221
|
+
? `/pvt/account/403?from=${encodeURIComponent('/pvt/account/orders')}`
|
|
222
|
+
: '/pvt/account/404'
|
|
229
223
|
|
|
230
224
|
return {
|
|
231
225
|
redirect: {
|
|
232
|
-
destination
|
|
226
|
+
destination,
|
|
233
227
|
permanent: false,
|
|
234
228
|
},
|
|
235
229
|
}
|
|
@@ -17,9 +17,8 @@ import type {
|
|
|
17
17
|
} from '@generated/graphql'
|
|
18
18
|
import { default as AfterSection } from 'src/customizations/src/myAccount/extensions/profile/after'
|
|
19
19
|
import { default as BeforeSection } from 'src/customizations/src/myAccount/extensions/profile/before'
|
|
20
|
-
import type { MyAccountProps } from 'src/experimental/
|
|
20
|
+
import type { MyAccountProps } from 'src/experimental/myAccountServerSideProps'
|
|
21
21
|
import { getIsRepresentative } from 'src/sdk/account/getIsRepresentative'
|
|
22
|
-
import { validateUser } from 'src/sdk/account/validateUser'
|
|
23
22
|
import { injectGlobalSections } from 'src/server/cms/global'
|
|
24
23
|
import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
|
|
25
24
|
|
|
@@ -33,7 +32,7 @@ const COMPONENTS: Record<string, ComponentType<any>> = {
|
|
|
33
32
|
...CUSTOM_COMPONENTS,
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
type
|
|
35
|
+
type ProfilePageProps = {
|
|
37
36
|
accountProfile: {
|
|
38
37
|
name: string | null
|
|
39
38
|
email: string | null
|
|
@@ -46,7 +45,7 @@ export default function Profile({
|
|
|
46
45
|
accountProfile,
|
|
47
46
|
accountName,
|
|
48
47
|
isRepresentative,
|
|
49
|
-
}:
|
|
48
|
+
}: ProfilePageProps) {
|
|
50
49
|
const { sections: globalSections, settings: globalSettings } =
|
|
51
50
|
globalSectionsProp ?? {}
|
|
52
51
|
|
|
@@ -83,22 +82,6 @@ export const getServerSideProps: GetServerSideProps<
|
|
|
83
82
|
Record<string, string>,
|
|
84
83
|
Locator
|
|
85
84
|
> = async (context) => {
|
|
86
|
-
const isValid = await validateUser(context)
|
|
87
|
-
|
|
88
|
-
if (!isValid) {
|
|
89
|
-
return {
|
|
90
|
-
redirect: {
|
|
91
|
-
destination: '/login',
|
|
92
|
-
permanent: false,
|
|
93
|
-
},
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const isRepresentative = getIsRepresentative({
|
|
98
|
-
headers: context.req.headers as Record<string, string>,
|
|
99
|
-
account: storeConfig.api.storeId,
|
|
100
|
-
})
|
|
101
|
-
|
|
102
85
|
const { isFaststoreMyAccountEnabled, redirect } = getMyAccountRedirect({
|
|
103
86
|
query: context.query,
|
|
104
87
|
})
|
|
@@ -107,6 +90,11 @@ export const getServerSideProps: GetServerSideProps<
|
|
|
107
90
|
return { redirect }
|
|
108
91
|
}
|
|
109
92
|
|
|
93
|
+
const isRepresentative = getIsRepresentative({
|
|
94
|
+
headers: context.req.headers as Record<string, string>,
|
|
95
|
+
account: storeConfig.api.storeId,
|
|
96
|
+
})
|
|
97
|
+
|
|
110
98
|
const [
|
|
111
99
|
globalSectionsPromise,
|
|
112
100
|
globalSectionsHeaderPromise,
|
|
@@ -131,8 +119,13 @@ export const getServerSideProps: GetServerSideProps<
|
|
|
131
119
|
console.error(...profile.errors)
|
|
132
120
|
|
|
133
121
|
const statusCode: number = (profile.errors[0] as any)?.extensions?.status
|
|
122
|
+
|
|
123
|
+
// Redirect to 403 for authentication errors (401/403) to handle token refresh
|
|
124
|
+
// Redirect to 404 for other errors
|
|
134
125
|
const destination: string =
|
|
135
|
-
statusCode ===
|
|
126
|
+
statusCode === 401 || statusCode === 403
|
|
127
|
+
? `/pvt/account/403?from=${encodeURIComponent('/pvt/account/profile')}`
|
|
128
|
+
: '/pvt/account/404'
|
|
136
129
|
|
|
137
130
|
return {
|
|
138
131
|
redirect: {
|
|
@@ -17,13 +17,12 @@ import type {
|
|
|
17
17
|
} from '@generated/graphql'
|
|
18
18
|
import { default as AfterSection } from 'src/customizations/src/myAccount/extensions/security/after'
|
|
19
19
|
import { default as BeforeSection } from 'src/customizations/src/myAccount/extensions/security/before'
|
|
20
|
-
import type { MyAccountProps } from 'src/experimental/
|
|
20
|
+
import type { MyAccountProps } from 'src/experimental/myAccountServerSideProps'
|
|
21
21
|
import { getIsRepresentative } from 'src/sdk/account/getIsRepresentative'
|
|
22
22
|
import { execute } from 'src/server'
|
|
23
23
|
import { injectGlobalSections } from 'src/server/cms/global'
|
|
24
24
|
import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
|
|
25
25
|
|
|
26
|
-
import { validateUser } from 'src/sdk/account/validateUser'
|
|
27
26
|
import PageProvider from 'src/sdk/overrides/PageProvider'
|
|
28
27
|
|
|
29
28
|
import storeConfig from 'discovery.config'
|
|
@@ -83,17 +82,6 @@ export const getServerSideProps: GetServerSideProps<
|
|
|
83
82
|
Record<string, string>,
|
|
84
83
|
Locator
|
|
85
84
|
> = async (context) => {
|
|
86
|
-
const isValid = await validateUser(context)
|
|
87
|
-
|
|
88
|
-
if (!isValid) {
|
|
89
|
-
return {
|
|
90
|
-
redirect: {
|
|
91
|
-
destination: '/login',
|
|
92
|
-
permanent: false,
|
|
93
|
-
},
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
85
|
const isRepresentative = getIsRepresentative({
|
|
98
86
|
headers: context.req.headers as Record<string, string>,
|
|
99
87
|
account: storeConfig.api.storeId,
|
|
@@ -130,8 +118,13 @@ export const getServerSideProps: GetServerSideProps<
|
|
|
130
118
|
if (security.errors) {
|
|
131
119
|
console.error(...security.errors)
|
|
132
120
|
const statusCode: number = (security.errors[0] as any)?.extensions?.status
|
|
121
|
+
|
|
122
|
+
// Redirect to 403 for authentication errors (401/403) to handle token refresh
|
|
123
|
+
// Redirect to 404 for other errors
|
|
133
124
|
const destination: string =
|
|
134
|
-
statusCode ===
|
|
125
|
+
statusCode === 401 || statusCode === 403
|
|
126
|
+
? `/pvt/account/403?from=${encodeURIComponent('/pvt/account/security')}`
|
|
127
|
+
: '/pvt/account/404'
|
|
135
128
|
|
|
136
129
|
return {
|
|
137
130
|
redirect: {
|
|
@@ -19,9 +19,8 @@ import storeConfig from 'discovery.config'
|
|
|
19
19
|
import MyAccountUserDetails from 'src/components/account/MyAccountUserDetails/MyAccountUserDetails'
|
|
20
20
|
import { default as AfterSection } from 'src/customizations/src/myAccount/extensions/user-details/after'
|
|
21
21
|
import { default as BeforeSection } from 'src/customizations/src/myAccount/extensions/user-details/before'
|
|
22
|
-
import type { MyAccountProps } from 'src/experimental/
|
|
22
|
+
import type { MyAccountProps } from 'src/experimental/myAccountServerSideProps'
|
|
23
23
|
import { getIsRepresentative } from 'src/sdk/account/getIsRepresentative'
|
|
24
|
-
import { validateUser } from 'src/sdk/account/validateUser'
|
|
25
24
|
import PageProvider from 'src/sdk/overrides/PageProvider'
|
|
26
25
|
import { execute } from 'src/server'
|
|
27
26
|
import { injectGlobalSections } from 'src/server/cms/global'
|
|
@@ -88,17 +87,6 @@ export const getServerSideProps: GetServerSideProps<
|
|
|
88
87
|
Record<string, string>,
|
|
89
88
|
Locator
|
|
90
89
|
> = async (context) => {
|
|
91
|
-
const isValid = await validateUser(context)
|
|
92
|
-
|
|
93
|
-
if (!isValid) {
|
|
94
|
-
return {
|
|
95
|
-
redirect: {
|
|
96
|
-
destination: '/login',
|
|
97
|
-
permanent: false,
|
|
98
|
-
},
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
90
|
const isRepresentative = getIsRepresentative({
|
|
103
91
|
headers: context.req.headers as Record<string, string>,
|
|
104
92
|
account: storeConfig.api.storeId,
|
|
@@ -153,8 +141,13 @@ export const getServerSideProps: GetServerSideProps<
|
|
|
153
141
|
|
|
154
142
|
const statusCode: number = (userDetails.errors[0] as any)?.extensions
|
|
155
143
|
?.status
|
|
144
|
+
|
|
145
|
+
// Redirect to 403 for authentication errors (401/403) to handle token refresh
|
|
146
|
+
// Redirect to 404 for other errors
|
|
156
147
|
const destination: string =
|
|
157
|
-
statusCode ===
|
|
148
|
+
statusCode === 401 || statusCode === 403
|
|
149
|
+
? `/pvt/account/403?from=${encodeURIComponent('/pvt/account/user-details')}`
|
|
150
|
+
: '/pvt/account/404'
|
|
158
151
|
|
|
159
152
|
return {
|
|
160
153
|
redirect: {
|
|
@@ -10,15 +10,16 @@ interface GetMyAccountRouteParams {
|
|
|
10
10
|
routes: Route[]
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export const
|
|
13
|
+
export const PROFILE_ROUTE = '/pvt/account/profile'
|
|
14
14
|
export const ORDERS_ROUTE = '/pvt/account/orders'
|
|
15
|
+
export const USER_DETAILS_ROUTE = '/pvt/account/user-details'
|
|
15
16
|
export const SECURITY_ROUTE = '/pvt/account/security'
|
|
16
17
|
|
|
17
18
|
// This is the default route list for My Account, we should add then as the feature is implemented
|
|
18
19
|
const DEFAULT_ROUTES: Route[] = [
|
|
19
20
|
{
|
|
20
21
|
title: 'Profile',
|
|
21
|
-
route:
|
|
22
|
+
route: PROFILE_ROUTE,
|
|
22
23
|
},
|
|
23
24
|
{
|
|
24
25
|
title: 'Orders',
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import discoveryConfig from 'discovery.config'
|
|
2
|
+
import fetch from 'isomorphic-unfetch'
|
|
3
|
+
import { sanitizeHost } from 'src/utils/utilities'
|
|
4
|
+
|
|
5
|
+
const REFRESH_TOKEN_URL = `${discoveryConfig.storeUrl}/api/vtexid/refreshtoken/webstore`
|
|
6
|
+
|
|
7
|
+
export interface RefreshTokenResponse {
|
|
8
|
+
status?: string
|
|
9
|
+
refreshAfter?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function fetchWithRetry(
|
|
13
|
+
url: RequestInfo | URL,
|
|
14
|
+
init?: RequestInit,
|
|
15
|
+
maxRetries = 3
|
|
16
|
+
): Promise<RefreshTokenResponse | undefined> {
|
|
17
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
18
|
+
try {
|
|
19
|
+
const res = await fetch(url, init)
|
|
20
|
+
if (res.status !== 200) continue
|
|
21
|
+
|
|
22
|
+
const data = await res.json()
|
|
23
|
+
return data
|
|
24
|
+
} catch {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return undefined
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const refreshTokenRequest = async (): Promise<
|
|
31
|
+
RefreshTokenResponse | undefined
|
|
32
|
+
> => {
|
|
33
|
+
const headers: HeadersInit = {
|
|
34
|
+
'content-type': 'application/json',
|
|
35
|
+
Host: `${sanitizeHost(discoveryConfig.storeUrl)}`,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return await fetchWithRetry(REFRESH_TOKEN_URL, {
|
|
39
|
+
credentials: 'include',
|
|
40
|
+
headers,
|
|
41
|
+
body: JSON.stringify({}),
|
|
42
|
+
method: 'POST',
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const isRefreshTokenSuccessful = (
|
|
47
|
+
result: RefreshTokenResponse | undefined
|
|
48
|
+
): boolean => {
|
|
49
|
+
return result?.status?.toLowerCase?.() === 'success'
|
|
50
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
import { sessionStore } from '../session'
|
|
3
|
+
import { isRefreshTokenSuccessful, refreshTokenRequest } from './refreshToken'
|
|
4
|
+
|
|
5
|
+
export const useRefreshToken = (
|
|
6
|
+
needsRefreshToken?: boolean,
|
|
7
|
+
fromPage?: string
|
|
8
|
+
) => {
|
|
9
|
+
const [shouldShow403, setShouldShow403] = useState(false)
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const handleRefreshTokenAndUpdateSession = async () => {
|
|
13
|
+
if (!needsRefreshToken) return
|
|
14
|
+
|
|
15
|
+
const currentSession = sessionStore.read() ?? sessionStore.readInitial()
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const result = await refreshTokenRequest()
|
|
19
|
+
|
|
20
|
+
if (isRefreshTokenSuccessful(result)) {
|
|
21
|
+
// Update session with new refreshAfter timestamp
|
|
22
|
+
const refreshAfter = String(
|
|
23
|
+
Math.floor(new Date(result?.refreshAfter).getTime() / 1000)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
sessionStore.set({
|
|
27
|
+
...currentSession,
|
|
28
|
+
refreshAfter,
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
// Refresh token successful, go back to the page that called 403
|
|
32
|
+
// Forces complete navigation through getServerSideProps by adding a cache-busting parameter
|
|
33
|
+
const previousPage = fromPage || '/pvt/account'
|
|
34
|
+
|
|
35
|
+
// Add timestamp to force server-side navigation and avoid browser cache
|
|
36
|
+
const url = new URL(previousPage, window.location.origin)
|
|
37
|
+
url.searchParams.set('_refresh', Date.now().toString())
|
|
38
|
+
window.location.href = url.toString()
|
|
39
|
+
} else {
|
|
40
|
+
// If refresh token failed, set refreshAfter to now + 1 hour
|
|
41
|
+
sessionStore.set({
|
|
42
|
+
...currentSession,
|
|
43
|
+
refreshAfter: String(Math.floor(Date.now() / 1000) + 1 * 60 * 60), // now + 1 hour
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
setShouldShow403(true)
|
|
47
|
+
}
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('Error during refresh token process:', error)
|
|
50
|
+
|
|
51
|
+
// Set refreshAfter to postpone future requests and redirect to login
|
|
52
|
+
sessionStore.set({
|
|
53
|
+
...currentSession,
|
|
54
|
+
refreshAfter: String(Math.floor(Date.now() / 1000) + 1 * 60 * 60), // now + 1 hour
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
setShouldShow403(true)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
handleRefreshTokenAndUpdateSession()
|
|
62
|
+
}, [needsRefreshToken, fromPage])
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
shouldShow403,
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -15,18 +15,62 @@ const query = gql(`
|
|
|
15
15
|
`)
|
|
16
16
|
|
|
17
17
|
export async function validateUser(context: GetServerSidePropsContext) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
try {
|
|
19
|
+
const validateUserResult = await execute<
|
|
20
|
+
ValidateUserQueryVariables,
|
|
21
|
+
ValidateUserQuery
|
|
22
|
+
>(
|
|
23
|
+
{
|
|
24
|
+
variables: {},
|
|
25
|
+
operation: query,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
headers: { ...context.req.headers },
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if (validateUserResult?.errors && validateUserResult.errors.length > 0) {
|
|
33
|
+
const hasUnauthorizedError = validateUserResult.errors.some(
|
|
34
|
+
(error: any) => {
|
|
35
|
+
const statusCode = error?.extensions?.status || error?.status
|
|
36
|
+
const errorType = error?.extensions?.type
|
|
37
|
+
return statusCode === 401 || errorType === 'UnauthorizedError'
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if (hasUnauthorizedError) {
|
|
42
|
+
return {
|
|
43
|
+
isValid: false,
|
|
44
|
+
needsRefresh: true,
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// For other errors, return as invalid without refresh
|
|
49
|
+
return {
|
|
50
|
+
isValid: false,
|
|
51
|
+
needsRefresh: false,
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
isValid: !!validateUserResult?.data?.validateUser?.isValid,
|
|
57
|
+
needsRefresh: false,
|
|
28
58
|
}
|
|
29
|
-
)
|
|
59
|
+
} catch (error: any) {
|
|
60
|
+
const statusCode = error?.extensions?.status || error?.status
|
|
61
|
+
const errorType = error?.extensions?.type
|
|
30
62
|
|
|
31
|
-
|
|
63
|
+
if (statusCode === 401 || errorType === 'UnauthorizedError') {
|
|
64
|
+
return {
|
|
65
|
+
isValid: false,
|
|
66
|
+
needsRefresh: true,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// For other errors, return as invalid without refresh
|
|
71
|
+
return {
|
|
72
|
+
isValid: false,
|
|
73
|
+
needsRefresh: false,
|
|
74
|
+
}
|
|
75
|
+
}
|
|
32
76
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { useSearch } from '@faststore/sdk'
|
|
2
|
+
import {
|
|
3
|
+
PICKUP_IN_POINT_FACET_VALUE,
|
|
4
|
+
PICKUP_POINT_FACET_KEY,
|
|
5
|
+
SHIPPING_FACET_KEY,
|
|
6
|
+
useDeliveryPromiseContext,
|
|
7
|
+
} from '.'
|
|
2
8
|
|
|
3
9
|
export function useDeliveryPromiseFacets() {
|
|
4
10
|
const { state: searchState } = useSearch()
|
|
@@ -14,6 +20,25 @@ export function useDeliveryPromiseFacets() {
|
|
|
14
20
|
}
|
|
15
21
|
}
|
|
16
22
|
|
|
23
|
+
export function useDeliveryPromiseGlobalFacets() {
|
|
24
|
+
const { globalPickupPoint } = useDeliveryPromiseContext()
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
globalDeliveryFacets: globalPickupPoint
|
|
28
|
+
? [
|
|
29
|
+
{
|
|
30
|
+
key: PICKUP_POINT_FACET_KEY,
|
|
31
|
+
value: globalPickupPoint.id,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
key: SHIPPING_FACET_KEY,
|
|
35
|
+
value: PICKUP_IN_POINT_FACET_VALUE,
|
|
36
|
+
},
|
|
37
|
+
]
|
|
38
|
+
: [],
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
17
42
|
const pickByKey =
|
|
18
43
|
(keys: Array<string>) =>
|
|
19
44
|
({ key }: { key: string }) =>
|
package/src/sdk/session/index.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Session } from '@faststore/sdk'
|
|
2
2
|
import { createSessionStore } from '@faststore/sdk'
|
|
3
|
-
import fetch from 'isomorphic-unfetch'
|
|
4
3
|
import { useMemo } from 'react'
|
|
5
4
|
|
|
6
5
|
import { gql } from '@generated'
|
|
@@ -8,17 +7,17 @@ import type {
|
|
|
8
7
|
ValidateSessionMutation,
|
|
9
8
|
ValidateSessionMutationVariables,
|
|
10
9
|
} from '@generated/graphql'
|
|
11
|
-
import discoveryConfig from 'discovery.config'
|
|
12
10
|
import deepEqual from 'fast-deep-equal'
|
|
13
|
-
import { sanitizeHost } from 'src/utils/utilities'
|
|
14
11
|
import storeConfig from '../../../discovery.config'
|
|
12
|
+
import {
|
|
13
|
+
isRefreshTokenSuccessful,
|
|
14
|
+
refreshTokenRequest,
|
|
15
|
+
} from '../account/refreshToken'
|
|
15
16
|
import { cartStore } from '../cart'
|
|
16
17
|
import { request } from '../graphql/request'
|
|
17
18
|
import { createValidationStore, useStore } from '../useStore'
|
|
18
19
|
import { getPostalCode } from '../userLocation/index'
|
|
19
20
|
|
|
20
|
-
const REFRESH_TOKEN_URL = `${discoveryConfig.storeUrl}/api/vtexid/refreshtoken/webstore`
|
|
21
|
-
|
|
22
21
|
export const mutation = gql(`
|
|
23
22
|
mutation ValidateSession($session: IStoreSession!, $search: String!) {
|
|
24
23
|
validateSession(session: $session, search: $search) {
|
|
@@ -112,19 +111,9 @@ export const validateSession = async (session: Session) => {
|
|
|
112
111
|
error?.status === 401 && storeConfig.experimental?.refreshToken
|
|
113
112
|
|
|
114
113
|
if (shouldRefreshToken) {
|
|
115
|
-
const
|
|
116
|
-
'content-type': 'application/json',
|
|
117
|
-
Host: `${sanitizeHost(discoveryConfig.storeUrl)}`,
|
|
118
|
-
}
|
|
114
|
+
const result = await refreshTokenRequest()
|
|
119
115
|
|
|
120
|
-
|
|
121
|
-
credentials: 'include',
|
|
122
|
-
headers,
|
|
123
|
-
body: JSON.stringify({}),
|
|
124
|
-
method: 'POST',
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
if (result?.status?.toLowerCase?.() === 'success') {
|
|
116
|
+
if (isRefreshTokenSuccessful(result)) {
|
|
128
117
|
const refreshAfter = String(
|
|
129
118
|
Math.floor(new Date(result?.refreshAfter).getTime() / 1000)
|
|
130
119
|
)
|
|
@@ -197,23 +186,3 @@ export const useSession = ({ filter }: SessionOptions = { filter: true }) => {
|
|
|
197
186
|
[isValidating, session, channel]
|
|
198
187
|
)
|
|
199
188
|
}
|
|
200
|
-
|
|
201
|
-
async function fetchWithRetry(
|
|
202
|
-
url: RequestInfo | URL,
|
|
203
|
-
init?: RequestInit,
|
|
204
|
-
maxRetries = 3
|
|
205
|
-
) {
|
|
206
|
-
for (let i = 0; i < maxRetries; i++) {
|
|
207
|
-
try {
|
|
208
|
-
const res = await fetch(url, init)
|
|
209
|
-
if (res.status !== 200) continue
|
|
210
|
-
|
|
211
|
-
const data = await res.json()
|
|
212
|
-
if (data.status?.toLowerCase?.() === 'success') {
|
|
213
|
-
return data
|
|
214
|
-
}
|
|
215
|
-
} catch {}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return
|
|
219
|
-
}
|
package/src/server/index.ts
CHANGED
|
@@ -11,6 +11,8 @@ import { useParserCache } from '@envelop/parser-cache'
|
|
|
11
11
|
import { useValidationCache } from '@envelop/validation-cache'
|
|
12
12
|
import type { CacheControl, Maybe } from '@faststore/api'
|
|
13
13
|
import {
|
|
14
|
+
authDirective,
|
|
15
|
+
cacheControlDirective,
|
|
14
16
|
BadRequestError,
|
|
15
17
|
getContextFactory,
|
|
16
18
|
getResolvers,
|
|
@@ -61,10 +63,14 @@ function getFinalAPISchema() {
|
|
|
61
63
|
const generatedSchema = loadGeneratedSchema()
|
|
62
64
|
const nativeResolvers = getResolvers(apiOptions)
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
const schema = makeExecutableSchema({
|
|
65
67
|
typeDefs: generatedSchema,
|
|
66
68
|
resolvers: [nativeResolvers, vtexExtensionsResolvers, thirdPartyResolvers],
|
|
67
69
|
})
|
|
70
|
+
|
|
71
|
+
// Apply directive transformations
|
|
72
|
+
const directives = [cacheControlDirective, authDirective]
|
|
73
|
+
return directives.reduce((s, d) => d.transformer(s), schema)
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
export const getEnvelop = async () =>
|
package/src/utils/utilities.ts
CHANGED
|
@@ -108,10 +108,3 @@ export const buildFormData = (
|
|
|
108
108
|
|
|
109
109
|
export const toArray = <T>(x: T[] | T | undefined) =>
|
|
110
110
|
Array.isArray(x) ? x : x ? [x] : []
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Array merging strategy from deepmerge that makes source arrays overwrite destination array
|
|
114
|
-
*
|
|
115
|
-
* @see https://www.npmjs.com/package/deepmerge
|
|
116
|
-
*/
|
|
117
|
-
export const overwriteMerge = (_: any[], sourceArray: any[]) => sourceArray
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";exports.id=7947,exports.ids=[7947],exports.modules={7947:(e,r,t)=>{t.a(e,async(e,n)=>{try{t.d(r,{h:()=>validateUser});var a=t(25487),o=t(99563),i=e([o]);function ownKeys(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter(function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable})),t.push.apply(t,n)}return t}o=(i.then?(await i)():i)[0];let c=a.fW;async function validateUser(e){let r=await (0,o.h)({variables:{},operation:c},{headers:function(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{};r%2?ownKeys(Object(t),!0).forEach(function(r){var n;n=t[r],r in e?Object.defineProperty(e,r,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[r]=n}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):ownKeys(Object(t)).forEach(function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))})}return e}({},e.req.headers)});return r?.data?.validateUser?.isValid}n()}catch(e){n(e)}})}};
|