@faststore/core 3.95.1-dev.0 → 3.96.0-dev.17
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 +54 -54
- 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 +6 -6
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/7098.js +1 -1
- package/.next/server/chunks/948.js +1 -1
- package/.next/server/chunks/9563.js +3 -3
- package/.next/server/chunks/9630.js +7 -7
- 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/[...slug].js +1 -1
- package/.next/server/pages/[slug]/p.js +1 -1
- package/.next/server/pages/api/graphql.js +3 -3
- 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/en-US.json +1 -1
- package/.next/server/pages/pvt/account/orders/[id].js +1 -1
- package/.next/server/pages/s.js +1 -1
- package/.next/server/pages-manifest.json +1 -1
- package/.next/static/Yo88n9O6FrhtIc3GGfGv9/_buildManifest.js +1 -0
- package/.next/static/chunks/{1841.b3a98a2a1886b09c.js → 1841.a1b15f2c88e02d32.js} +1 -1
- package/.next/static/chunks/{2500.d6beb5af6ee00a9e.js → 2500.b188ad84b5a0a521.js} +1 -1
- package/.next/static/chunks/{7191-5aa417081c97d46a.js → 7191-e43007cdde83bc1f.js} +1 -1
- package/.next/static/chunks/{9173-49a05f6f96710bd1.js → 9173-2ed920b87ee6640e.js} +1 -1
- package/.next/static/chunks/pages/{404-4b3f1e22c77f849a.js → 404-f04d51a89ab8e8c8.js} +1 -1
- package/.next/static/chunks/pages/{500-bb2de0c11524b2b8.js → 500-b3cd1219951eb7d1.js} +1 -1
- package/.next/static/chunks/pages/{[...slug]-3579b3b8b8309552.js → [...slug]-28b3f75a1b2b22b8.js} +1 -1
- package/.next/static/chunks/pages/[slug]/{p-cf620759e25940f8.js → p-f3b7653e4bd1ba57.js} +1 -1
- package/.next/static/chunks/pages/{_app-8e3a3eccc99a6f96.js → _app-38f75642a57fe506.js} +1 -1
- package/.next/static/chunks/pages/{checkout-dc07d72b3514c83d.js → checkout-9a253c6c2498d41f.js} +1 -1
- package/.next/static/chunks/pages/{index-1f8bf0fb351b90f4.js → index-f522924c892c46dd.js} +1 -1
- package/.next/static/chunks/pages/{login-e97ef92769456bf6.js → login-1d364797aaa9da36.js} +1 -1
- package/.next/static/chunks/pages/pvt/account/{403-91597100f8956385.js → 403-2105ed93b3e3e58e.js} +1 -1
- package/.next/static/chunks/pages/pvt/account/{404-c68124bed7cb7c48.js → 404-2e555481b1a4f63b.js} +1 -1
- package/.next/static/chunks/pages/pvt/account/orders/{[id]-68bbe8db444fd60a.js → [id]-2bd9adec59ae1ed3.js} +1 -1
- package/.next/static/chunks/pages/pvt/account/{orders-12a215899ae6f3eb.js → orders-4d66173a6e6282a1.js} +1 -1
- package/.next/static/chunks/pages/pvt/account/{profile-b6cdbf02d4682544.js → profile-1799ddf1749086aa.js} +1 -1
- package/.next/static/chunks/pages/pvt/account/{security-e6289a40e745d3c4.js → security-f2734d61da9099db.js} +1 -1
- package/.next/static/chunks/pages/pvt/account/{user-details-fba1822e52e7de26.js → user-details-c8636b99b6725815.js} +1 -1
- package/.next/static/chunks/pages/{s-41cffb20de1d2617.js → s-603fab8b09726274.js} +1 -1
- package/.next/static/chunks/{webpack-f9e5828934d6d57c.js → webpack-3cd689c2fd3d4dd1.js} +1 -1
- package/.next/trace +138 -138
- package/.turbo/turbo-build.log +17 -17
- package/.turbo/turbo-test.log +8 -7
- package/@generated/gql.ts +2 -2
- package/@generated/graphql.ts +6 -1
- package/@generated/persisted-documents.json +1 -1
- package/@generated/schema.graphql +3 -0
- package/CHANGELOG.md +82 -0
- package/cms/faststore/base.jsonc +42 -0
- package/cms/faststore/components/cms_component__alert.jsonc +40 -0
- package/cms/faststore/components/cms_component__bannernewsletter.jsonc +183 -0
- package/cms/faststore/components/cms_component__bannertext.jsonc +51 -0
- package/cms/faststore/components/cms_component__breadcrumb.jsonc +21 -0
- package/cms/faststore/components/cms_component__cartsidebar.jsonc +122 -0
- package/cms/faststore/components/cms_component__children.jsonc +8 -0
- package/cms/faststore/components/cms_component__crosssellingshelf.jsonc +50 -0
- package/cms/faststore/components/cms_component__emptystate.jsonc +73 -0
- package/cms/faststore/components/cms_component__footer.jsonc +238 -0
- package/cms/faststore/components/cms_component__hero.jsonc +71 -0
- package/cms/faststore/components/cms_component__incentives.jsonc +51 -0
- package/cms/faststore/components/cms_component__navbar.jsonc +318 -0
- package/cms/faststore/components/cms_component__newsletter.jsonc +133 -0
- package/cms/faststore/components/cms_component__productdetails.jsonc +246 -0
- package/cms/faststore/components/cms_component__productgallery.jsonc +312 -0
- package/cms/faststore/components/cms_component__productshelf.jsonc +117 -0
- package/cms/faststore/components/cms_component__producttiles.jsonc +95 -0
- package/cms/faststore/components/cms_component__regionbar.jsonc +58 -0
- package/cms/faststore/components/cms_component__regionmodal.jsonc +85 -0
- package/cms/faststore/components/cms_component__regionpopover.jsonc +97 -0
- package/cms/faststore/components/cms_component__search.jsonc +144 -0
- package/cms/faststore/pages/cms_content_type__404.jsonc +18 -0
- package/cms/faststore/pages/cms_content_type__500.jsonc +18 -0
- package/cms/faststore/pages/cms_content_type__globalfootersections.jsonc +73 -0
- package/cms/faststore/pages/cms_content_type__globalheadersections.jsonc +73 -0
- package/cms/faststore/pages/cms_content_type__globalsections.jsonc +375 -0
- package/cms/faststore/pages/cms_content_type__home.jsonc +213 -0
- package/cms/faststore/pages/cms_content_type__landingpage.jsonc +108 -0
- package/cms/faststore/pages/cms_content_type__login.jsonc +18 -0
- package/cms/faststore/pages/cms_content_type__pdp.jsonc +115 -0
- package/cms/faststore/pages/cms_content_type__plp.jsonc +130 -0
- package/cms/faststore/pages/cms_content_type__search.jsonc +118 -0
- package/cms/faststore/schema.json +3859 -0
- package/cms/faststore/sections.json +2 -2
- package/package.json +15 -8
- package/src/components/account/orders/MyAccountOrderDetails/MyAccountDeliveryOptionAccordion/MyAccountDeliveryOptionAccordion.tsx +18 -15
- package/src/components/account/orders/MyAccountOrderDetails/MyAccountOrderDetails.tsx +9 -3
- package/src/components/account/orders/MyAccountOrderDetails/MyAccountSummaryCard/MyAccountSummaryCard.tsx +0 -1
- package/src/pages/api/graphql.ts +26 -5
- package/src/pages/pvt/account/orders/[id].tsx +2 -0
- package/src/sdk/graphql/request.ts +10 -1
- package/src/utils/cookieCacheBusting.ts +141 -0
- package/test/utils/cookieCacheBusting.test.ts +121 -0
- package/.next/static/xPZqGftdSs0H8UD6M_H3H/_buildManifest.js +0 -1
- /package/.next/static/{xPZqGftdSs0H8UD6M_H3H → Yo88n9O6FrhtIc3GGfGv9}/_ssgManifest.js +0 -0
|
@@ -959,7 +959,7 @@
|
|
|
959
959
|
"after": {
|
|
960
960
|
"type": "integer",
|
|
961
961
|
"title": "After",
|
|
962
|
-
"default":
|
|
962
|
+
"default": 0,
|
|
963
963
|
"description": "Initial pagination item"
|
|
964
964
|
},
|
|
965
965
|
"sort": {
|
|
@@ -1122,7 +1122,7 @@
|
|
|
1122
1122
|
"after": {
|
|
1123
1123
|
"title": "After",
|
|
1124
1124
|
"type": "integer",
|
|
1125
|
-
"default":
|
|
1125
|
+
"default": 0,
|
|
1126
1126
|
"description": "Initial pagination item"
|
|
1127
1127
|
},
|
|
1128
1128
|
"sort": {
|
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.96.0-dev.17",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"repository":
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/vtex/faststore",
|
|
8
|
+
"directory": "packages/core"
|
|
9
|
+
},
|
|
6
10
|
"browserslist": "supports es6-module and not dead",
|
|
7
11
|
"exports": {
|
|
8
12
|
".": "./index.ts",
|
|
@@ -36,6 +40,9 @@
|
|
|
36
40
|
"pnpm": "9.15.1",
|
|
37
41
|
"yarn": "1.22.22"
|
|
38
42
|
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
39
46
|
"sideEffects": false,
|
|
40
47
|
"dependencies": {
|
|
41
48
|
"@antfu/ni": "^0.21.12",
|
|
@@ -44,11 +51,11 @@
|
|
|
44
51
|
"@envelop/graphql-jit": "^8.0.3",
|
|
45
52
|
"@envelop/parser-cache": "^6.0.2",
|
|
46
53
|
"@envelop/validation-cache": "^6.0.2",
|
|
47
|
-
"@faststore/api": "3.
|
|
48
|
-
"@faststore/graphql-utils": "^3.
|
|
49
|
-
"@faststore/lighthouse": "3.
|
|
50
|
-
"@faststore/sdk": "3.
|
|
51
|
-
"@faststore/ui": "3.
|
|
54
|
+
"@faststore/api": "3.96.0-dev.17",
|
|
55
|
+
"@faststore/graphql-utils": "^3.96.0-dev.17",
|
|
56
|
+
"@faststore/lighthouse": "3.96.0-dev.17",
|
|
57
|
+
"@faststore/sdk": "3.96.0-dev.17",
|
|
58
|
+
"@faststore/ui": "3.96.0-dev.17",
|
|
52
59
|
"@graphql-codegen/cli": "5.0.2",
|
|
53
60
|
"@graphql-codegen/client-preset": "4.2.6",
|
|
54
61
|
"@graphql-codegen/typescript": "4.0.7",
|
|
@@ -116,5 +123,5 @@
|
|
|
116
123
|
"ts-jest": "29.1.1",
|
|
117
124
|
"typescript": "5.3.2"
|
|
118
125
|
},
|
|
119
|
-
"gitHead": "
|
|
126
|
+
"gitHead": "303ea1a81126ab23f136c241a18f00c681c574d8"
|
|
120
127
|
}
|
|
@@ -69,21 +69,24 @@ function MyAccountDeliveryOptionAccordion({
|
|
|
69
69
|
contact={contact}
|
|
70
70
|
/>
|
|
71
71
|
<MyAccountDeliveryOptionAccordionProducts>
|
|
72
|
-
{deliveryOption.items?.map((item, index) =>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
72
|
+
{deliveryOption.items?.map((item, index) => {
|
|
73
|
+
const tax = (item.tax ?? 0) + (item.taxPriceTagsTotal ?? 0)
|
|
74
|
+
return (
|
|
75
|
+
<MyAccountDeliveryOptionAccordionProduct
|
|
76
|
+
key={index}
|
|
77
|
+
image={item.imageUrl || ''}
|
|
78
|
+
quantity={item.quantity}
|
|
79
|
+
name={item.name}
|
|
80
|
+
field={
|
|
81
|
+
customFields?.find((cf) => cf.id === item.uniqueId)
|
|
82
|
+
?.fields?.[0]
|
|
83
|
+
}
|
|
84
|
+
price={formatPrice(item.sellingPrice ?? 0, currencyCode)}
|
|
85
|
+
tax={formatPrice(tax, currencyCode)}
|
|
86
|
+
total={formatPrice(item.total ?? 0, currencyCode)}
|
|
87
|
+
/>
|
|
88
|
+
)
|
|
89
|
+
})}
|
|
87
90
|
</MyAccountDeliveryOptionAccordionProducts>
|
|
88
91
|
</MyAccountAccordionPanel>
|
|
89
92
|
</MyAccountAccordionItem>
|
|
@@ -8,7 +8,11 @@ import MyAccountOrderedByCard from './MyAccountOrderedByCard'
|
|
|
8
8
|
import MyAccountPaymentCard from './MyAccountPaymentCard'
|
|
9
9
|
import MyAccountSummaryCard from './MyAccountSummaryCard'
|
|
10
10
|
|
|
11
|
-
import type {
|
|
11
|
+
import type {
|
|
12
|
+
ServerOrderDetailsQueryQuery,
|
|
13
|
+
UserOrderDeliveryOption,
|
|
14
|
+
UserOrderDeliveryOptionsData,
|
|
15
|
+
} from '@generated/graphql'
|
|
12
16
|
import type { OrderStatusKey } from 'src/utils/userOrderStatus'
|
|
13
17
|
import MyAccountStatusBadge from '../../components/MyAccountStatusBadge'
|
|
14
18
|
import MyAccountMoreInformationCard from './MyAccountMoreInformationCard'
|
|
@@ -72,7 +76,9 @@ export default function MyAccountOrderDetails({
|
|
|
72
76
|
/>
|
|
73
77
|
|
|
74
78
|
<MyAccountDeliveryCard
|
|
75
|
-
deliveryOptionsData={
|
|
79
|
+
deliveryOptionsData={
|
|
80
|
+
order.deliveryOptionsData as UserOrderDeliveryOptionsData
|
|
81
|
+
}
|
|
76
82
|
fields={
|
|
77
83
|
order?.customFields?.find((field) => field.type === 'address')
|
|
78
84
|
?.fields || []
|
|
@@ -99,7 +105,7 @@ export default function MyAccountOrderDetails({
|
|
|
99
105
|
{order.deliveryOptionsData.deliveryOptions.map((option) => (
|
|
100
106
|
<MyAccountDeliveryOptionAccordion
|
|
101
107
|
key={option.friendlyDeliveryOptionName}
|
|
102
|
-
deliveryOption={option}
|
|
108
|
+
deliveryOption={option as UserOrderDeliveryOption}
|
|
103
109
|
contact={order.deliveryOptionsData.contact}
|
|
104
110
|
currencyCode={order.storePreferencesData.currencyCode}
|
|
105
111
|
customFields={order.customFields.filter(
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import MyAccountCard from 'src/components/account/components/MyAccountCard'
|
|
2
2
|
import { useFormatPrice } from 'src/components/account/utils/useFormatPrice'
|
|
3
|
-
import { useSession } from 'src/sdk/session'
|
|
4
3
|
|
|
5
4
|
// Interface for order totals (items, shipping, discounts)
|
|
6
5
|
// TODO: Use type from API
|
package/src/pages/api/graphql.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
isFastStoreError,
|
|
5
5
|
stringifyCacheControl,
|
|
6
6
|
} from '@faststore/api'
|
|
7
|
+
import { parse } from 'cookie'
|
|
7
8
|
import type { NextApiHandler, NextApiRequest } from 'next'
|
|
8
9
|
|
|
9
10
|
import discoveryConfig from 'discovery.config'
|
|
@@ -34,7 +35,7 @@ const replaceSetCookieDomain = (request: NextApiRequest, setCookie: string) => {
|
|
|
34
35
|
|
|
35
36
|
const parseRequest = (request: NextApiRequest) => {
|
|
36
37
|
try {
|
|
37
|
-
const { operationName, operationHash, variables, query } =
|
|
38
|
+
const { operationName, operationHash, variables, query, v } =
|
|
38
39
|
request.method === 'POST'
|
|
39
40
|
? request.body
|
|
40
41
|
: {
|
|
@@ -45,6 +46,7 @@ const parseRequest = (request: NextApiRequest) => {
|
|
|
45
46
|
? request.query.variables
|
|
46
47
|
: ''
|
|
47
48
|
),
|
|
49
|
+
v: request.query.v,
|
|
48
50
|
query: undefined,
|
|
49
51
|
}
|
|
50
52
|
|
|
@@ -56,6 +58,7 @@ const parseRequest = (request: NextApiRequest) => {
|
|
|
56
58
|
},
|
|
57
59
|
},
|
|
58
60
|
variables,
|
|
61
|
+
v,
|
|
59
62
|
// Do not allow queries in production, only for devMode so we can use graphql tools
|
|
60
63
|
// like introspection etc. In production, we only accept known queries for better
|
|
61
64
|
// security
|
|
@@ -68,6 +71,17 @@ const parseRequest = (request: NextApiRequest) => {
|
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Checks if there is any cookie that starts with 'VtexIdclientAutCookie'
|
|
76
|
+
* in the request headers
|
|
77
|
+
*/
|
|
78
|
+
const hasVtexIdclientAutCookie = (request: NextApiRequest): boolean => {
|
|
79
|
+
const cookies = parse(request.headers.cookie ?? '')
|
|
80
|
+
return Object.keys(cookies).some((cookieName) =>
|
|
81
|
+
cookieName.startsWith('VtexIdclientAutCookie')
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
71
85
|
const handler: NextApiHandler = async (request, response) => {
|
|
72
86
|
if (request.method !== 'POST' && request.method !== 'GET') {
|
|
73
87
|
response.status(405).end()
|
|
@@ -76,7 +90,8 @@ const handler: NextApiHandler = async (request, response) => {
|
|
|
76
90
|
}
|
|
77
91
|
|
|
78
92
|
try {
|
|
79
|
-
|
|
93
|
+
// value is used to cache bust the request if there is a VtexIdclientAutCookie
|
|
94
|
+
const { operation, variables, query, v: value } = parseRequest(request)
|
|
80
95
|
|
|
81
96
|
if (
|
|
82
97
|
operation.__meta__.operationName === 'ValidateSession' &&
|
|
@@ -129,7 +144,7 @@ const handler: NextApiHandler = async (request, response) => {
|
|
|
129
144
|
const { data, errors, extensions } = await execute(
|
|
130
145
|
{
|
|
131
146
|
operation,
|
|
132
|
-
variables,
|
|
147
|
+
variables: { ...variables, ...(value ? { v: value } : {}) },
|
|
133
148
|
query,
|
|
134
149
|
},
|
|
135
150
|
{ headers: request.headers }
|
|
@@ -145,8 +160,13 @@ const handler: NextApiHandler = async (request, response) => {
|
|
|
145
160
|
return
|
|
146
161
|
}
|
|
147
162
|
|
|
163
|
+
const hasAuthCookie = hasVtexIdclientAutCookie(request)
|
|
164
|
+
|
|
148
165
|
if (extensions.cacheControl) {
|
|
149
|
-
const cacheControl = stringifyCacheControl(
|
|
166
|
+
const cacheControl = stringifyCacheControl(
|
|
167
|
+
extensions.cacheControl,
|
|
168
|
+
hasAuthCookie
|
|
169
|
+
)
|
|
150
170
|
response.setHeader('cache-control', cacheControl)
|
|
151
171
|
} else if (
|
|
152
172
|
request.method === 'GET' &&
|
|
@@ -167,9 +187,10 @@ const handler: NextApiHandler = async (request, response) => {
|
|
|
167
187
|
.staleWhileRevalidate
|
|
168
188
|
: DEFAULT_STALE_WHILE_REVALIDATE // 1 hour
|
|
169
189
|
|
|
190
|
+
const scope = hasAuthCookie ? 'private' : 'public'
|
|
170
191
|
response.setHeader(
|
|
171
192
|
'cache-control',
|
|
172
|
-
|
|
193
|
+
`${scope}, s-maxage=${maxAge}, stale-while-revalidate=${staleWhileRevalidate}`
|
|
173
194
|
)
|
|
174
195
|
} else {
|
|
175
196
|
response.setHeader('cache-control', 'no-cache, no-store')
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getClientCacheBustingValue } from 'src/utils/cookieCacheBusting'
|
|
2
|
+
|
|
1
3
|
export type RequestOptions = Omit<BaseRequestOptions, 'operation' | 'variables'>
|
|
2
4
|
export type Operation = {
|
|
3
5
|
__meta__?: Record<string, any>
|
|
@@ -12,6 +14,8 @@ export interface BaseRequestOptions<V = any> {
|
|
|
12
14
|
operation: Operation
|
|
13
15
|
variables: V
|
|
14
16
|
fetchOptions?: RequestInit
|
|
17
|
+
cacheBusting?: boolean
|
|
18
|
+
value?: string | null
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
const DEFAULT_HEADERS_BY_VERB: Record<string, Record<string, string>> = {
|
|
@@ -25,10 +29,14 @@ export const request = async <Query = unknown, Variables = unknown>(
|
|
|
25
29
|
variables: Variables,
|
|
26
30
|
options?: RequestOptions
|
|
27
31
|
) => {
|
|
32
|
+
// Get cache busting value based on cookie changes
|
|
33
|
+
const value = getClientCacheBustingValue()
|
|
34
|
+
|
|
28
35
|
const { data, errors } = await baseRequest<Variables, Query>('/api/graphql', {
|
|
29
36
|
...options,
|
|
30
37
|
variables,
|
|
31
38
|
operation,
|
|
39
|
+
value,
|
|
32
40
|
})
|
|
33
41
|
|
|
34
42
|
if (errors?.length) {
|
|
@@ -41,7 +49,7 @@ export const request = async <Query = unknown, Variables = unknown>(
|
|
|
41
49
|
/* This piece of code was taken out of @faststore/graphql-utils */
|
|
42
50
|
const baseRequest = async <V = any, D = any>(
|
|
43
51
|
endpoint: string,
|
|
44
|
-
{ operation, variables, fetchOptions }: BaseRequestOptions<V>
|
|
52
|
+
{ operation, variables, fetchOptions, value }: BaseRequestOptions<V>
|
|
45
53
|
): Promise<GraphQLResponse<D>> => {
|
|
46
54
|
const { operationName, operationHash } = operation['__meta__']
|
|
47
55
|
|
|
@@ -58,6 +66,7 @@ const baseRequest = async <V = any, D = any>(
|
|
|
58
66
|
operationName,
|
|
59
67
|
operationHash,
|
|
60
68
|
...(method === 'GET' && { variables: JSON.stringify(variables) }),
|
|
69
|
+
...(method === 'GET' && value && { v: value }),
|
|
61
70
|
})
|
|
62
71
|
|
|
63
72
|
const body =
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import discoveryConfig from 'discovery.config'
|
|
2
|
+
|
|
3
|
+
export const STORAGE_KEY_AUTH_COOKIE_VALUE = 'faststore_auth_cookie_value'
|
|
4
|
+
export const STORAGE_KEY_CACHE_BUST_LAST_VALUE =
|
|
5
|
+
'faststore_cache_bust_last_value'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Gets the VtexIdclientAutCookie value from browser
|
|
9
|
+
* Note: vtex_segment is httpOnly and cannot be accessed via JavaScript,
|
|
10
|
+
* so we only monitor VtexIdclientAutCookie_<account>
|
|
11
|
+
*/
|
|
12
|
+
const getAuthCookieValue = (): string | null => {
|
|
13
|
+
if (typeof document === 'undefined') {
|
|
14
|
+
return null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const account = discoveryConfig.api.storeId
|
|
18
|
+
const authCookieName = `VtexIdclientAutCookie_${account}`
|
|
19
|
+
const cookies = document.cookie.split(';').map((cookie) => cookie.trim())
|
|
20
|
+
const authCookie = cookies.find((c) => c.startsWith(`${authCookieName}=`))
|
|
21
|
+
|
|
22
|
+
if (!authCookie) {
|
|
23
|
+
return null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return authCookie.split('=').slice(1).join('=')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Gets the stored auth cookie value from sessionStorage (client-side only)
|
|
31
|
+
*/
|
|
32
|
+
const getStoredAuthCookieValue = (): string | null => {
|
|
33
|
+
if (typeof sessionStorage === 'undefined') {
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
return sessionStorage.getItem(STORAGE_KEY_AUTH_COOKIE_VALUE)
|
|
39
|
+
} catch {
|
|
40
|
+
return null
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Stores the auth cookie value in sessionStorage (client-side only)
|
|
46
|
+
*/
|
|
47
|
+
const storeAuthCookieValue = (value: string | null): void => {
|
|
48
|
+
if (typeof sessionStorage === 'undefined') {
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
if (value === null) {
|
|
54
|
+
sessionStorage.removeItem(STORAGE_KEY_AUTH_COOKIE_VALUE)
|
|
55
|
+
} else {
|
|
56
|
+
sessionStorage.setItem(STORAGE_KEY_AUTH_COOKIE_VALUE, value)
|
|
57
|
+
}
|
|
58
|
+
} catch {
|
|
59
|
+
// Ignore storage errors
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Gets the last cache busting value from sessionStorage (client-side only)
|
|
65
|
+
*/
|
|
66
|
+
const getLastValue = (): string | null => {
|
|
67
|
+
if (typeof sessionStorage === 'undefined') {
|
|
68
|
+
return null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
return sessionStorage.getItem(STORAGE_KEY_CACHE_BUST_LAST_VALUE)
|
|
73
|
+
} catch {
|
|
74
|
+
return null
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Stores the last cache busting value in sessionStorage (client-side only)
|
|
80
|
+
*/
|
|
81
|
+
const storeLastValue = (value: string): void => {
|
|
82
|
+
if (typeof sessionStorage === 'undefined') {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
sessionStorage.setItem(STORAGE_KEY_CACHE_BUST_LAST_VALUE, value)
|
|
88
|
+
} catch {
|
|
89
|
+
// Ignore storage errors
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Clears all cache busting related data from sessionStorage (client-side only)
|
|
95
|
+
*/
|
|
96
|
+
const clearStorage = (): void => {
|
|
97
|
+
if (typeof sessionStorage === 'undefined') {
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
sessionStorage.removeItem(STORAGE_KEY_AUTH_COOKIE_VALUE)
|
|
103
|
+
sessionStorage.removeItem(STORAGE_KEY_CACHE_BUST_LAST_VALUE)
|
|
104
|
+
} catch {
|
|
105
|
+
// Ignore storage errors
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Gets cache busting value for client-side based on auth cookie changes
|
|
111
|
+
*/
|
|
112
|
+
export const getClientCacheBustingValue = (): string | null => {
|
|
113
|
+
const currentAuthCookieValue = getAuthCookieValue()
|
|
114
|
+
|
|
115
|
+
// Guard clause: if auth cookie doesn't exist, clear storage and don't proceed with cache busting logic
|
|
116
|
+
if (currentAuthCookieValue === null) {
|
|
117
|
+
clearStorage()
|
|
118
|
+
return null
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const storedAuthCookieValue = getStoredAuthCookieValue()
|
|
122
|
+
|
|
123
|
+
// If auth cookie changed, update stored value and return new timestamp
|
|
124
|
+
if (currentAuthCookieValue !== storedAuthCookieValue) {
|
|
125
|
+
storeAuthCookieValue(currentAuthCookieValue)
|
|
126
|
+
const timestamp = Date.now().toString()
|
|
127
|
+
storeLastValue(timestamp)
|
|
128
|
+
return timestamp
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Auth cookie hasn't changed, return last value or create one if it doesn't exist
|
|
132
|
+
const lastValue = getLastValue()
|
|
133
|
+
if (lastValue) {
|
|
134
|
+
return lastValue
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Fallback: if no last value, create one
|
|
138
|
+
const timestamp = Date.now().toString()
|
|
139
|
+
storeLastValue(timestamp)
|
|
140
|
+
return timestamp
|
|
141
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
jest.mock('discovery.config', () => ({
|
|
6
|
+
__esModule: true,
|
|
7
|
+
default: {
|
|
8
|
+
api: {
|
|
9
|
+
storeId: 'store',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
}))
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
getClientCacheBustingValue,
|
|
16
|
+
STORAGE_KEY_AUTH_COOKIE_VALUE,
|
|
17
|
+
STORAGE_KEY_CACHE_BUST_LAST_VALUE,
|
|
18
|
+
} from '../../src/utils/cookieCacheBusting'
|
|
19
|
+
|
|
20
|
+
const setAuthCookie = (value: string) => {
|
|
21
|
+
document.cookie = `VtexIdclientAutCookie_store=${value}; path=/`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const clearAllCookies = () => {
|
|
25
|
+
const cookies = document.cookie
|
|
26
|
+
.split(';')
|
|
27
|
+
.map((c) => c.trim())
|
|
28
|
+
.filter(Boolean)
|
|
29
|
+
|
|
30
|
+
for (const cookie of cookies) {
|
|
31
|
+
const [name] = cookie.split('=')
|
|
32
|
+
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe('cookieCacheBusting', () => {
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
clearAllCookies()
|
|
39
|
+
sessionStorage.clear()
|
|
40
|
+
jest.restoreAllMocks()
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('should clear storage and return null when auth cookie is missing', () => {
|
|
44
|
+
const removeItemSpy = jest.spyOn(Storage.prototype, 'removeItem')
|
|
45
|
+
|
|
46
|
+
const result = getClientCacheBustingValue()
|
|
47
|
+
|
|
48
|
+
expect(result).toBeNull()
|
|
49
|
+
expect(removeItemSpy).toHaveBeenCalledWith(STORAGE_KEY_AUTH_COOKIE_VALUE)
|
|
50
|
+
expect(removeItemSpy).toHaveBeenCalledWith(
|
|
51
|
+
STORAGE_KEY_CACHE_BUST_LAST_VALUE
|
|
52
|
+
)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('should return a new timestamp and persist values when auth cookie changed', () => {
|
|
56
|
+
setAuthCookie('token-1')
|
|
57
|
+
|
|
58
|
+
const nowSpy = jest.spyOn(Date, 'now').mockReturnValue(1700000000000)
|
|
59
|
+
const setItemSpy = jest.spyOn(Storage.prototype, 'setItem')
|
|
60
|
+
|
|
61
|
+
const result = getClientCacheBustingValue()
|
|
62
|
+
|
|
63
|
+
expect(result).toBe('1700000000000')
|
|
64
|
+
expect(nowSpy).toHaveBeenCalled()
|
|
65
|
+
expect(setItemSpy).toHaveBeenCalledWith(
|
|
66
|
+
STORAGE_KEY_AUTH_COOKIE_VALUE,
|
|
67
|
+
'token-1'
|
|
68
|
+
)
|
|
69
|
+
expect(setItemSpy).toHaveBeenCalledWith(
|
|
70
|
+
STORAGE_KEY_CACHE_BUST_LAST_VALUE,
|
|
71
|
+
'1700000000000'
|
|
72
|
+
)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('should return last cached value when auth cookie is the same and last value exists', () => {
|
|
76
|
+
setAuthCookie('token-1')
|
|
77
|
+
sessionStorage.setItem(STORAGE_KEY_AUTH_COOKIE_VALUE, 'token-1')
|
|
78
|
+
sessionStorage.setItem(STORAGE_KEY_CACHE_BUST_LAST_VALUE, 'prev')
|
|
79
|
+
|
|
80
|
+
const nowSpy = jest.spyOn(Date, 'now')
|
|
81
|
+
const setItemSpy = jest.spyOn(Storage.prototype, 'setItem')
|
|
82
|
+
|
|
83
|
+
const result = getClientCacheBustingValue()
|
|
84
|
+
|
|
85
|
+
expect(result).toBe('prev')
|
|
86
|
+
expect(nowSpy).not.toHaveBeenCalled()
|
|
87
|
+
expect(setItemSpy).not.toHaveBeenCalled()
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('should create and persist a new last value when auth cookie is the same but last value is missing', () => {
|
|
91
|
+
setAuthCookie('token-1')
|
|
92
|
+
sessionStorage.setItem(STORAGE_KEY_AUTH_COOKIE_VALUE, 'token-1')
|
|
93
|
+
|
|
94
|
+
const nowSpy = jest.spyOn(Date, 'now').mockReturnValue(1700000000123)
|
|
95
|
+
const setItemSpy = jest.spyOn(Storage.prototype, 'setItem')
|
|
96
|
+
|
|
97
|
+
const result = getClientCacheBustingValue()
|
|
98
|
+
|
|
99
|
+
expect(result).toBe('1700000000123')
|
|
100
|
+
expect(nowSpy).toHaveBeenCalled()
|
|
101
|
+
expect(setItemSpy).toHaveBeenCalledWith(
|
|
102
|
+
STORAGE_KEY_CACHE_BUST_LAST_VALUE,
|
|
103
|
+
'1700000000123'
|
|
104
|
+
)
|
|
105
|
+
expect(setItemSpy).not.toHaveBeenCalledWith(
|
|
106
|
+
STORAGE_KEY_AUTH_COOKIE_VALUE,
|
|
107
|
+
'token-1'
|
|
108
|
+
)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('should keep "=" characters in cookie value', () => {
|
|
112
|
+
setAuthCookie('a=b=c')
|
|
113
|
+
|
|
114
|
+
jest.spyOn(Date, 'now').mockReturnValue(1700000000456)
|
|
115
|
+
|
|
116
|
+
const result = getClientCacheBustingValue()
|
|
117
|
+
|
|
118
|
+
expect(result).toBe('1700000000456')
|
|
119
|
+
expect(sessionStorage.getItem(STORAGE_KEY_AUTH_COOKIE_VALUE)).toBe('a=b=c')
|
|
120
|
+
})
|
|
121
|
+
})
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
self.__BUILD_MANIFEST=function(s,c,t,a,e,u,n){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":[s,c,t,e,"static/css/02259c549b2179f2.css","static/chunks/pages/index-1f8bf0fb351b90f4.js"],"/404":[s,c,t,a,"static/chunks/pages/404-4b3f1e22c77f849a.js"],"/500":[s,c,t,a,"static/chunks/pages/500-bb2de0c11524b2b8.js"],"/_error":["static/chunks/pages/_error-2b0148be56a716e9.js"],"/checkout":[s,c,t,"static/chunks/pages/checkout-dc07d72b3514c83d.js"],"/login":[s,c,t,a,"static/chunks/pages/login-e97ef92769456bf6.js"],"/pvt/account":["static/chunks/pages/pvt/account-65fefcc699344bdb.js"],"/pvt/account/403":[s,c,t,"static/css/0fae3d432331aae9.css","static/chunks/pages/pvt/account/403-91597100f8956385.js"],"/pvt/account/404":[s,c,t,"static/css/0fc6b2ff69142c6a.css","static/chunks/pages/pvt/account/404-c68124bed7cb7c48.js"],"/pvt/account/orders":[s,c,t,"static/css/40a294d0a24ad01d.css","static/chunks/pages/pvt/account/orders-12a215899ae6f3eb.js"],"/pvt/account/orders/[id]":[s,c,t,"static/css/5eecefd2c6deeee4.css","static/chunks/pages/pvt/account/orders/[id]-68bbe8db444fd60a.js"],"/pvt/account/profile":[s,c,t,"static/css/47f1b4e8de15d314.css","static/chunks/pages/pvt/account/profile-b6cdbf02d4682544.js"],"/pvt/account/security":[s,c,t,"static/css/973dd40d4773e8cd.css","static/chunks/pages/pvt/account/security-e6289a40e745d3c4.js"],"/pvt/account/user-details":[s,c,t,"static/css/05c399956ff24b77.css","static/chunks/pages/pvt/account/user-details-fba1822e52e7de26.js"],"/pvt/account/[...unknown]":["static/chunks/pages/pvt/account/[...unknown]-f80f645594d2740c.js"],"/s":[s,c,t,u,n,a,"static/chunks/pages/s-41cffb20de1d2617.js"],"/[slug]/p":[s,"static/chunks/1208-9118a8f14ecf05c8.js",c,t,"static/chunks/7522-9010743f5d7e8aca.js",e,"static/css/a6a4ebbe01adbbad.css","static/chunks/pages/[slug]/p-cf620759e25940f8.js"],"/[...slug]":[s,c,t,u,n,"static/chunks/pages/[...slug]-3579b3b8b8309552.js"],sortedPages:["/","/404","/500","/_app","/_error","/checkout","/login","/pvt/account","/pvt/account/403","/pvt/account/404","/pvt/account/orders","/pvt/account/orders/[id]","/pvt/account/profile","/pvt/account/security","/pvt/account/user-details","/pvt/account/[...unknown]","/s","/[slug]/p","/[...slug]"]}}("static/chunks/6031-b0b111f48a7d504d.js","static/css/9d403a1bee48c9fc.css","static/chunks/9173-49a05f6f96710bd1.js","static/css/2980acad3f8e1028.css","static/css/837662922091162f.css","static/css/31380ebc6e671486.css","static/chunks/7191-5aa417081c97d46a.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
|
|
File without changes
|