@faststore/core 3.71.0 → 3.72.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 +39 -39
- 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 +13 -13
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/2570.js +1 -0
- package/.next/server/chunks/4168.js +1 -1
- package/.next/server/chunks/4365.js +1 -1
- package/.next/server/chunks/4913.js +13 -0
- package/.next/server/chunks/5723.js +13 -0
- package/.next/server/chunks/772.js +6 -0
- package/.next/server/chunks/870.js +1 -1
- package/.next/server/chunks/948.js +1 -1
- package/.next/server/chunks/9563.js +2 -2
- package/.next/server/chunks/9630.js +2 -2
- package/.next/server/chunks/9990.js +1 -0
- 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 +1 -1
- package/.next/server/pages/404.js.nft.json +1 -1
- package/.next/server/pages/500.js +1 -1
- package/.next/server/pages/500.js.nft.json +1 -1
- package/.next/server/pages/[...slug].js +1 -1
- package/.next/server/pages/[...slug].js.nft.json +1 -1
- package/.next/server/pages/[slug]/p.js +1 -1
- package/.next/server/pages/[slug]/p.js.nft.json +1 -1
- package/.next/server/pages/_app.js +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 +1 -1
- package/.next/server/pages/_error.js.nft.json +1 -1
- package/.next/server/pages/account/403.js +1 -1
- package/.next/server/pages/account/403.js.nft.json +1 -1
- package/.next/server/pages/account/404.js +1 -1
- package/.next/server/pages/account/404.js.nft.json +1 -1
- package/.next/server/pages/account/[...unknown].js +1 -1
- package/.next/server/pages/account/[...unknown].js.nft.json +1 -1
- package/.next/server/pages/account/orders/[id].js +1 -1
- package/.next/server/pages/account/orders/[id].js.nft.json +1 -1
- package/.next/server/pages/account/orders.js +1 -1
- package/.next/server/pages/account/orders.js.nft.json +1 -1
- package/.next/server/pages/account/profile.js +1 -1
- package/.next/server/pages/account/profile.js.nft.json +1 -1
- package/.next/server/pages/account/security.js +1 -1
- package/.next/server/pages/account/security.js.nft.json +1 -1
- package/.next/server/pages/account/user-details.js +1 -1
- package/.next/server/pages/account/user-details.js.nft.json +1 -1
- package/.next/server/pages/account.js +1 -1
- package/.next/server/pages/account.js.nft.json +1 -1
- package/.next/server/pages/api/graphql.js +2 -2
- 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 +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/500.html +1 -1
- package/.next/server/pages/en-US/checkout.html +1 -1
- package/.next/server/pages/en-US/login.html +1 -1
- package/.next/server/pages/en-US/s.html +1 -1
- package/.next/server/pages/en-US.html +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 +1 -1
- package/.next/server/pages/login.js.nft.json +1 -1
- package/.next/server/pages/s.js +1 -1
- package/.next/server/pages/s.js.nft.json +1 -1
- package/.next/server/pages-manifest.json +1 -1
- package/.next/static/{nM-tG24KHPHfLNOK1C9F- → -SjQxcfSq7pTpFNFEK-4Z}/_buildManifest.js +1 -1
- package/.next/static/chunks/353.3e74b28c8ca649a2.js +1 -0
- package/.next/static/chunks/{6393.53e9ea4f29d1bf23.js → 6393.f13568b0fd5f52f6.js} +1 -1
- package/.next/static/chunks/{7191-df87383e8d7c078f.js → 7191-61293e7b7a7d9fc5.js} +1 -1
- package/.next/static/chunks/7692.d434a8499fb2aa03.js +1 -0
- package/.next/static/chunks/{9173-ed47aa8015d45a84.js → 9173-3a00edf7b695a319.js} +1 -1
- package/.next/static/chunks/{9399.49b20139636a39f2.js → 9399.6bd7f24a04ccfff4.js} +1 -1
- package/.next/static/chunks/941.2a946730a9174ed7.js +1 -0
- package/.next/static/chunks/pages/_app-4068e2b477988545.js +1 -0
- package/.next/static/chunks/{webpack-50cb24c3054682c1.js → webpack-2ddf567180dd5aaa.js} +1 -1
- package/.next/trace +134 -135
- package/.turbo/turbo-build.log +28 -28
- package/.turbo/turbo-test.log +5 -5
- package/@generated/gql.ts +2 -2
- package/@generated/graphql.ts +6 -1
- package/@generated/persisted-documents.json +1 -1
- package/@generated/schema.graphql +4 -0
- package/CHANGELOG.md +6 -0
- package/discovery.config.default.js +2 -0
- package/package.json +5 -4
- package/src/pages/api/graphql.ts +56 -0
- package/src/sdk/graphql/request.ts +13 -0
- package/src/sdk/session/index.ts +76 -6
- package/src/utils/getCookie.ts +22 -0
- package/.next/server/chunks/4941.js +0 -6
- package/.next/server/chunks/5244.js +0 -1
- package/.next/server/chunks/8130.js +0 -13
- package/.next/server/chunks/8404.js +0 -13
- package/.next/static/chunks/353.7f2181843462717d.js +0 -1
- package/.next/static/chunks/7692.1597d1d292a09609.js +0 -1
- package/.next/static/chunks/941.80a0abd58f11d696.js +0 -1
- package/.next/static/chunks/pages/_app-728289774860e9d9.js +0 -1
- /package/.next/static/{nM-tG24KHPHfLNOK1C9F- → -SjQxcfSq7pTpFNFEK-4Z}/_ssgManifest.js +0 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@3.
|
|
2
|
+
> @faststore/core@3.71.0 prebuild /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> na run partytown && na run generate
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @faststore/core@3.
|
|
6
|
+
> @faststore/core@3.71.0 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.
|
|
11
|
+
> @faststore/core@3.71.0 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.
|
|
15
|
+
> @faststore/core@3.71.0 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.
|
|
20
|
+
> @faststore/core@3.71.0 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.
|
|
40
|
+
> @faststore/core@3.71.0 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.
|
|
44
|
+
> @faststore/core@3.71.0 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
|
|
@@ -73,19 +73,19 @@ Warning: Dynamic Content not found for the page: home. Refer to the Dynamic Cont
|
|
|
73
73
|
Collecting build traces ...
|
|
74
74
|
|
|
75
75
|
Route (pages) Size First Load JS
|
|
76
|
-
┌ ● / 3.66 kB
|
|
76
|
+
┌ ● / 3.66 kB 140 kB
|
|
77
77
|
├ └ css/b1806cbafd0c1f81.css 3.06 kB
|
|
78
|
-
├ /_app 0 B
|
|
79
|
-
├ ● /[...slug] 2.45 kB
|
|
80
|
-
├ ● /[slug]/p 32.6 kB
|
|
78
|
+
├ /_app 0 B 106 kB
|
|
79
|
+
├ ● /[...slug] 2.45 kB 148 kB
|
|
80
|
+
├ ● /[slug]/p 32.6 kB 169 kB
|
|
81
81
|
├ ├ css/a3ca6a9b63f657be.css 5.75 kB
|
|
82
82
|
├ ├ css/62a5153ac7061286.css 6.11 kB
|
|
83
83
|
├ └ css/6831395ff5fd317a.css 16.1 kB
|
|
84
|
-
├ ○ /404 1.55 kB
|
|
85
|
-
├ ● /500 1.55 kB
|
|
86
|
-
├ λ /account 240 B
|
|
87
|
-
├ ● /account/[...unknown] 281 B
|
|
88
|
-
├ λ /account/403 2.44 kB
|
|
84
|
+
├ ○ /404 1.55 kB 138 kB
|
|
85
|
+
├ ● /500 1.55 kB 138 kB
|
|
86
|
+
├ λ /account 240 B 106 kB
|
|
87
|
+
├ ● /account/[...unknown] 281 B 106 kB
|
|
88
|
+
├ λ /account/403 2.44 kB 139 kB
|
|
89
89
|
├ └ css/b7bba8fce075688b.css 4.2 kB
|
|
90
90
|
├ λ /account/404 2.13 kB 138 kB
|
|
91
91
|
├ └ css/5347dbc8b71de47d.css 4.25 kB
|
|
@@ -93,24 +93,24 @@ Route (pages) Size First Load JS
|
|
|
93
93
|
├ └ css/3d41485722b4e3f5.css 12.1 kB
|
|
94
94
|
├ λ /account/orders/[id] 12.1 kB 148 kB
|
|
95
95
|
├ └ css/70353bf19c496790.css 12.6 kB
|
|
96
|
-
├ λ /account/profile 1.79 kB
|
|
96
|
+
├ λ /account/profile 1.79 kB 138 kB
|
|
97
97
|
├ └ css/831a1f72fe4b2d80.css 3.97 kB
|
|
98
|
-
├ λ /account/security 2.48 kB
|
|
98
|
+
├ λ /account/security 2.48 kB 139 kB
|
|
99
99
|
├ └ css/32b1696118552960.css 5.19 kB
|
|
100
|
-
├ λ /account/user-details 1.74 kB
|
|
100
|
+
├ λ /account/user-details 1.74 kB 138 kB
|
|
101
101
|
├ └ css/e46393a76c5d93a9.css 4.17 kB
|
|
102
|
-
├ λ /api/graphql 0 B
|
|
103
|
-
├ λ /api/health/live 0 B
|
|
104
|
-
├ λ /api/health/ready 0 B
|
|
105
|
-
├ λ /api/preview 0 B
|
|
106
|
-
├ ● /checkout 737 B
|
|
107
|
-
├ ● /login 1.68 kB
|
|
102
|
+
├ λ /api/graphql 0 B 106 kB
|
|
103
|
+
├ λ /api/health/live 0 B 106 kB
|
|
104
|
+
├ λ /api/health/ready 0 B 106 kB
|
|
105
|
+
├ λ /api/preview 0 B 106 kB
|
|
106
|
+
├ ● /checkout 737 B 137 kB
|
|
107
|
+
├ ● /login 1.68 kB 138 kB
|
|
108
108
|
└ ● /s 3.28 kB 148 kB
|
|
109
|
-
+ First Load JS shared by all
|
|
109
|
+
+ First Load JS shared by all 109 kB
|
|
110
110
|
├ chunks/framework-807b0f81cbc129f0.js 45.4 kB
|
|
111
111
|
├ chunks/main-f658704b53a96ab1.js 33.1 kB
|
|
112
|
-
├ chunks/pages/_app-
|
|
113
|
-
├ chunks/webpack-
|
|
112
|
+
├ chunks/pages/_app-4068e2b477988545.js 23.5 kB
|
|
113
|
+
├ chunks/webpack-2ddf567180dd5aaa.js 3.81 kB
|
|
114
114
|
└ css/0a57ee6c7a57788c.css 3.49 kB
|
|
115
115
|
|
|
116
116
|
λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@3.
|
|
2
|
+
> @faststore/core@3.71.0 test /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> jest
|
|
4
4
|
|
|
5
|
-
PASS test/
|
|
6
|
-
PASS test/
|
|
5
|
+
PASS test/utils/multipleTemplates.test.ts (26.363 s)
|
|
6
|
+
PASS test/server/cms/global.test.ts (26.431 s)
|
|
7
7
|
PASS test/server/cms/index.test.ts
|
|
8
|
-
PASS test/server/index.test.ts (29.
|
|
8
|
+
PASS test/server/index.test.ts (29.79 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.
|
|
13
|
+
Time: 31.087 s
|
|
14
14
|
Ran all test suites.
|
package/@generated/gql.ts
CHANGED
|
@@ -82,7 +82,7 @@ const documents = {
|
|
|
82
82
|
types.ClientSearchSuggestionsQueryDocument,
|
|
83
83
|
'\n query ClientTopSearchSuggestionsQuery(\n $term: String!\n $selectedFacets: [IStoreSelectedFacet!]\n ) {\n ...ClientTopSearchSuggestions\n search(first: 5, term: $term, selectedFacets: $selectedFacets) {\n suggestions {\n terms {\n value\n }\n }\n }\n }\n':
|
|
84
84
|
types.ClientTopSearchSuggestionsQueryDocument,
|
|
85
|
-
'\n mutation ValidateSession($session: IStoreSession!, $search: String!) {\n validateSession(session: $session, search: $search) {\n locale\n channel\n country\n addressType\n postalCode\n city\n deliveryMode {\n deliveryChannel\n deliveryMethod\n deliveryWindow {\n startDate\n endDate\n }\n }\n geoCoordinates {\n latitude\n longitude\n }\n currency {\n code\n symbol\n }\n person {\n id\n email\n givenName\n familyName\n }\n b2b {\n customerId\n isRepresentative\n unitName\n unitId\n firstName\n lastName\n userName\n userEmail\n savedPostalCode\n }\n marketingData {\n utmCampaign\n utmMedium\n utmSource\n utmiCampaign\n utmiPage\n utmiPart\n }\n }\n }\n':
|
|
85
|
+
'\n mutation ValidateSession($session: IStoreSession!, $search: String!) {\n validateSession(session: $session, search: $search) {\n locale\n channel\n country\n addressType\n postalCode\n city\n deliveryMode {\n deliveryChannel\n deliveryMethod\n deliveryWindow {\n startDate\n endDate\n }\n }\n geoCoordinates {\n latitude\n longitude\n }\n currency {\n code\n symbol\n }\n person {\n id\n email\n givenName\n familyName\n }\n b2b {\n customerId\n isRepresentative\n unitName\n unitId\n firstName\n lastName\n userName\n userEmail\n savedPostalCode\n }\n marketingData {\n utmCampaign\n utmMedium\n utmSource\n utmiCampaign\n utmiPage\n utmiPart\n }\n refreshAfter\n }\n }\n':
|
|
86
86
|
types.ValidateSessionDocument,
|
|
87
87
|
'\n query ClientShippingSimulationQuery(\n $postalCode: String!\n $country: String!\n $items: [IShippingItem!]!\n ) {\n ...ClientShippingSimulation\n shipping(items: $items, postalCode: $postalCode, country: $country) {\n logisticsInfo {\n slas {\n carrier\n price\n availableDeliveryWindows {\n startDateUtc\n endDateUtc\n price\n listPrice\n }\n shippingEstimate\n localizedEstimates\n deliveryChannel\n }\n }\n address {\n city\n neighborhood\n state\n }\n }\n }\n':
|
|
88
88
|
types.ClientShippingSimulationQueryDocument,
|
|
@@ -304,7 +304,7 @@ export function gql(
|
|
|
304
304
|
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
305
305
|
*/
|
|
306
306
|
export function gql(
|
|
307
|
-
source: '\n mutation ValidateSession($session: IStoreSession!, $search: String!) {\n validateSession(session: $session, search: $search) {\n locale\n channel\n country\n addressType\n postalCode\n city\n deliveryMode {\n deliveryChannel\n deliveryMethod\n deliveryWindow {\n startDate\n endDate\n }\n }\n geoCoordinates {\n latitude\n longitude\n }\n currency {\n code\n symbol\n }\n person {\n id\n email\n givenName\n familyName\n }\n b2b {\n customerId\n isRepresentative\n unitName\n unitId\n firstName\n lastName\n userName\n userEmail\n savedPostalCode\n }\n marketingData {\n utmCampaign\n utmMedium\n utmSource\n utmiCampaign\n utmiPage\n utmiPart\n }\n }\n }\n'
|
|
307
|
+
source: '\n mutation ValidateSession($session: IStoreSession!, $search: String!) {\n validateSession(session: $session, search: $search) {\n locale\n channel\n country\n addressType\n postalCode\n city\n deliveryMode {\n deliveryChannel\n deliveryMethod\n deliveryWindow {\n startDate\n endDate\n }\n }\n geoCoordinates {\n latitude\n longitude\n }\n currency {\n code\n symbol\n }\n person {\n id\n email\n givenName\n familyName\n }\n b2b {\n customerId\n isRepresentative\n unitName\n unitId\n firstName\n lastName\n userName\n userEmail\n savedPostalCode\n }\n marketingData {\n utmCampaign\n utmMedium\n utmSource\n utmiCampaign\n utmiPage\n utmiPart\n }\n refreshAfter\n }\n }\n'
|
|
308
308
|
): typeof import('./graphql').ValidateSessionDocument
|
|
309
309
|
/**
|
|
310
310
|
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
package/@generated/graphql.ts
CHANGED
|
@@ -571,6 +571,8 @@ export type IStoreSession = {
|
|
|
571
571
|
person: InputMaybe<IStorePerson>
|
|
572
572
|
/** Session input postal code. */
|
|
573
573
|
postalCode: InputMaybe<Scalars['String']['input']>
|
|
574
|
+
/** Refresh token after Information. */
|
|
575
|
+
refreshAfter: InputMaybe<Scalars['String']['input']>
|
|
574
576
|
}
|
|
575
577
|
|
|
576
578
|
/** Input to the cancel order API. */
|
|
@@ -1543,6 +1545,8 @@ export type StoreSession = {
|
|
|
1543
1545
|
person: Maybe<StorePerson>
|
|
1544
1546
|
/** Session postal code. */
|
|
1545
1547
|
postalCode: Maybe<Scalars['String']['output']>
|
|
1548
|
+
/** Refresh token after Information. */
|
|
1549
|
+
refreshAfter: Maybe<Scalars['String']['output']>
|
|
1546
1550
|
}
|
|
1547
1551
|
|
|
1548
1552
|
/** Product search results sorting options. */
|
|
@@ -3372,6 +3376,7 @@ export type ValidateSessionMutation = {
|
|
|
3372
3376
|
addressType: string | null
|
|
3373
3377
|
postalCode: string | null
|
|
3374
3378
|
city: string | null
|
|
3379
|
+
refreshAfter: string | null
|
|
3375
3380
|
deliveryMode: {
|
|
3376
3381
|
deliveryChannel: string
|
|
3377
3382
|
deliveryMethod: string
|
|
@@ -4166,7 +4171,7 @@ export const ClientTopSearchSuggestionsQueryDocument = {
|
|
|
4166
4171
|
export const ValidateSessionDocument = {
|
|
4167
4172
|
__meta__: {
|
|
4168
4173
|
operationName: 'ValidateSession',
|
|
4169
|
-
operationHash: '
|
|
4174
|
+
operationHash: '5da2700f5a69ee8835b1cb6c69e14f4b6e12c4df',
|
|
4170
4175
|
},
|
|
4171
4176
|
} as unknown as TypedDocumentString<
|
|
4172
4177
|
ValidateSessionMutation,
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"34ea14c0d4a57ddf9bc11e4be0cd2b5a6506d3d4": "query ClientProfileQuery($id: String!) { profile(id: $id) { addresses { city country geoCoordinate postalCode } } }",
|
|
22
22
|
"b548281d477a173be7b6960434604d69769a97e7": "fragment ClientSearchSuggestions on Query { search(first: 5, term: $term, selectedFacets: $selectedFacets) { suggestions { terms { value } } } } fragment ProductSummary_product on StoreProduct { additionalProperty { name propertyID value valueReference } advertisement { adId adResponseId } brand { brandName: name } brand { name } gtin image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations allVariantsByName availableVariations slugsMap } } name offers { lowPrice lowPriceWithTaxes offers { availability listPrice listPriceWithTaxes price priceWithTaxes quantity seller { identifier } } } id: productID sku slug unitMultiplier } fragment SearchEvent_metadata on SearchMetadata { fuzzy isTermMisspelled logicalOperator } query ClientSearchSuggestionsQuery($selectedFacets: [IStoreSelectedFacet!], $term: String!) { search(first: 5, term: $term, selectedFacets: $selectedFacets) { metadata { ...SearchEvent_metadata } products { pageInfo { totalCount } } suggestions { products { ...ProductSummary_product } terms { value } } } ...ClientSearchSuggestions }",
|
|
23
23
|
"e2385b0f11726d0068f96548f57a8dd441c064e3": "fragment ClientTopSearchSuggestions on Query { search(first: 5, term: $term, selectedFacets: $selectedFacets) { suggestions { terms { value } } } } query ClientTopSearchSuggestionsQuery($selectedFacets: [IStoreSelectedFacet!], $term: String!) { search(first: 5, term: $term, selectedFacets: $selectedFacets) { suggestions { terms { value } } } ...ClientTopSearchSuggestions }",
|
|
24
|
-
"
|
|
24
|
+
"5da2700f5a69ee8835b1cb6c69e14f4b6e12c4df": "mutation ValidateSession($search: String!, $session: IStoreSession!) { validateSession(session: $session, search: $search) { addressType b2b { customerId firstName isRepresentative lastName savedPostalCode unitId unitName userEmail userName } channel city country currency { code symbol } deliveryMode { deliveryChannel deliveryMethod deliveryWindow { endDate startDate } } geoCoordinates { latitude longitude } locale marketingData { utmCampaign utmMedium utmSource utmiCampaign utmiPage utmiPart } person { email familyName givenName id } postalCode refreshAfter } }",
|
|
25
25
|
"c35bad22f67f3eb34fea52bb49efa6b1da6b728d": "fragment ClientShippingSimulation on Query { shipping(items: $items, postalCode: $postalCode, country: $country) { address { city } } } query ClientShippingSimulationQuery($country: String!, $items: [IShippingItem!]!, $postalCode: String!) { shipping(items: $items, postalCode: $postalCode, country: $country) { address { city neighborhood state } logisticsInfo { slas { availableDeliveryWindows { endDateUtc listPrice price startDateUtc } carrier deliveryChannel localizedEstimates price shippingEstimate } } } ...ClientShippingSimulation }",
|
|
26
26
|
"5c2181dde311ca80b72e0cc76ac0855d8aa8b51e": "fragment ClientManyProducts on Query { search( first: $first after: $after sort: $sort term: $term selectedFacets: $selectedFacets sponsoredCount: $sponsoredCount ) { products { pageInfo { totalCount } } } } fragment ProductSummary_product on StoreProduct { additionalProperty { name propertyID value valueReference } advertisement { adId adResponseId } brand { brandName: name } brand { name } gtin image { alternateName url } isVariantOf { name productGroupID skuVariants { activeVariations allVariantsByName availableVariations slugsMap } } name offers { lowPrice lowPriceWithTaxes offers { availability listPrice listPriceWithTaxes price priceWithTaxes quantity seller { identifier } } } id: productID sku slug unitMultiplier } fragment SearchEvent_metadata on SearchMetadata { fuzzy isTermMisspelled logicalOperator } query ServerManyProductsQuery($after: String, $first: Int!, $selectedFacets: [IStoreSelectedFacet!]!, $sort: StoreSort!, $sponsoredCount: Int, $term: String!) { search( first: $first after: $after sort: $sort term: $term selectedFacets: $selectedFacets sponsoredCount: $sponsoredCount ) { metadata { ...SearchEvent_metadata } products { edges { node { ...ProductSummary_product } } pageInfo { totalCount } } } ...ClientManyProducts }"
|
|
27
27
|
}
|
|
@@ -1207,6 +1207,8 @@ type StoreSession {
|
|
|
1207
1207
|
b2b: StoreB2B
|
|
1208
1208
|
"""Marketing information."""
|
|
1209
1209
|
marketingData: StoreMarketingData
|
|
1210
|
+
"""Refresh token after Information."""
|
|
1211
|
+
refreshAfter: String
|
|
1210
1212
|
}
|
|
1211
1213
|
|
|
1212
1214
|
type StoreB2B {
|
|
@@ -1259,6 +1261,8 @@ input IStoreSession {
|
|
|
1259
1261
|
b2b: IStoreB2B
|
|
1260
1262
|
"""Marketing information input."""
|
|
1261
1263
|
marketingData: IStoreMarketingData
|
|
1264
|
+
"""Refresh token after Information."""
|
|
1265
|
+
refreshAfter: String
|
|
1262
1266
|
}
|
|
1263
1267
|
|
|
1264
1268
|
"""Shipping Simulation item input."""
|
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.72.0](https://github.com/vtex/faststore/compare/v3.71.0...v3.72.0) (2025-08-05)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- refresh token - SFS-2462 ([#2936](https://github.com/vtex/faststore/issues/2936)) ([0fc856f](https://github.com/vtex/faststore/commit/0fc856f46ffe800debccd90078564e9ff524e727)), closes [#1](https://github.com/vtex/faststore/issues/1) [#2](https://github.com/vtex/faststore/issues/2)
|
|
11
|
+
|
|
6
12
|
# [3.71.0](https://github.com/vtex/faststore/compare/v3.70.2...v3.71.0) (2025-08-05)
|
|
7
13
|
|
|
8
14
|
### Features
|
|
@@ -66,6 +66,7 @@ module.exports = {
|
|
|
66
66
|
utmiPart: '',
|
|
67
67
|
utmiPage: '',
|
|
68
68
|
},
|
|
69
|
+
refreshAfter: null, // timestamp in seconds e.g. '1743042990'
|
|
69
70
|
},
|
|
70
71
|
|
|
71
72
|
// Default cart
|
|
@@ -150,5 +151,6 @@ module.exports = {
|
|
|
150
151
|
maxAge: 0, // 0 disables cache, 5 * 60 enable cache control maxAge 5 minutes
|
|
151
152
|
staleWhileRevalidate: 60,
|
|
152
153
|
},
|
|
154
|
+
refreshToken: false,
|
|
153
155
|
},
|
|
154
156
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.72.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": "vtex/faststore",
|
|
6
6
|
"browserslist": "supports es6-module and not dead",
|
|
@@ -44,10 +44,10 @@
|
|
|
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.
|
|
47
|
+
"@faststore/api": "^3.72.0",
|
|
48
48
|
"@faststore/graphql-utils": "^3.56.1",
|
|
49
49
|
"@faststore/lighthouse": "^3.56.1",
|
|
50
|
-
"@faststore/sdk": "^3.
|
|
50
|
+
"@faststore/sdk": "^3.72.0",
|
|
51
51
|
"@faststore/ui": "^3.70.2",
|
|
52
52
|
"@graphql-codegen/cli": "5.0.2",
|
|
53
53
|
"@graphql-codegen/client-preset": "4.2.6",
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
"fs-extra": "^10.1.0",
|
|
73
73
|
"graphql": "^15.6.0",
|
|
74
74
|
"include-media": "^1.4.10",
|
|
75
|
+
"isomorphic-unfetch": "^3.1.0",
|
|
75
76
|
"next": "^13.5.9",
|
|
76
77
|
"next-seo": "^6.6.0",
|
|
77
78
|
"postcss": "^8.4.4",
|
|
@@ -107,5 +108,5 @@
|
|
|
107
108
|
"ts-jest": "29.1.1",
|
|
108
109
|
"typescript": "5.3.2"
|
|
109
110
|
},
|
|
110
|
-
"gitHead": "
|
|
111
|
+
"gitHead": "716cd3fd6d6bfd6ec1f857ce6f3829669de2fe6c"
|
|
111
112
|
}
|
package/src/pages/api/graphql.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BadRequestError,
|
|
3
|
+
UnauthorizedError,
|
|
3
4
|
isFastStoreError,
|
|
4
5
|
stringifyCacheControl,
|
|
5
6
|
} from '@faststore/api'
|
|
6
7
|
import type { NextApiHandler, NextApiRequest } from 'next'
|
|
7
8
|
|
|
8
9
|
import discoveryConfig from 'discovery.config'
|
|
10
|
+
import { getJWTAutCookie, isExpired } from 'src/utils/getCookie'
|
|
9
11
|
import { execute } from '../../server'
|
|
10
12
|
|
|
11
13
|
const ONE_MINUTE = 60
|
|
@@ -75,6 +77,54 @@ const handler: NextApiHandler = async (request, response) => {
|
|
|
75
77
|
try {
|
|
76
78
|
const { operation, variables, query } = parseRequest(request)
|
|
77
79
|
|
|
80
|
+
if (
|
|
81
|
+
operation.__meta__.operationName === 'ValidateSession' &&
|
|
82
|
+
discoveryConfig.experimental?.refreshToken
|
|
83
|
+
) {
|
|
84
|
+
const jwt = getJWTAutCookie({
|
|
85
|
+
headers: request.headers,
|
|
86
|
+
account: discoveryConfig.api.storeId,
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const tokenExpired = Boolean(jwt && isExpired(Number(jwt?.exp)))
|
|
90
|
+
|
|
91
|
+
const refreshAfterExist = !!variables?.session?.refreshAfter
|
|
92
|
+
|
|
93
|
+
const refreshAfterExpired =
|
|
94
|
+
refreshAfterExist && isExpired(Number(variables.session.refreshAfter))
|
|
95
|
+
|
|
96
|
+
const tokenExistAndIsFirstRefreshTokenRequest =
|
|
97
|
+
!!jwt && !refreshAfterExist
|
|
98
|
+
|
|
99
|
+
// when token expired, browser clears the cookie, but we still have the refreshAfter in session and the refresh token cookie
|
|
100
|
+
const tokenNotExistAndRefreshAfterExistAndIsExpired =
|
|
101
|
+
!jwt && !!refreshAfterExist && refreshAfterExpired
|
|
102
|
+
|
|
103
|
+
const tokenExpiredAndRefreshAfterIsNullOrExpired =
|
|
104
|
+
tokenExpired && (!refreshAfterExist || refreshAfterExpired)
|
|
105
|
+
|
|
106
|
+
const shouldRefreshToken =
|
|
107
|
+
tokenExistAndIsFirstRefreshTokenRequest ||
|
|
108
|
+
tokenNotExistAndRefreshAfterExistAndIsExpired ||
|
|
109
|
+
tokenExpiredAndRefreshAfterIsNullOrExpired
|
|
110
|
+
|
|
111
|
+
if (shouldRefreshToken) {
|
|
112
|
+
throw new UnauthorizedError(
|
|
113
|
+
'Unauthorized: Token expired. Please login again or refresh the page.'
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Prevents to call ValidateSession or ValidateCartMutation without session (required) and get GraphQLError
|
|
119
|
+
const doNotRun =
|
|
120
|
+
(operation.__meta__.operationName === 'ValidateSession' ||
|
|
121
|
+
operation.__meta__.operationName === 'ValidateCartMutation') &&
|
|
122
|
+
!variables?.session
|
|
123
|
+
|
|
124
|
+
if (doNotRun) {
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
|
|
78
128
|
const { data, errors, extensions } = await execute(
|
|
79
129
|
{
|
|
80
130
|
operation,
|
|
@@ -138,7 +188,13 @@ const handler: NextApiHandler = async (request, response) => {
|
|
|
138
188
|
return
|
|
139
189
|
}
|
|
140
190
|
|
|
191
|
+
if (err instanceof UnauthorizedError) {
|
|
192
|
+
response.status(401).end()
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
|
|
141
196
|
response.status(500).end()
|
|
197
|
+
return
|
|
142
198
|
}
|
|
143
199
|
}
|
|
144
200
|
|
|
@@ -81,5 +81,18 @@ const baseRequest = async <V = any, D = any>(
|
|
|
81
81
|
},
|
|
82
82
|
})
|
|
83
83
|
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
const statusText = response.statusText
|
|
86
|
+
return {
|
|
87
|
+
errors: [
|
|
88
|
+
{
|
|
89
|
+
status: response.status,
|
|
90
|
+
message: statusText,
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
data: undefined,
|
|
94
|
+
} as GraphQLResponse<D>
|
|
95
|
+
}
|
|
96
|
+
|
|
84
97
|
return response.json()
|
|
85
98
|
}
|
package/src/sdk/session/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Session } from '@faststore/sdk'
|
|
2
2
|
import { createSessionStore } from '@faststore/sdk'
|
|
3
|
+
import fetch from 'isomorphic-unfetch'
|
|
3
4
|
import { useMemo } from 'react'
|
|
4
5
|
|
|
5
6
|
import { gql } from '@generated'
|
|
@@ -7,12 +8,16 @@ import type {
|
|
|
7
8
|
ValidateSessionMutation,
|
|
8
9
|
ValidateSessionMutationVariables,
|
|
9
10
|
} from '@generated/graphql'
|
|
11
|
+
import discoveryConfig from 'discovery.config'
|
|
12
|
+
import { sanitizeHost } from 'src/utils/utilities'
|
|
10
13
|
import storeConfig from '../../../discovery.config'
|
|
11
14
|
import { cartStore } from '../cart'
|
|
12
15
|
import { request } from '../graphql/request'
|
|
13
16
|
import { getSavedAddress } from '../profile'
|
|
14
17
|
import { createValidationStore, useStore } from '../useStore'
|
|
15
18
|
|
|
19
|
+
const REFRESH_TOKEN_URL = `${discoveryConfig.storeUrl}/api/vtexid/refreshtoken/webstore`
|
|
20
|
+
|
|
16
21
|
export const mutation = gql(`
|
|
17
22
|
mutation ValidateSession($session: IStoreSession!, $search: String!) {
|
|
18
23
|
validateSession(session: $session, search: $search) {
|
|
@@ -63,6 +68,7 @@ export const mutation = gql(`
|
|
|
63
68
|
utmiPage
|
|
64
69
|
utmiPart
|
|
65
70
|
}
|
|
71
|
+
refreshAfter
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
74
|
`)
|
|
@@ -107,12 +113,54 @@ export const validateSession = async (session: Session) => {
|
|
|
107
113
|
}
|
|
108
114
|
}
|
|
109
115
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
116
|
+
try {
|
|
117
|
+
// Prevents to call ValidateSession without session (required) and get Error
|
|
118
|
+
if (!session) {
|
|
119
|
+
return null
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const data = await request<
|
|
123
|
+
ValidateSessionMutation,
|
|
124
|
+
ValidateSessionMutationVariables
|
|
125
|
+
>(mutation, { session, search: window.location.search })
|
|
126
|
+
|
|
127
|
+
return data.validateSession
|
|
128
|
+
} catch (error) {
|
|
129
|
+
const shouldRefreshToken =
|
|
130
|
+
error?.status === 401 && storeConfig.experimental?.refreshToken
|
|
131
|
+
|
|
132
|
+
if (shouldRefreshToken) {
|
|
133
|
+
const headers: HeadersInit = {
|
|
134
|
+
'content-type': 'application/json',
|
|
135
|
+
Host: `${sanitizeHost(discoveryConfig.storeUrl)}`,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const result = await fetchWithRetry(REFRESH_TOKEN_URL, {
|
|
139
|
+
credentials: 'include',
|
|
140
|
+
headers,
|
|
141
|
+
body: JSON.stringify({}),
|
|
142
|
+
method: 'POST',
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
if (result?.status?.toLowerCase?.() === 'success') {
|
|
146
|
+
const refreshAfter = String(
|
|
147
|
+
Math.floor(new Date(result?.refreshAfter).getTime() / 1000)
|
|
148
|
+
)
|
|
114
149
|
|
|
115
|
-
|
|
150
|
+
sessionStore.set({
|
|
151
|
+
...session,
|
|
152
|
+
refreshAfter,
|
|
153
|
+
})
|
|
154
|
+
} else {
|
|
155
|
+
// If the refresh token fails 3x, set the refreshAfter to now + 1 hour
|
|
156
|
+
// so that we can postpone refreshToken request and continue the ValidateSession request
|
|
157
|
+
sessionStore.set({
|
|
158
|
+
...session,
|
|
159
|
+
refreshAfter: String(Math.floor(Date.now() / 1000) + 1 * 60 * 60), // now + 1 hour
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
116
164
|
}
|
|
117
165
|
|
|
118
166
|
const [validationStore, onValidate] = createValidationStore(validateSession)
|
|
@@ -145,8 +193,10 @@ interface SessionOptions {
|
|
|
145
193
|
*/
|
|
146
194
|
|
|
147
195
|
export const useSession = ({ filter }: SessionOptions = { filter: true }) => {
|
|
148
|
-
|
|
196
|
+
const currentSessionStore = sessionStore.read() ?? sessionStore.readInitial()
|
|
197
|
+
const resultSessionStore = useStore(sessionStore)
|
|
149
198
|
const isValidating = useStore(validationStore)
|
|
199
|
+
let { channel, ...session } = resultSessionStore ?? currentSessionStore
|
|
150
200
|
|
|
151
201
|
if (filter) {
|
|
152
202
|
const { hasOnlyDefaultSalesChannel, ...filteredChannel } =
|
|
@@ -163,3 +213,23 @@ export const useSession = ({ filter }: SessionOptions = { filter: true }) => {
|
|
|
163
213
|
[isValidating, session, channel]
|
|
164
214
|
)
|
|
165
215
|
}
|
|
216
|
+
|
|
217
|
+
async function fetchWithRetry(
|
|
218
|
+
url: RequestInfo | URL,
|
|
219
|
+
init?: RequestInit,
|
|
220
|
+
maxRetries = 3
|
|
221
|
+
) {
|
|
222
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
223
|
+
try {
|
|
224
|
+
const res = await fetch(url, init)
|
|
225
|
+
if (res.status !== 200) continue
|
|
226
|
+
|
|
227
|
+
const data = await res.json()
|
|
228
|
+
if (data.status?.toLowerCase?.() === 'success') {
|
|
229
|
+
return data
|
|
230
|
+
}
|
|
231
|
+
} catch {}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return
|
|
235
|
+
}
|
package/src/utils/getCookie.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import { parse } from 'cookie'
|
|
2
|
+
import type { NextApiRequest } from 'next/types'
|
|
3
|
+
|
|
4
|
+
type Params = {
|
|
5
|
+
headers?: Record<string, string> | NextApiRequest['headers']
|
|
6
|
+
account: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const MILLISECONDS_PER_SECOND = 1000
|
|
10
|
+
|
|
1
11
|
export function getCookie(name: string): string | undefined {
|
|
2
12
|
const cookieString = decodeURIComponent(document.cookie)
|
|
3
13
|
const cookies = cookieString.split(';')
|
|
@@ -19,3 +29,15 @@ export function parseJwt(token: string) {
|
|
|
19
29
|
}
|
|
20
30
|
return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString())
|
|
21
31
|
}
|
|
32
|
+
|
|
33
|
+
export function getJWTAutCookie({ headers, account }: Params) {
|
|
34
|
+
const authCookie = parse(headers?.cookie ?? '')?.[
|
|
35
|
+
'VtexIdclientAutCookie_' + account
|
|
36
|
+
]
|
|
37
|
+
return parseJwt(authCookie)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function isExpired(exp: number): boolean {
|
|
41
|
+
const now = Math.floor(Date.now() / MILLISECONDS_PER_SECOND)
|
|
42
|
+
return now > exp
|
|
43
|
+
}
|