@faststore/core 3.99.3 → 3.99.6
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 +38 -38
- 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/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-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/3890.js +1 -1
- package/.next/server/chunks/948.js +1 -1
- package/.next/server/chunks/9563.js +1 -1
- 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/api/graphql.js +1 -1
- package/.next/server/pages/en-US/404.html +2 -2
- package/.next/server/pages/en-US/500.html +2 -2
- package/.next/server/pages/en-US/checkout.html +2 -2
- package/.next/server/pages/en-US/login.html +2 -2
- package/.next/server/pages/en-US/s.html +2 -2
- package/.next/server/pages/en-US.html +2 -2
- package/.next/server/pages/pvt/account/403.js +1 -1
- package/.next/server/pages-manifest.json +1 -1
- package/.next/static/{WPYJvsqBdHs3zpay3w2iE → UmIFhJcdMOfy3xrHNNZS2}/_buildManifest.js +1 -1
- package/.next/static/chunks/{2927.23bae2c79f0ac0f3.js → 2927.5a79877943a6bf7c.js} +1 -1
- package/.next/static/chunks/9173-515913f3f10caf5e.js +2 -0
- package/.next/static/chunks/{UIToast.de15325248043ce5.js → UIToast.19a8664c01a00d3a.js} +1 -1
- package/.next/static/chunks/pages/{_app-84aaff8a9d4de60e.js → _app-35e8dda638ee2672.js} +1 -1
- package/.next/static/chunks/pages/pvt/account/403-ccddb4364ef27179.js +1 -0
- package/.next/static/chunks/{webpack-61b283a96fbb5ee2.js → webpack-65b1de5f075b8367.js} +1 -1
- package/.next/trace +143 -143
- package/.turbo/turbo-build.log +11 -11
- package/.turbo/turbo-test.log +11 -9
- package/CHANGELOG.md +13 -0
- package/package.json +7 -7
- package/src/components/cms/RenderSections.tsx +38 -3
- package/src/pages/api/graphql.ts +2 -2
- package/src/pages/pvt/account/403.tsx +9 -0
- package/src/sdk/account/useRefreshToken.ts +12 -0
- package/src/sdk/session/index.ts +3 -7
- package/src/utils/isLocalHost.ts +33 -0
- package/test/utils/isLocalHost.browser.test.ts +40 -0
- package/test/utils/isLocalHost.test.ts +38 -0
- package/.next/static/chunks/9173-e89da04079c35360.js +0 -2
- package/.next/static/chunks/pages/pvt/account/403-491e6b062487b30f.js +0 -1
- /package/.next/static/{WPYJvsqBdHs3zpay3w2iE → UmIFhJcdMOfy3xrHNNZS2}/_ssgManifest.js +0 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@3.99.
|
|
2
|
+
> @faststore/core@3.99.4 prebuild /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> na run partytown && na run generate
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @faststore/core@3.99.
|
|
6
|
+
> @faststore/core@3.99.4 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.99.
|
|
11
|
+
> @faststore/core@3.99.4 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.99.
|
|
15
|
+
> @faststore/core@3.99.4 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.99.
|
|
20
|
+
> @faststore/core@3.99.4 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.99.
|
|
40
|
+
> @faststore/core@3.99.4 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.99.
|
|
44
|
+
> @faststore/core@3.99.4 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
|
|
@@ -86,8 +86,8 @@ Search not found. Add a new component for this section or remove it from the CMS
|
|
|
86
86
|
|
|
87
87
|
Generating static pages (2/6)
|
|
88
88
|
Warning: Dynamic Content not found for the page: home. Refer to the Dynamic Content documentation at https://developers.vtex.com/docs/guides/faststore/dynamic-content-overview for mapping the page and the corresponding data-fetching function.
|
|
89
89
|
Search not found. Add a new component for this section or remove it from the CMS
|
|
90
|
-
|
|
91
90
|
Generating static pages (4/6)
|
|
92
91
|
Search not found. Add a new component for this section or remove it from the CMS
|
|
92
|
+
|
|
93
93
|
Generating static pages (4/6)
|
|
94
94
|
Search not found. Add a new component for this section or remove it from the CMS
|
|
95
95
|
|
|
96
96
|
✓ Generating static pages (6/6)
|
|
97
97
|
Finalizing page optimization ...
|
|
@@ -112,7 +112,7 @@ Route (pages) Size First Load JS
|
|
|
112
112
|
├ ● /login 1.7 kB 160 kB
|
|
113
113
|
├ λ /pvt/account 247 B 109 kB
|
|
114
114
|
├ ● /pvt/account/[...unknown] 287 B 109 kB
|
|
115
|
-
├ λ /pvt/account/403
|
|
115
|
+
├ λ /pvt/account/403 3 kB 161 kB
|
|
116
116
|
├ └ css/6819dddf2b1b5ea7.css 4.84 kB
|
|
117
117
|
├ λ /pvt/account/404 2.18 kB 160 kB
|
|
118
118
|
├ └ css/ea11d74a2848b093.css 4.89 kB
|
|
@@ -130,8 +130,8 @@ Route (pages) Size First Load JS
|
|
|
130
130
|
+ First Load JS shared by all 118 kB
|
|
131
131
|
├ chunks/framework-d514426edf885c68.js 45.4 kB
|
|
132
132
|
├ chunks/main-ec03882c4375091d.js 33.2 kB
|
|
133
|
-
├ chunks/pages/_app-
|
|
134
|
-
├ chunks/webpack-
|
|
133
|
+
├ chunks/pages/_app-35e8dda638ee2672.js 26.6 kB
|
|
134
|
+
├ chunks/webpack-65b1de5f075b8367.js 3.89 kB
|
|
135
135
|
└ css/146a8678babc61bf.css 9.2 kB
|
|
136
136
|
|
|
137
137
|
λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@3.99.
|
|
2
|
+
> @faststore/core@3.99.4 test /home/runner/work/faststore/faststore/packages/core
|
|
3
3
|
> jest
|
|
4
4
|
|
|
5
|
-
PASS test/utils/
|
|
6
|
-
PASS test/utils/
|
|
5
|
+
PASS test/utils/multipleTemplates.test.ts (11.618 s)
|
|
6
|
+
PASS test/utils/clearCookies.test.ts (12.194 s)
|
|
7
|
+
PASS test/utils/cookieCacheBusting.test.ts (13.633 s)
|
|
7
8
|
PASS test/server/cms/global.test.ts
|
|
8
9
|
PASS test/utils/validateSessionRefreshToken.test.ts
|
|
9
|
-
PASS test/utils/
|
|
10
|
-
PASS test/
|
|
11
|
-
PASS test/server/index.test.ts (
|
|
10
|
+
PASS test/utils/isLocalHost.test.ts
|
|
11
|
+
PASS test/utils/isLocalHost.browser.test.ts
|
|
12
|
+
PASS test/server/cms/index.test.ts (6.005 s)
|
|
13
|
+
PASS test/server/index.test.ts (13.099 s)
|
|
12
14
|
|
|
13
|
-
Test Suites:
|
|
14
|
-
Tests:
|
|
15
|
+
Test Suites: 9 passed, 9 total
|
|
16
|
+
Tests: 68 passed, 68 total
|
|
15
17
|
Snapshots: 0 total
|
|
16
|
-
Time:
|
|
18
|
+
Time: 25.905 s
|
|
17
19
|
Ran all test suites.
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
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.99.6](https://github.com/vtex/faststore/compare/v3.99.5...v3.99.6) (2026-05-19)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- bypass refresh-token flow on localhost in 403 page and useRefreshToken hook ([#3326](https://github.com/vtex/faststore/issues/3326)) ([5943129](https://github.com/vtex/faststore/commit/5943129ed4aa51823e90b7826a88a864f75ddd11)), closes [#3325](https://github.com/vtex/faststore/issues/3325) [#3325](https://github.com/vtex/faststore/issues/3325)
|
|
11
|
+
|
|
12
|
+
## 3.99.4 (2026-05-14)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
- region slider section render 3.x ([#3321](https://github.com/vtex/faststore/issues/3321)) ([8e9fa4f](https://github.com/vtex/faststore/commit/8e9fa4fae7d6c306e66164e3229d2f74b28982d3))
|
|
17
|
+
- use starter.store 3.x branch in CI ([#3324](https://github.com/vtex/faststore/issues/3324)) ([baaf13c](https://github.com/vtex/faststore/commit/baaf13cc791b7c54948f31fe2891ea3351706053)), closes [#3321](https://github.com/vtex/faststore/issues/3321) [#3321](https://github.com/vtex/faststore/issues/3321)
|
|
18
|
+
|
|
6
19
|
## [3.99.3](https://github.com/vtex/faststore/compare/v3.99.2...v3.99.3) (2026-05-12)
|
|
7
20
|
|
|
8
21
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "3.99.
|
|
3
|
+
"version": "3.99.6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -51,11 +51,11 @@
|
|
|
51
51
|
"@envelop/graphql-jit": "^8.0.3",
|
|
52
52
|
"@envelop/parser-cache": "^6.0.2",
|
|
53
53
|
"@envelop/validation-cache": "^6.0.2",
|
|
54
|
-
"@faststore/api": "3.99.
|
|
55
|
-
"@faststore/graphql-utils": "^3.99.
|
|
56
|
-
"@faststore/lighthouse": "3.99.
|
|
57
|
-
"@faststore/sdk": "3.99.
|
|
58
|
-
"@faststore/ui": "3.99.
|
|
54
|
+
"@faststore/api": "3.99.4",
|
|
55
|
+
"@faststore/graphql-utils": "^3.99.4",
|
|
56
|
+
"@faststore/lighthouse": "3.99.4",
|
|
57
|
+
"@faststore/sdk": "3.99.4",
|
|
58
|
+
"@faststore/ui": "3.99.4",
|
|
59
59
|
"@graphql-codegen/cli": "5.0.2",
|
|
60
60
|
"@graphql-codegen/client-preset": "4.2.6",
|
|
61
61
|
"@graphql-codegen/typescript": "4.0.7",
|
|
@@ -126,5 +126,5 @@
|
|
|
126
126
|
"ts-jest": "29.1.1",
|
|
127
127
|
"typescript": "5.3.2"
|
|
128
128
|
},
|
|
129
|
-
"gitHead": "
|
|
129
|
+
"gitHead": "5636f4f2af5ef09cc522c45364d85d445ca5c716"
|
|
130
130
|
}
|
|
@@ -23,7 +23,37 @@ interface Props {
|
|
|
23
23
|
isInteractive?: boolean
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const
|
|
26
|
+
const REGION_SLIDER_SECTION_NAME = 'RegionSlider'
|
|
27
|
+
|
|
28
|
+
const SECTIONS_OUT_OF_VIEWPORT = [
|
|
29
|
+
'CartSidebar',
|
|
30
|
+
'RegionModal',
|
|
31
|
+
REGION_SLIDER_SECTION_NAME,
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Ensure a RegionSlider section exists in the iteration. After PR #2961 the
|
|
36
|
+
* section was removed from `sections.json`, so CP-based stores (whose CP
|
|
37
|
+
* schemas were generated in PR #3071) and fresh hCMS stores no longer have it
|
|
38
|
+
* in their CMS content. The runtime still expects the section to flow through
|
|
39
|
+
* `RenderSections` so that `LazyLoadingSection` can gate the lazy import on
|
|
40
|
+
* `regionSlider.isOpen`. Inject the entry only if it is not already present in
|
|
41
|
+
* `sections` or `globalSections` to avoid double-rendering for legacy hCMS
|
|
42
|
+
* stores that have it persisted in their CMS.
|
|
43
|
+
*/
|
|
44
|
+
function withRegionSliderSection(
|
|
45
|
+
sections: Section[] | undefined,
|
|
46
|
+
globalSections: Section[] | undefined
|
|
47
|
+
): Section[] {
|
|
48
|
+
const base = sections ?? []
|
|
49
|
+
const isPresent =
|
|
50
|
+
base.some(({ name }) => name === REGION_SLIDER_SECTION_NAME) ||
|
|
51
|
+
globalSections?.some(({ name }) => name === REGION_SLIDER_SECTION_NAME)
|
|
52
|
+
|
|
53
|
+
if (isPresent) return base
|
|
54
|
+
|
|
55
|
+
return [...base, { name: REGION_SLIDER_SECTION_NAME, data: {} }]
|
|
56
|
+
}
|
|
27
57
|
|
|
28
58
|
const Toast = dynamic(
|
|
29
59
|
() => import(/* webpackChunkName: "Toast" */ '../common/Toast'),
|
|
@@ -148,6 +178,11 @@ function RenderSections({
|
|
|
148
178
|
globalSections ?? sections
|
|
149
179
|
)
|
|
150
180
|
|
|
181
|
+
const augmentedSections = useMemo(
|
|
182
|
+
() => withRegionSliderSection(sections, globalSections),
|
|
183
|
+
[sections, globalSections]
|
|
184
|
+
)
|
|
185
|
+
|
|
151
186
|
const { isInteractive } = useTTI()
|
|
152
187
|
const router = useRouter()
|
|
153
188
|
|
|
@@ -170,9 +205,9 @@ function RenderSections({
|
|
|
170
205
|
isInteractive={isInteractive}
|
|
171
206
|
/>
|
|
172
207
|
)}
|
|
173
|
-
{
|
|
208
|
+
{augmentedSections.length > 0 && (
|
|
174
209
|
<RenderSectionsBase
|
|
175
|
-
sections={
|
|
210
|
+
sections={augmentedSections}
|
|
176
211
|
components={components}
|
|
177
212
|
isInteractive={isInteractive}
|
|
178
213
|
/>
|
package/src/pages/api/graphql.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { NextApiHandler, NextApiRequest } from 'next'
|
|
|
9
9
|
|
|
10
10
|
import discoveryConfig from 'discovery.config'
|
|
11
11
|
import { getJWTAutCookie } from 'src/utils/getCookie'
|
|
12
|
+
import { isLocalHost } from 'src/utils/isLocalHost'
|
|
12
13
|
import { shouldForceRefreshTokenForValidateSession } from 'src/utils/validateSessionRefreshToken'
|
|
13
14
|
import { execute } from '../../server'
|
|
14
15
|
|
|
@@ -161,8 +162,7 @@ const handler: NextApiHandler = async (request, response) => {
|
|
|
161
162
|
// value is used to cache bust the request if there is a VtexIdclientAutCookie
|
|
162
163
|
const { operation, variables, query, v: value } = parseRequest(request)
|
|
163
164
|
|
|
164
|
-
const
|
|
165
|
-
const isLocal = hostname === 'localhost' || hostname === '127.0.0.1'
|
|
165
|
+
const isLocal = isLocalHost(request.headers.host?.split(':')[0])
|
|
166
166
|
|
|
167
167
|
if (
|
|
168
168
|
!isLocal &&
|
|
@@ -23,6 +23,7 @@ import { useRefreshToken } from 'src/sdk/account/useRefreshToken'
|
|
|
23
23
|
import PageProvider from 'src/sdk/overrides/PageProvider'
|
|
24
24
|
import { execute } from 'src/server'
|
|
25
25
|
import { injectGlobalSections } from 'src/server/cms/global'
|
|
26
|
+
import { isLocalHost } from 'src/utils/isLocalHost'
|
|
26
27
|
import { getMyAccountRedirect } from 'src/utils/myAccountRedirect'
|
|
27
28
|
|
|
28
29
|
import storeConfig from 'discovery.config'
|
|
@@ -132,10 +133,18 @@ export const getServerSideProps: GetServerSideProps<
|
|
|
132
133
|
const fromPage =
|
|
133
134
|
typeof context.query.from === 'string' ? context.query.from : ''
|
|
134
135
|
|
|
136
|
+
// The refresh-token round-trip is unreachable from localhost (cross-origin
|
|
137
|
+
// POST that drops the `vid_rt` cookie), and forcing it would clear the
|
|
138
|
+
// manually injected `VtexIdclientAutCookie_<account>`. Render the static
|
|
139
|
+
// 403 view instead so developers can keep testing logged-in scenarios
|
|
140
|
+
// regardless of the `experimental.refreshToken` flag.
|
|
141
|
+
const isLocal = isLocalHost(context.req.headers.host?.split(':')[0])
|
|
142
|
+
|
|
135
143
|
return {
|
|
136
144
|
props: {
|
|
137
145
|
globalSections: globalSectionsResult,
|
|
138
146
|
needsRefreshToken:
|
|
147
|
+
!isLocal &&
|
|
139
148
|
(statusCode === 401 || statusCode === 403) &&
|
|
140
149
|
storeConfig.experimental?.refreshToken,
|
|
141
150
|
fromPage,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react'
|
|
2
|
+
import { isLocalHostBrowser } from 'src/utils/isLocalHost'
|
|
2
3
|
import { logoutAndClearSession, sessionStore } from '../session'
|
|
3
4
|
import { isRefreshTokenSuccessful, refreshTokenRequest } from './refreshToken'
|
|
4
5
|
|
|
@@ -12,6 +13,17 @@ export const useRefreshToken = (
|
|
|
12
13
|
const handleRefreshTokenAndUpdateSession = async () => {
|
|
13
14
|
if (!needsRefreshToken) return
|
|
14
15
|
|
|
16
|
+
// The refresh-token endpoint lives on the production origin and relies on
|
|
17
|
+
// the `vid_rt` cookie scoped to that origin. From localhost the request is
|
|
18
|
+
// cross-origin, so the cookie is not sent and the refresh always fails —
|
|
19
|
+
// which would also wipe the manually injected `VtexIdclientAutCookie_<account>`
|
|
20
|
+
// via `logoutAndClearSession`. Bail out and fall back to the static 403
|
|
21
|
+
// view so developers can keep testing logged-in flows.
|
|
22
|
+
if (isLocalHostBrowser()) {
|
|
23
|
+
setShouldShow403(true)
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
15
27
|
const currentSession = sessionStore.read() ?? sessionStore.readInitial()
|
|
16
28
|
|
|
17
29
|
try {
|
package/src/sdk/session/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
ValidateSessionMutationVariables,
|
|
9
9
|
} from '@generated/graphql'
|
|
10
10
|
import deepEqual from 'fast-deep-equal'
|
|
11
|
+
import { isLocalHostBrowser } from 'src/utils/isLocalHost'
|
|
11
12
|
import storeConfig from '../../../discovery.config'
|
|
12
13
|
import {
|
|
13
14
|
isRefreshTokenSuccessful,
|
|
@@ -19,11 +20,6 @@ import { createValidationStore, useStore } from '../useStore'
|
|
|
19
20
|
import { getPostalCode } from '../userLocation/index'
|
|
20
21
|
import { RELOAD_AFTER_LOGOUT_KEY, SESSION_READY_KEY } from './storageKeys'
|
|
21
22
|
|
|
22
|
-
const isLocalEnvironment = (): boolean =>
|
|
23
|
-
typeof window !== 'undefined' &&
|
|
24
|
-
(window.location.hostname === 'localhost' ||
|
|
25
|
-
window.location.hostname === '127.0.0.1')
|
|
26
|
-
|
|
27
23
|
const isReloadAfterLogoutPending = (): boolean => {
|
|
28
24
|
try {
|
|
29
25
|
return (
|
|
@@ -127,7 +123,7 @@ export const validateSession = async (session: Session) => {
|
|
|
127
123
|
// On failure (logoutAndClearSession already triggered), bail out.
|
|
128
124
|
// Skipped in local environments where the refresh token infrastructure is unavailable.
|
|
129
125
|
if (
|
|
130
|
-
!
|
|
126
|
+
!isLocalHostBrowser() &&
|
|
131
127
|
storeConfig.experimental?.refreshToken &&
|
|
132
128
|
isRefreshAfterExpired(session)
|
|
133
129
|
) {
|
|
@@ -180,7 +176,7 @@ export const validateSession = async (session: Session) => {
|
|
|
180
176
|
return data.validateSession
|
|
181
177
|
} catch (error) {
|
|
182
178
|
const shouldRefreshToken =
|
|
183
|
-
!
|
|
179
|
+
!isLocalHostBrowser() &&
|
|
184
180
|
error?.status === 401 &&
|
|
185
181
|
storeConfig.experimental?.refreshToken
|
|
186
182
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hostnames that represent a local development environment.
|
|
3
|
+
*
|
|
4
|
+
* These are the only hosts where the FastStore app skips the refresh-token
|
|
5
|
+
* flow so developers can drive the app with a manually injected
|
|
6
|
+
* `VtexIdclientAutCookie_<account>` cookie regardless of feature flags.
|
|
7
|
+
*/
|
|
8
|
+
const LOCAL_HOSTNAMES = new Set(['localhost', '127.0.0.1'])
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Returns `true` when the given hostname corresponds to a local development
|
|
12
|
+
* environment (`localhost` / `127.0.0.1`).
|
|
13
|
+
*
|
|
14
|
+
* Refresh-token and other production-only flows MUST be bypassed on these
|
|
15
|
+
* hostnames so that developers can test logged-in scenarios with manually
|
|
16
|
+
* injected cookies, independent of any experimental flag.
|
|
17
|
+
*
|
|
18
|
+
* The input MUST be a bare hostname (no port). Callers should strip the port
|
|
19
|
+
* (e.g. `host.split(':')[0]`) before invoking this helper.
|
|
20
|
+
*/
|
|
21
|
+
export function isLocalHost(hostname: string | null | undefined): boolean {
|
|
22
|
+
if (!hostname) return false
|
|
23
|
+
return LOCAL_HOSTNAMES.has(hostname.toLowerCase())
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Browser-side wrapper that reads `window.location.hostname`. Returns `false`
|
|
28
|
+
* when `window` is not available (SSR/Node).
|
|
29
|
+
*/
|
|
30
|
+
export function isLocalHostBrowser(): boolean {
|
|
31
|
+
if (typeof window === 'undefined') return false
|
|
32
|
+
return isLocalHost(window.location.hostname)
|
|
33
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment jsdom
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { isLocalHostBrowser } from '../../src/utils/isLocalHost'
|
|
6
|
+
|
|
7
|
+
const originalLocation = window.location
|
|
8
|
+
|
|
9
|
+
function stubHostname(hostname: string) {
|
|
10
|
+
// jsdom forbids assigning to `window.location` directly, so we redefine the
|
|
11
|
+
// descriptor with a minimal stub that exposes the hostname we want to test.
|
|
12
|
+
Object.defineProperty(window, 'location', {
|
|
13
|
+
configurable: true,
|
|
14
|
+
value: { ...originalLocation, hostname },
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe('isLocalHostBrowser', () => {
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
Object.defineProperty(window, 'location', {
|
|
21
|
+
configurable: true,
|
|
22
|
+
value: originalLocation,
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('returns true when window.location.hostname is "localhost"', () => {
|
|
27
|
+
stubHostname('localhost')
|
|
28
|
+
expect(isLocalHostBrowser()).toBe(true)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('returns true when window.location.hostname is "127.0.0.1"', () => {
|
|
32
|
+
stubHostname('127.0.0.1')
|
|
33
|
+
expect(isLocalHostBrowser()).toBe(true)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('returns false for a production hostname', () => {
|
|
37
|
+
stubHostname('brandless.fast.store')
|
|
38
|
+
expect(isLocalHostBrowser()).toBe(false)
|
|
39
|
+
})
|
|
40
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { isLocalHost } from '../../src/utils/isLocalHost'
|
|
2
|
+
|
|
3
|
+
describe('isLocalHost', () => {
|
|
4
|
+
it('returns true for "localhost"', () => {
|
|
5
|
+
expect(isLocalHost('localhost')).toBe(true)
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
it('returns true for "127.0.0.1"', () => {
|
|
9
|
+
expect(isLocalHost('127.0.0.1')).toBe(true)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('is case-insensitive', () => {
|
|
13
|
+
expect(isLocalHost('LOCALHOST')).toBe(true)
|
|
14
|
+
expect(isLocalHost('Localhost')).toBe(true)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('returns false for a production hostname', () => {
|
|
18
|
+
expect(isLocalHost('brandless.fast.store')).toBe(false)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('returns false for IPv6 loopback (not in the bypass list)', () => {
|
|
22
|
+
// We intentionally bypass only the two canonical local hosts. IPv6
|
|
23
|
+
// loopback (`::1`) and other loopback variants are out of scope.
|
|
24
|
+
expect(isLocalHost('::1')).toBe(false)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('returns false for inputs that still carry a port', () => {
|
|
28
|
+
// Callers MUST normalize the hostname (strip the port) before invoking
|
|
29
|
+
// this helper.
|
|
30
|
+
expect(isLocalHost('localhost:3000')).toBe(false)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('returns false for null/undefined/empty input', () => {
|
|
34
|
+
expect(isLocalHost(null)).toBe(false)
|
|
35
|
+
expect(isLocalHost(undefined)).toBe(false)
|
|
36
|
+
expect(isLocalHost('')).toBe(false)
|
|
37
|
+
})
|
|
38
|
+
})
|