@faststore/core 3.60.4 → 3.61.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 +40 -40
- 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 +37 -30
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/948.js +2 -2
- 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/api/preview.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-manifest.json +1 -1
- package/.next/static/{GpoK55xkQiF2khQfod1ac → -iM74ScvesldH1477MJQu}/_buildManifest.js +1 -1
- package/.next/static/chunks/{3166-1fd17b322ca991eb.js → 3166-50d81179a0f5a894.js} +1 -1
- package/.next/static/chunks/3465.af28497e8069330f.js +1 -0
- package/.next/static/chunks/4949.58cc42cd6109f59a.js +6 -0
- package/.next/static/chunks/6355.f1b1feefc0c84a2a.js +1 -0
- package/.next/static/chunks/{83.c68f386e6783ec51.js → 83.b87d797323ff2034.js} +1 -1
- package/.next/static/chunks/9173-94386b70c1626a31.js +1 -0
- package/.next/static/chunks/{BannerNewsletter.7f2d79c25b0e2546.js → BannerNewsletter.7c592f132e7048e5.js} +1 -1
- package/.next/static/chunks/{BannerText.50b22511f61fe02a.js → BannerText.695d4d4b6a3f7309.js} +1 -1
- package/.next/static/chunks/{CartSidebar.4822eeeb560ccb43.js → CartSidebar.a00083c44c87c268.js} +1 -1
- package/.next/static/chunks/PreviewTag.0b16a5b6ac35ce1c.js +1 -0
- package/.next/static/chunks/{ProductShelf.ffceb1cb3d66e171.js → ProductShelf.d51ba3e6a1b4a57d.js} +1 -1
- package/.next/static/chunks/{RegionModal.21284dd0660b4e6d.js → RegionModal.f61aa62e0a09182a.js} +1 -1
- package/.next/static/chunks/{Toast.4ff856492d402ad9.js → Toast.6116bc845cd67f49.js} +1 -1
- package/.next/static/chunks/pages/{[...slug]-34d0d47df01bbdc6.js → [...slug]-72047653203f9fd2.js} +1 -1
- package/.next/static/chunks/webpack-c76f1cac87402029.js +1 -0
- package/.next/static/css/2841bab51b99dd53.css +1 -0
- package/.next/static/css/74e963fcd3434141.css +1 -0
- package/.next/trace +129 -128
- package/.turbo/turbo-build.log +13 -13
- package/.turbo/turbo-test.log +5 -5
- package/CHANGELOG.md +6 -0
- package/package.json +3 -3
- package/src/components/cms/RenderSections.tsx +18 -0
- package/src/components/common/PreviewTag/PreviewTag.tsx +49 -0
- package/src/components/common/PreviewTag/index.ts +2 -0
- package/src/components/common/PreviewTag/section.module.scss +16 -0
- package/src/pages/[...slug].tsx +1 -1
- package/src/pages/api/preview.ts +22 -6
- package/src/server/content/service.ts +100 -61
- package/src/server/content/types.ts +1 -1
- package/src/server/content/utils.ts +10 -1
- package/.next/static/chunks/630.400b772c0b28fb0b.js +0 -6
- package/.next/static/chunks/6355.3b698d9dabef2570.js +0 -1
- package/.next/static/chunks/6867.d82d45995c75aa12.js +0 -1
- package/.next/static/chunks/9173-737c162805bb7193.js +0 -1
- package/.next/static/chunks/webpack-97e23458f9fce352.js +0 -1
- package/.next/static/css/5b9680256f4d8968.css +0 -1
- /package/.next/static/{GpoK55xkQiF2khQfod1ac → -iM74ScvesldH1477MJQu}/_ssgManifest.js +0 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @faststore/core@3.60.
|
|
2
|
+
> @faststore/core@3.60.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.60.
|
|
6
|
+
> @faststore/core@3.60.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.60.
|
|
11
|
+
> @faststore/core@3.60.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.60.
|
|
15
|
+
> @faststore/core@3.60.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.60.
|
|
20
|
+
> @faststore/core@3.60.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.60.
|
|
40
|
+
> @faststore/core@3.60.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.60.
|
|
44
|
+
> @faststore/core@3.60.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
|
|
@@ -62,8 +62,8 @@ Browserslist: browsers data (caniuse-lite) is 6 months old. Please run:
|
|
|
62
62
|
Collecting page data ...
|
|
63
63
|
Generating static pages (0/6) ...
|
|
64
64
|
|
|
65
65
|
Generating static pages (1/6)
|
|
66
|
-
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.
|
|
67
66
|
|
|
68
67
|
Generating static pages (2/6)
|
|
68
|
+
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.
|
|
69
69
|
|
|
70
70
|
Generating static pages (4/6)
|
|
71
71
|
|
|
72
72
|
✓ Generating static pages (6/6)
|
|
73
73
|
Finalizing page optimization ...
|
|
@@ -73,7 +73,7 @@ Route (pages) Size First Load JS
|
|
|
73
73
|
┌ ● / 3.87 kB 133 kB
|
|
74
74
|
├ └ css/b1806cbafd0c1f81.css 3.06 kB
|
|
75
75
|
├ /_app 0 B 100 kB
|
|
76
|
-
├ ● /[...slug] 2.
|
|
76
|
+
├ ● /[...slug] 2.37 kB 141 kB
|
|
77
77
|
├ ● /[slug]/p 32.4 kB 162 kB
|
|
78
78
|
├ ├ css/a3ca6a9b63f657be.css 5.75 kB
|
|
79
79
|
├ ├ css/62a5153ac7061286.css 6.11 kB
|
|
@@ -81,14 +81,14 @@ Route (pages) Size First Load JS
|
|
|
81
81
|
├ ○ /404 1.48 kB 131 kB
|
|
82
82
|
├ ● /500 1.48 kB 131 kB
|
|
83
83
|
├ λ /account 240 B 100 kB
|
|
84
|
-
├ ● /account/[...unknown] 281 B
|
|
84
|
+
├ ● /account/[...unknown] 281 B 101 kB
|
|
85
85
|
├ λ /account/403 2.33 kB 132 kB
|
|
86
86
|
├ └ css/b7bba8fce075688b.css 4.2 kB
|
|
87
|
-
├ λ /account/404 2.03 kB
|
|
87
|
+
├ λ /account/404 2.03 kB 132 kB
|
|
88
88
|
├ └ css/5347dbc8b71de47d.css 4.25 kB
|
|
89
89
|
├ λ /account/orders 8.57 kB 138 kB
|
|
90
90
|
├ └ css/8a3f440e0ff9cd8e.css 11.9 kB
|
|
91
|
-
├ λ /account/orders/[id] 10 kB
|
|
91
|
+
├ λ /account/orders/[id] 10 kB 140 kB
|
|
92
92
|
├ └ css/506442c818624bd2.css 11.5 kB
|
|
93
93
|
├ λ /account/profile 1.27 kB 131 kB
|
|
94
94
|
├ λ /account/security 1.27 kB 131 kB
|
|
@@ -104,7 +104,7 @@ Route (pages) Size First Load JS
|
|
|
104
104
|
├ chunks/framework-807b0f81cbc129f0.js 45.4 kB
|
|
105
105
|
├ chunks/main-f658704b53a96ab1.js 33.1 kB
|
|
106
106
|
├ chunks/pages/_app-52aa8f30f7707675.js 18.1 kB
|
|
107
|
-
├ chunks/webpack-
|
|
107
|
+
├ chunks/webpack-c76f1cac87402029.js 3.73 kB
|
|
108
108
|
└ css/0a57ee6c7a57788c.css 3.49 kB
|
|
109
109
|
|
|
110
110
|
λ (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.60.
|
|
2
|
+
> @faststore/core@3.60.4 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 (25.727 s)
|
|
6
|
+
PASS test/server/cms/global.test.ts (26.444 s)
|
|
7
7
|
PASS test/server/cms/index.test.ts
|
|
8
|
-
PASS test/server/index.test.ts (
|
|
8
|
+
PASS test/server/index.test.ts (31.174 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:
|
|
13
|
+
Time: 32.394 s
|
|
14
14
|
Ran all test suites.
|
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.61.0](https://github.com/vtex/faststore/compare/v3.60.4...v3.61.0) (2025-07-04)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- implement CP branch preview support ([#2885](https://github.com/vtex/faststore/issues/2885)) ([a55fe24](https://github.com/vtex/faststore/commit/a55fe24dac70ccfedc6296001bd5c18225affeda)), closes [/github.com/vtex/faststore/pull/2885/files#diff-63a7f8cba93bce2eb5ed6be3a1bcf1fbde76d643b165ae2a1a44cc8765dfb73fR40](https://github.com//github.com/vtex/faststore/pull/2885/files/issues/diff-63a7f8cba93bce2eb5ed6be3a1bcf1fbde76d643b165ae2a1a44cc8765dfb73fR40) [/github.com/vtex/faststore/pull/2885/files#diff-63a7f8cba93bce2eb5ed6be3a1bcf1fbde76d643b165ae2a1a44cc8765dfb73fR250](https://github.com//github.com/vtex/faststore/pull/2885/files/issues/diff-63a7f8cba93bce2eb5ed6be3a1bcf1fbde76d643b165ae2a1a44cc8765dfb73fR250) [/github.com/vtex/faststore/pull/2885/files#diff-8dd0ec358e808043c69af593825ff65e9afe1dd776dad04f15480a45b57a2608L36](https://github.com//github.com/vtex/faststore/pull/2885/files/issues/diff-8dd0ec358e808043c69af593825ff65e9afe1dd776dad04f15480a45b57a2608L36) [/github.com/vtex/faststore/pull/2885/files#diff-6728e613609d08999bccf3fc982a6a61c19d6d8eb08eb4d7adb66f4a6924843dR14](https://github.com//github.com/vtex/faststore/pull/2885/files/issues/diff-6728e613609d08999bccf3fc982a6a61c19d6d8eb08eb4d7adb66f4a6924843dR14) [/github.com/vtex/faststore/pull/2885/files#diff-7c7bcf90ece929b012c8fa7a7b62eac4ab72ca06aa5684add108af699bd62f50R38](https://github.com//github.com/vtex/faststore/pull/2885/files/issues/diff-7c7bcf90ece929b012c8fa7a7b62eac4ab72ca06aa5684add108af699bd62f50R38) [/github.com/vtex/faststore/pull/2885/files#diff-b45ed72491ecc419d59ca49fa8b4fc7a45deb55758a6a401f3c8401c11114227R148](https://github.com//github.com/vtex/faststore/pull/2885/files/issues/diff-b45ed72491ecc419d59ca49fa8b4fc7a45deb55758a6a401f3c8401c11114227R148) [/github.com/vtex/faststore/pull/2885/files#diff-8dd0ec358e808043c69af593825ff65e9afe1dd776dad04f15480a45b57a2608R52](https://github.com//github.com/vtex/faststore/pull/2885/files/issues/diff-8dd0ec358e808043c69af593825ff65e9afe1dd776dad04f15480a45b57a2608R52) [/github.com/vtex/faststore/pull/2885/files#diff-6728e613609d08999bccf3fc982a6a61c19d6d8eb08eb4d7adb66f4a6924843dR22](https://github.com//github.com/vtex/faststore/pull/2885/files/issues/diff-6728e613609d08999bccf3fc982a6a61c19d6d8eb08eb4d7adb66f4a6924843dR22) [/github.com/vtex/faststore/blob/main/packages/core/discovery.config.default.js#L128](https://github.com//github.com/vtex/faststore/blob/main/packages/core/discovery.config.default.js/issues/L128) [/github.com/vtex/faststore/blob/main/packages/core/discovery.config.default.js#L128](https://github.com//github.com/vtex/faststore/blob/main/packages/core/discovery.config.default.js/issues/L128)
|
|
11
|
+
|
|
6
12
|
## [3.60.4](https://github.com/vtex/faststore/compare/v3.60.3...v3.60.4) (2025-07-04)
|
|
7
13
|
|
|
8
14
|
**Note:** Version bump only for package @faststore/core
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.61.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": "vtex/faststore",
|
|
6
6
|
"browserslist": "supports es6-module and not dead",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@parcel/watcher": "^2.4.0",
|
|
62
62
|
"@types/react": "^18.2.42",
|
|
63
63
|
"@vtex/client-cms": "^0.2.12",
|
|
64
|
-
"@vtex/client-cp": "0.
|
|
64
|
+
"@vtex/client-cp": "0.3.0",
|
|
65
65
|
"@vtex/prettier-config": "1.0.0",
|
|
66
66
|
"autoprefixer": "^10.4.0",
|
|
67
67
|
"css-loader": "^6.7.1",
|
|
@@ -105,5 +105,5 @@
|
|
|
105
105
|
"ts-jest": "29.1.1",
|
|
106
106
|
"typescript": "5.3.2"
|
|
107
107
|
},
|
|
108
|
-
"gitHead": "
|
|
108
|
+
"gitHead": "2ba46c81202a84ae4a13e61e7a453c034df6b187"
|
|
109
109
|
}
|
|
@@ -9,7 +9,9 @@ import {
|
|
|
9
9
|
import { useUI } from '@faststore/ui'
|
|
10
10
|
import type { Section } from '@vtex/client-cms'
|
|
11
11
|
import dynamic from 'next/dynamic'
|
|
12
|
+
import { useRouter } from 'next/router'
|
|
12
13
|
import useTTI from 'src/sdk/performance/useTTI'
|
|
14
|
+
import { isContentPlatformSource } from 'src/server/content/utils'
|
|
13
15
|
import SectionBoundary from './SectionBoundary'
|
|
14
16
|
import ViewportObserver from './ViewportObserver'
|
|
15
17
|
import COMPONENTS from './global/Components'
|
|
@@ -28,6 +30,11 @@ const Toast = dynamic(
|
|
|
28
30
|
{ ssr: false }
|
|
29
31
|
)
|
|
30
32
|
|
|
33
|
+
const PreviewTag = dynamic(
|
|
34
|
+
() => import(/* webpackChunkName: "PreviewTag" */ '../common/PreviewTag'),
|
|
35
|
+
{ ssr: false }
|
|
36
|
+
)
|
|
37
|
+
|
|
31
38
|
const useDividedSections = (sections: Section[]) => {
|
|
32
39
|
return useMemo(() => {
|
|
33
40
|
const indexChildren = sections.findIndex(({ name }) => name === 'Children')
|
|
@@ -137,9 +144,20 @@ function RenderSections({
|
|
|
137
144
|
)
|
|
138
145
|
|
|
139
146
|
const { isInteractive } = useTTI()
|
|
147
|
+
const router = useRouter()
|
|
148
|
+
|
|
149
|
+
const shouldDisplayPreviewTag = isContentPlatformSource() && router.isPreview
|
|
140
150
|
|
|
141
151
|
return (
|
|
142
152
|
<>
|
|
153
|
+
{shouldDisplayPreviewTag && (
|
|
154
|
+
<LazyLoadingSection
|
|
155
|
+
sectionName="PreviewTag"
|
|
156
|
+
isInteractive={isInteractive}
|
|
157
|
+
>
|
|
158
|
+
<PreviewTag />
|
|
159
|
+
</LazyLoadingSection>
|
|
160
|
+
)}
|
|
143
161
|
{firstSections && (
|
|
144
162
|
<RenderSectionsBase
|
|
145
163
|
sections={firstSections}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import { Tag as UITag } from '@faststore/ui'
|
|
3
|
+
import Section from 'src/components/sections/Section/Section'
|
|
4
|
+
|
|
5
|
+
import styles from './section.module.scss'
|
|
6
|
+
|
|
7
|
+
export interface PreviewTagProps {
|
|
8
|
+
text?: string
|
|
9
|
+
exitUrl?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function PreviewTag({ text = 'Preview', exitUrl }: PreviewTagProps) {
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const handleBeforeUnload = () => {
|
|
15
|
+
navigator.sendBeacon('/api/preview?action=clear')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
window.addEventListener('beforeunload', handleBeforeUnload)
|
|
19
|
+
|
|
20
|
+
return () => {
|
|
21
|
+
window.removeEventListener('beforeunload', handleBeforeUnload)
|
|
22
|
+
}
|
|
23
|
+
}, [])
|
|
24
|
+
|
|
25
|
+
const handleExitPreview = () => {
|
|
26
|
+
if (typeof window !== 'undefined') {
|
|
27
|
+
const exitPath =
|
|
28
|
+
exitUrl || window.location.pathname + window.location.search
|
|
29
|
+
window.location.href = `/api/preview?action=clear&redirect=${encodeURIComponent(
|
|
30
|
+
exitPath
|
|
31
|
+
)}`
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Section className={`${styles.section} section-preview-tag`}>
|
|
37
|
+
<UITag
|
|
38
|
+
data-fs-preview-tag
|
|
39
|
+
testId="fs-preview-tag"
|
|
40
|
+
variant="danger"
|
|
41
|
+
label={text}
|
|
42
|
+
iconButtonLabel="Exit preview"
|
|
43
|
+
onClose={handleExitPreview}
|
|
44
|
+
/>
|
|
45
|
+
</Section>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default PreviewTag
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.section {
|
|
3
|
+
@import "@faststore/ui/src/components/atoms/Badge/styles.scss";
|
|
4
|
+
@import "@faststore/ui/src/components/atoms/Icon/styles.scss";
|
|
5
|
+
@import "@faststore/ui/src/components/molecules/Tag/styles.scss";
|
|
6
|
+
|
|
7
|
+
[data-fs-preview-tag] {
|
|
8
|
+
box-shadow: var(--fs-shadow-darker);
|
|
9
|
+
backdrop-filter: blur(var(--fs-spacing-1));
|
|
10
|
+
position: fixed;
|
|
11
|
+
top: 1rem;
|
|
12
|
+
right: 1rem;
|
|
13
|
+
z-index: 10000;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
package/src/pages/[...slug].tsx
CHANGED
package/src/pages/api/preview.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import type { NextApiHandler, NextApiRequest } from 'next'
|
|
1
|
+
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
|
|
2
2
|
|
|
3
3
|
import { previewRedirects } from '../../../discovery.config'
|
|
4
4
|
import { contentService } from 'src/server/content/service'
|
|
5
5
|
import { isLocator } from 'src/server/cms'
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
isBranchPreview,
|
|
8
|
+
isContentPlatformSource,
|
|
9
|
+
} from 'src/server/content/utils'
|
|
10
|
+
import type { PreviewData } from 'src/server/content/types'
|
|
7
11
|
|
|
8
12
|
type Settings = {
|
|
9
13
|
seo: {
|
|
@@ -27,20 +31,32 @@ const pickParam = (req: NextApiRequest, parameter: string) => {
|
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
const setPreviewAndRedirect = (
|
|
30
|
-
res:
|
|
34
|
+
res: NextApiResponse,
|
|
31
35
|
previewData: Record<string, string>,
|
|
32
36
|
redirectPath: string
|
|
33
37
|
) => {
|
|
34
|
-
|
|
38
|
+
const options: { maxAge: number; path?: string } = {
|
|
35
39
|
maxAge: 3600,
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!isBranchPreview(previewData as PreviewData)) {
|
|
43
|
+
options.path = redirectPath
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
res.setPreviewData(previewData, options)
|
|
38
47
|
res.redirect(redirectPath)
|
|
39
48
|
}
|
|
40
49
|
|
|
41
50
|
// TODO: Improve security by disabling CMS preview in production
|
|
42
51
|
const handler: NextApiHandler = async (req, res) => {
|
|
43
52
|
try {
|
|
53
|
+
if (pickParam(req, 'action') === 'clear') {
|
|
54
|
+
res.clearPreviewData()
|
|
55
|
+
const redirectTo = pickParam(req, 'redirect') || '/'
|
|
56
|
+
res.redirect(redirectTo)
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
44
60
|
let slug = pickParam(req, 'slug')
|
|
45
61
|
if (slug && !slug.startsWith('/')) {
|
|
46
62
|
slug = `/${slug}`
|
|
@@ -2,7 +2,7 @@ import type { ContentData, Locator } from '@vtex/client-cms'
|
|
|
2
2
|
import ClientCP from '@vtex/client-cp'
|
|
3
3
|
import type { ContentEntry, EntryPathParams } from '@vtex/client-cp'
|
|
4
4
|
import { getCMSPage, getPage, type PageContentType } from 'src/server/cms'
|
|
5
|
-
import type { ContentOptions, ContentParams } from './types'
|
|
5
|
+
import type { ContentOptions, ContentParams, PreviewData } from './types'
|
|
6
6
|
import config from '../../../discovery.config'
|
|
7
7
|
import { getPLP, type PLPContentType } from '../cms/plp'
|
|
8
8
|
import {
|
|
@@ -15,7 +15,9 @@ import MissingContentError from 'src/sdk/error/MissingContentError'
|
|
|
15
15
|
import { getPDP, type PDPContentType } from '../cms/pdp'
|
|
16
16
|
import MultipleContentError from 'src/sdk/error/MultipleContentError'
|
|
17
17
|
import type { ServerProductQueryQuery } from '@generated/graphql'
|
|
18
|
-
import { isContentPlatformSource } from './utils'
|
|
18
|
+
import { isBranchPreview, isContentPlatformSource } from './utils'
|
|
19
|
+
|
|
20
|
+
type ContentResult = ContentData | (ContentEntry & PageContentType)
|
|
19
21
|
|
|
20
22
|
export class ContentService {
|
|
21
23
|
private clientCP: ClientCP
|
|
@@ -37,22 +39,15 @@ export class ContentService {
|
|
|
37
39
|
return getPage(options.cmsOptions)
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
async
|
|
42
|
+
async getMultipleContent(
|
|
43
|
+
params: ContentParams
|
|
44
|
+
): Promise<{ data: ContentResult[] }> {
|
|
41
45
|
const options = this.createContentOptions(params)
|
|
42
46
|
|
|
43
47
|
if (isContentPlatformSource()) {
|
|
44
48
|
const serviceParams = this.convertOptionsToParams(options)
|
|
45
49
|
const { entries } = await this.clientCP.listEntries(serviceParams)
|
|
46
|
-
|
|
47
|
-
entries.map(async (entry) => {
|
|
48
|
-
const entryData = await this.getSingleEntry(
|
|
49
|
-
{ ...serviceParams, entryId: entry.id },
|
|
50
|
-
!!options.isPreview
|
|
51
|
-
)
|
|
52
|
-
return this.mergeEntryWithData(entry, entryData)
|
|
53
|
-
})
|
|
54
|
-
)
|
|
55
|
-
return { data }
|
|
50
|
+
return this.fillEntriesWithData(entries, serviceParams, options.isPreview)
|
|
56
51
|
}
|
|
57
52
|
return getCMSPage(options.cmsOptions)
|
|
58
53
|
}
|
|
@@ -65,10 +60,10 @@ export class ContentService {
|
|
|
65
60
|
const options = this.createContentOptions(plpParams)
|
|
66
61
|
|
|
67
62
|
if (isContentPlatformSource()) {
|
|
68
|
-
const pages = (await this.
|
|
63
|
+
const pages = (await this.getMultipleContent(plpParams)).data
|
|
69
64
|
if (!pages?.length) throw new MissingContentError(options.cmsOptions)
|
|
70
65
|
return findBestPLPTemplate(
|
|
71
|
-
pages,
|
|
66
|
+
pages as Partial<PLPContentType>[],
|
|
72
67
|
options.slug,
|
|
73
68
|
rewrites
|
|
74
69
|
) as PLPContentType
|
|
@@ -84,9 +79,12 @@ export class ContentService {
|
|
|
84
79
|
const options = this.createContentOptions(pdpParams)
|
|
85
80
|
|
|
86
81
|
if (isContentPlatformSource()) {
|
|
87
|
-
const pages = (await this.
|
|
82
|
+
const pages = (await this.getMultipleContent(pdpParams)).data
|
|
88
83
|
if (!pages.length) throw new MissingContentError(options.cmsOptions)
|
|
89
|
-
return findBestPDPTemplate(
|
|
84
|
+
return findBestPDPTemplate(
|
|
85
|
+
pages as Partial<PDPContentType>[],
|
|
86
|
+
product
|
|
87
|
+
) as PDPContentType
|
|
90
88
|
}
|
|
91
89
|
return getPDP(product, options.cmsOptions as Locator)
|
|
92
90
|
}
|
|
@@ -96,64 +94,92 @@ export class ContentService {
|
|
|
96
94
|
): Promise<T> {
|
|
97
95
|
const params = this.convertOptionsToParams(options)
|
|
98
96
|
try {
|
|
99
|
-
const entry: PageContentType =
|
|
100
|
-
params
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
const entry: PageContentType = await this.getEntry(
|
|
98
|
+
params,
|
|
99
|
+
options.isPreview
|
|
100
|
+
)
|
|
104
101
|
return entry as T
|
|
105
102
|
} catch (err: unknown) {
|
|
106
|
-
if (isNotFoundError(err)) console.
|
|
103
|
+
if (isNotFoundError(err)) console.warn('Content not found', err)
|
|
107
104
|
else throw err
|
|
108
105
|
}
|
|
109
106
|
}
|
|
110
107
|
|
|
111
|
-
private async
|
|
108
|
+
private async fillEntriesWithData(
|
|
109
|
+
entries: ContentEntry[],
|
|
110
|
+
serviceParams: EntryPathParams,
|
|
111
|
+
isPreview: boolean
|
|
112
|
+
): Promise<{ data: (ContentEntry & PageContentType)[] }> {
|
|
113
|
+
const data = await Promise.all(
|
|
114
|
+
entries.map(async (entry) => {
|
|
115
|
+
const entryData = await this.getEntryData(
|
|
116
|
+
{ ...serviceParams, entryId: entry.id },
|
|
117
|
+
isPreview
|
|
118
|
+
)
|
|
119
|
+
return this.mergeEntryWithData(entry, entryData)
|
|
120
|
+
})
|
|
121
|
+
)
|
|
122
|
+
return { data }
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private async getEntry(
|
|
126
|
+
params: EntryPathParams,
|
|
127
|
+
isPreview: boolean
|
|
128
|
+
): Promise<PageContentType> {
|
|
129
|
+
return params.entryId || params.slug
|
|
130
|
+
? await this.getEntryData(params, isPreview)
|
|
131
|
+
: await this.fetchFirstEntryFromList(params, isPreview)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private async getEntryData(
|
|
112
135
|
params: EntryPathParams,
|
|
113
136
|
isPreview: boolean
|
|
114
137
|
): Promise<PageContentType> {
|
|
138
|
+
if (!params.entryId && !params.slug) {
|
|
139
|
+
const operation = isPreview ? 'Preview' : 'getEntry'
|
|
140
|
+
throw new Error(`${operation} requires entryId or slug`)
|
|
141
|
+
}
|
|
142
|
+
|
|
115
143
|
if (isPreview) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
throw new Error('Preview requires entryId or slug')
|
|
125
|
-
}
|
|
126
|
-
if (params.entryId)
|
|
127
|
-
return this.clientCP.getEntry(params) as Promise<PageContentType>
|
|
128
|
-
if (params.slug)
|
|
129
|
-
return this.clientCP.getEntryBySlug(params) as Promise<PageContentType>
|
|
130
|
-
throw new Error('getEntry requires entryId or slug')
|
|
144
|
+
return params.entryId
|
|
145
|
+
? (this.clientCP.previewEntryById(params) as Promise<PageContentType>)
|
|
146
|
+
: (this.clientCP.previewEntryBySlug(params) as Promise<PageContentType>)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return params.entryId
|
|
150
|
+
? (this.clientCP.getEntry(params) as Promise<PageContentType>)
|
|
151
|
+
: (this.clientCP.getEntryBySlug(params) as Promise<PageContentType>)
|
|
131
152
|
}
|
|
132
153
|
|
|
133
|
-
private async
|
|
154
|
+
private async fetchFirstEntryFromList(
|
|
134
155
|
params: EntryPathParams,
|
|
135
156
|
isPreview: boolean
|
|
136
157
|
): Promise<PageContentType> {
|
|
137
158
|
const { entries } = await this.clientCP.listEntries(params)
|
|
138
159
|
if (!entries || entries.length === 0) {
|
|
139
|
-
console.
|
|
160
|
+
console.warn('No entries found for params', params)
|
|
140
161
|
return {} as PageContentType
|
|
141
162
|
}
|
|
142
163
|
if (entries.length > 1) {
|
|
143
164
|
throw new MultipleContentError(params)
|
|
144
165
|
}
|
|
145
|
-
return this.
|
|
166
|
+
return this.getEntryData({ ...params, entryId: entries[0].id }, isPreview)
|
|
146
167
|
}
|
|
147
168
|
|
|
148
|
-
private
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
169
|
+
private createContentOptions(params: ContentParams): ContentOptions {
|
|
170
|
+
const { contentType, previewData, slug } = params
|
|
171
|
+
|
|
172
|
+
const contentPreviewEnabled = previewData?.contentType === contentType
|
|
173
|
+
const branchPreviewEnabled = isBranchPreview(previewData)
|
|
174
|
+
|
|
152
175
|
return {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
176
|
+
cmsOptions: this.buildCmsOptions(
|
|
177
|
+
params,
|
|
178
|
+
contentPreviewEnabled,
|
|
179
|
+
branchPreviewEnabled
|
|
180
|
+
),
|
|
181
|
+
...(slug !== undefined && { slug }),
|
|
182
|
+
isPreview: contentPreviewEnabled || branchPreviewEnabled,
|
|
157
183
|
}
|
|
158
184
|
}
|
|
159
185
|
|
|
@@ -176,8 +202,10 @@ export class ContentService {
|
|
|
176
202
|
params.branchId = cmsOptions.releaseId
|
|
177
203
|
}
|
|
178
204
|
if ('filters' in cmsOptions && cmsOptions.filters) {
|
|
179
|
-
const nested =
|
|
180
|
-
|
|
205
|
+
const nested = (
|
|
206
|
+
cmsOptions.filters as { filters?: Record<string, unknown> }
|
|
207
|
+
).filters as Record<string, unknown>
|
|
208
|
+
if (nested && nested['settings.seo.slug']) {
|
|
181
209
|
const seo = nested['settings.seo.slug'] as string
|
|
182
210
|
params.slug = seo.replace(/^\//, '')
|
|
183
211
|
}
|
|
@@ -187,33 +215,44 @@ export class ContentService {
|
|
|
187
215
|
return params as EntryPathParams
|
|
188
216
|
}
|
|
189
217
|
|
|
190
|
-
private
|
|
218
|
+
private buildCmsOptions(
|
|
219
|
+
params: ContentParams,
|
|
220
|
+
isContentPreview: boolean,
|
|
221
|
+
isBranchPreview: boolean
|
|
222
|
+
) {
|
|
191
223
|
const {
|
|
192
224
|
contentType,
|
|
193
225
|
previewData,
|
|
194
|
-
slug,
|
|
195
226
|
documentId,
|
|
196
227
|
versionId,
|
|
197
228
|
releaseId,
|
|
198
229
|
filters,
|
|
199
230
|
} = params
|
|
200
|
-
|
|
201
|
-
const isPreview = previewData?.contentType === contentType
|
|
202
231
|
const { slug: _, ...previewLocator } = previewData || {}
|
|
203
232
|
|
|
204
|
-
|
|
233
|
+
return {
|
|
205
234
|
contentType,
|
|
206
|
-
...(
|
|
235
|
+
...(isContentPreview ? previewLocator : {}),
|
|
236
|
+
...(isBranchPreview && {
|
|
237
|
+
versionId: previewData?.versionId,
|
|
238
|
+
releaseId: previewData?.releaseId,
|
|
239
|
+
}),
|
|
207
240
|
...(documentId !== undefined && { documentId }),
|
|
208
241
|
...(versionId !== undefined && { versionId }),
|
|
209
242
|
...(releaseId !== undefined && { releaseId }),
|
|
210
243
|
...(filters && { filters }),
|
|
211
244
|
}
|
|
245
|
+
}
|
|
212
246
|
|
|
247
|
+
private mergeEntryWithData(
|
|
248
|
+
entry: ContentEntry,
|
|
249
|
+
data: PageContentType
|
|
250
|
+
): ContentEntry & PageContentType {
|
|
213
251
|
return {
|
|
214
|
-
|
|
215
|
-
...
|
|
216
|
-
|
|
252
|
+
...entry,
|
|
253
|
+
...data,
|
|
254
|
+
id: entry.id,
|
|
255
|
+
name: entry.name || '',
|
|
217
256
|
}
|
|
218
257
|
}
|
|
219
258
|
}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { contentSource } from '../../../discovery.config'
|
|
2
|
-
import { ContentSourceType } from './types'
|
|
2
|
+
import { ContentSourceType, type PreviewData } from './types'
|
|
3
3
|
|
|
4
4
|
export function isContentPlatformSource(): boolean {
|
|
5
5
|
return (
|
|
6
6
|
contentSource.type.toLocaleLowerCase() === ContentSourceType.ContentPlatform
|
|
7
7
|
)
|
|
8
8
|
}
|
|
9
|
+
|
|
10
|
+
export function isBranchPreview(
|
|
11
|
+
previewData: PreviewData | null | undefined
|
|
12
|
+
): boolean {
|
|
13
|
+
return (
|
|
14
|
+
isContentPlatformSource() &&
|
|
15
|
+
!!(previewData?.versionId || previewData?.releaseId)
|
|
16
|
+
)
|
|
17
|
+
}
|