@faststore/core 3.0.60 → 3.0.61

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.
Files changed (48) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +3 -3
  3. package/.next/build-manifest.json +21 -21
  4. package/.next/cache/.tsbuildinfo +1 -1
  5. package/.next/cache/config.json +3 -3
  6. package/.next/cache/eslint/.cache_1gneedd +1 -1
  7. package/.next/cache/fetch-cache/50912854cb7c781522a6ff8792d714e549515fcbbbfd660761961b06afe01c07 +1 -1
  8. package/.next/cache/webpack/client-production/0.pack +0 -0
  9. package/.next/cache/webpack/client-production/index.pack +0 -0
  10. package/.next/cache/webpack/server-production/0.pack +0 -0
  11. package/.next/cache/webpack/server-production/index.pack +0 -0
  12. package/.next/next-minimal-server.js.nft.json +1 -1
  13. package/.next/next-server.js.nft.json +1 -1
  14. package/.next/prerender-manifest.js +1 -1
  15. package/.next/prerender-manifest.json +1 -1
  16. package/.next/routes-manifest.json +1 -1
  17. package/.next/server/app/_not-found.html +2 -2
  18. package/.next/server/app/_not-found.rsc +1 -1
  19. package/.next/server/app/fs-next-update.html +2 -2
  20. package/.next/server/app/fs-next-update.rsc +1 -1
  21. package/.next/server/chunks/2381.js +1 -1
  22. package/.next/server/middleware-build-manifest.js +1 -1
  23. package/.next/server/pages/404.html +2 -2
  24. package/.next/server/pages/[slug]/p.js +5 -5
  25. package/.next/server/pages/en-US/404.html +2 -2
  26. package/.next/server/pages/en-US/500.html +2 -2
  27. package/.next/server/pages/en-US/account.html +2 -2
  28. package/.next/server/pages/en-US/checkout.html +2 -2
  29. package/.next/server/pages/en-US/login.html +2 -2
  30. package/.next/server/pages/en-US/s.html +2 -2
  31. package/.next/server/pages/en-US.html +2 -2
  32. package/.next/server/pages-manifest.json +1 -1
  33. package/.next/static/{6RpWP2aATNq_ljgOww_7v → 4w3LMmusMebDghIVyNvPn}/_buildManifest.js +1 -1
  34. package/.next/static/chunks/pages/{404-be2217109dab18cf.js → 404-6d926d3bdc58852b.js} +1 -1
  35. package/.next/static/chunks/pages/{500-64a07a16830e129c.js → 500-cbffc24e6eaddf18.js} +1 -1
  36. package/.next/static/chunks/pages/{login-258e5b7ecec36481.js → login-78b2d6166a2ebbaa.js} +1 -1
  37. package/.next/static/chunks/{webpack-a45dc84c9a0ef3fd.js → webpack-4f403c9b52a287c6.js} +1 -1
  38. package/.next/static/css/9b7689964b990431.css +1 -0
  39. package/.next/trace +62 -62
  40. package/.turbo/turbo-build.log +3 -3
  41. package/.turbo/turbo-test.log +5 -5
  42. package/package.json +2 -2
  43. package/src/pages/[slug]/p.tsx +1 -1
  44. package/src/server/cms/pdp.ts +7 -15
  45. package/src/utils/multipleTemplates.ts +57 -19
  46. package/test/utils/multipleTemplates.test.ts +80 -2
  47. package/.next/static/css/548bab931c45c770.css +0 -1
  48. /package/.next/static/{6RpWP2aATNq_ljgOww_7v → 4w3LMmusMebDghIVyNvPn}/_ssgManifest.js +0 -0
@@ -1,7 +1,7 @@
1
1
  $ yarn partytown & yarn generate && next build
2
2
  $ partytown copylib ./public/~partytown
3
- Partytown lib copied to: /home/runner/work/faststore/faststore/packages/core/public/~partytown
4
3
  $ faststore generate-graphql -c
4
+ Partytown lib copied to: /home/runner/work/faststore/faststore/packages/core/public/~partytown
5
5
  success - GraphQL schema, types, and optimizations successfully generated 🎉
6
6
  ⚠ No build cache found. Please configure build caching for faster rebuilds. Read more: https://nextjs.org/docs/messages/no-cache
7
7
  Attention: Next.js now collects completely anonymous telemetry regarding usage.
@@ -38,7 +38,7 @@ Route (app) Size First Load JS
38
38
  ├ chunks/472-369461a1f39981d5.js 28.4 kB
39
39
  ├ chunks/fd9d1056-43c43818840d7811.js 51.1 kB
40
40
  ├ chunks/main-app-e13fa67c2c3ceca5.js 230 B
41
- └ chunks/webpack-a45dc84c9a0ef3fd.js 2.43 kB
41
+ └ chunks/webpack-4f403c9b52a287c6.js 2.43 kB
42
42
 
43
43
  Route (pages) Size First Load JS
44
44
  ┌ ● / 1.04 kB 148 kB
@@ -62,7 +62,7 @@ Route (pages) Size First Load JS
62
62
  ├ chunks/framework-21e9365486ba23a6.js 45.4 kB
63
63
  ├ chunks/main-9c9c62c368c0a47e.js 34.8 kB
64
64
  ├ chunks/pages/_app-1930798899758fda.js 11.2 kB
65
- ├ chunks/webpack-a45dc84c9a0ef3fd.js 2.43 kB
65
+ ├ chunks/webpack-4f403c9b52a287c6.js 2.43 kB
66
66
  └ css/5d1f64b61ea581f4.css 3.05 kB
67
67
 
68
68
  λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps)
@@ -1,10 +1,10 @@
1
1
  $ jest
2
- PASS test/utils/multipleTemplates.test.ts (32.235 s)
3
- PASS test/server/cms/index.test.ts (32.591 s)
4
- PASS test/server/index.test.ts (34.429 s)
2
+ PASS test/server/cms/index.test.ts (31.47 s)
3
+ PASS test/utils/multipleTemplates.test.ts (31.586 s)
4
+ PASS test/server/index.test.ts (32.977 s)
5
5
 
6
6
  Test Suites: 3 passed, 3 total
7
- Tests: 16 passed, 16 total
7
+ Tests: 19 passed, 19 total
8
8
  Snapshots: 0 total
9
- Time: 35.349 s
9
+ Time: 34.047 s
10
10
  Ran all test suites.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/core",
3
- "version": "3.0.60",
3
+ "version": "3.0.61",
4
4
  "license": "MIT",
5
5
  "repository": "vtex/faststore",
6
6
  "browserslist": "supports es6-module and not dead",
@@ -125,5 +125,5 @@
125
125
  "node": "18.19.0",
126
126
  "yarn": "1.19.1"
127
127
  },
128
- "gitHead": "19bd97e7ce1d842d390dbdd1e7e1859c1624b5fb"
128
+ "gitHead": "9ce5509d24e1a1f6eca08c77544b94db7ef4037b"
129
129
  }
@@ -231,7 +231,7 @@ export const getStaticProps: GetStaticProps<
231
231
  throw errors[0]
232
232
  }
233
233
 
234
- const cmsPage: PDPContentType = await getPDP(slug, data.product, previewData)
234
+ const cmsPage: PDPContentType = await getPDP(data.product, previewData)
235
235
 
236
236
  const { seo } = data.product
237
237
  const title = seo.title || storeConfig.seo.title
@@ -21,7 +21,6 @@ type PDPfromCmsEnvData = {
21
21
  export type PDPContentType = ContentData & PDPSettings
22
22
 
23
23
  export const getPDP = async (
24
- slug: string,
25
24
  product: ServerProductQueryQuery['product'],
26
25
  previewData: Locator
27
26
  ) => {
@@ -29,25 +28,19 @@ export const getPDP = async (
29
28
  const cmsData = JSON.parse(config.cms.data)
30
29
  const allPDPsFromCmsEnvData: PDPfromCmsEnvData[] = cmsData['pdp']
31
30
 
32
- return await getPDPFromCmsEnvData(
33
- `/${slug}/p`,
34
- product,
35
- allPDPsFromCmsEnvData,
36
- {
37
- ...(previewData?.contentType === 'pdp' ? previewData : null),
38
- contentType: 'pdp',
39
- }
40
- )
31
+ return await getPDPFromCmsEnvData(product, allPDPsFromCmsEnvData, {
32
+ ...(previewData?.contentType === 'pdp' ? previewData : null),
33
+ contentType: 'pdp',
34
+ })
41
35
  }
42
36
 
43
- return (await getPDPFromCms(`/${slug}/p`, product, {
37
+ return (await getPDPFromCms(product, {
44
38
  ...(previewData?.contentType === 'pdp' ? previewData : null),
45
39
  contentType: 'pdp',
46
40
  })) as PDPContentType
47
41
  }
48
42
 
49
43
  const getPDPFromCmsEnvData = async (
50
- slug: string,
51
44
  product: ServerProductQueryQuery['product'],
52
45
  allPDPsFromCMSData: PDPfromCmsEnvData[],
53
46
  options: Options
@@ -58,7 +51,7 @@ const getPDPFromCmsEnvData = async (
58
51
  throw new MissingContentError(options)
59
52
  }
60
53
 
61
- const template = findBestPDPTemplate(pages, slug, product)
54
+ const template = findBestPDPTemplate(pages, product)
62
55
 
63
56
  return getPage<PDPContentType>({
64
57
  contentType: 'pdp',
@@ -68,7 +61,6 @@ const getPDPFromCmsEnvData = async (
68
61
  }
69
62
 
70
63
  const getPDPFromCms = async (
71
- slug: string,
72
64
  product: ServerProductQueryQuery['product'],
73
65
  options: Options
74
66
  ): Promise<Partial<PDPContentType>> => {
@@ -78,5 +70,5 @@ const getPDPFromCms = async (
78
70
  throw new MissingContentError(options)
79
71
  }
80
72
 
81
- return findBestPDPTemplate(pages, slug, product)
73
+ return findBestPDPTemplate(pages, product)
82
74
  }
@@ -135,40 +135,53 @@ export function normalizePDPTemplate(templateValue: string) {
135
135
  return formattedValue.toLowerCase()
136
136
  }
137
137
 
138
+ // Returns an array of slugs without the number at the end ("-{number}/p") at each interaction if it matches, otherwise returns the slug as is.
139
+ const getSlugsWithoutSkuIdFromPDP = (slug: string) => {
140
+ const slugs = []
141
+ let currentSlug = slug
142
+ let match = currentSlug.match(/-\d+\/p$/)
143
+
144
+ while (match) {
145
+ const newSlug = currentSlug.replace(/-\d+\/p$/, '/p')
146
+ slugs.push(newSlug)
147
+ currentSlug = newSlug
148
+ match = currentSlug.match(/-\d+\/p$/)
149
+ }
150
+
151
+ return slugs
152
+ }
153
+
138
154
  /**
139
155
  * Find the best PDP template from the CMS based on the slug or in the product category tree.
140
156
  * Prioritizing the following order:
141
157
  *
142
- * 1. A PDP template that matches the page slug (e.g. slug = /apple-magic-mouse/p).
143
- * 2. A PDP template that matches the product subcategory (e.g. /department/category/subcategory).
144
- * 3. A PDP template that matches the product category (e.g. /department/category).
145
- * 4. A PDP template that matches the product department (e.g. /department).
146
- * 5. If no matches are found, use the generic PDP template.
158
+ * 1. A PDP template that matches the page slug with skuId (e.g. slug = /apple-magic-mouse-12345/p).
159
+ * 2. A PDP template that matches the page slug (e.g. slug = /apple-magic-mouse/p).
160
+ * 3. A PDP template that matches the product subcategory (e.g. /department/category/subcategory).
161
+ * 4. A PDP template that matches the product category (e.g. /department/category).
162
+ * 5. A PDP template that matches the product department (e.g. /department).
163
+ * 6. If no matches are found, use the generic PDP template.
147
164
  *
148
165
  * @param pages
149
- * @param originalSlug
150
166
  * @param product
151
- * @returns The best PDP template page for the slug
167
+ * @returns The best PDP template page for the product
152
168
  */
153
169
  export function findBestPDPTemplate(
154
170
  pages: Partial<PDPContentType>[],
155
- slug: string,
156
171
  product: ServerProductQueryQuery['product']
157
172
  ) {
158
- // productSlugAndCategoryTree with the prioritized order. [slug, subcategory tree, category tree, department]
159
- const productSlugAndCategoryTree = product?.breadcrumbList?.itemListElement
160
- ? [...product?.breadcrumbList?.itemListElement]
161
- .reverse()
162
- .map(({ item }) => item)
163
- : []
164
- productSlugAndCategoryTree.unshift(slug)
165
-
166
- for (const item of productSlugAndCategoryTree) {
173
+ const templateValues = getPDPTemplateValues({
174
+ itemListElement: product.breadcrumbList.itemListElement ?? [],
175
+ })
176
+
177
+ for (const template of templateValues) {
167
178
  for (const page of pages) {
168
179
  if (!page.settings?.template?.value) continue
169
180
 
170
- const templateValue = normalizePDPTemplate(page.settings.template.value)
171
- if (templateValue === item) {
181
+ const templateValueFromCms = normalizePDPTemplate(
182
+ page.settings.template.value
183
+ )
184
+ if (templateValueFromCms === template) {
172
185
  return page
173
186
  }
174
187
  }
@@ -176,3 +189,28 @@ export function findBestPDPTemplate(
176
189
 
177
190
  return pages.find((page) => !page.settings?.template?.value) || pages[0]
178
191
  }
192
+
193
+ export function getPDPTemplateValues({
194
+ itemListElement = [],
195
+ }: {
196
+ itemListElement: ServerProductQueryQuery['product']['breadcrumbList']['itemListElement']
197
+ }) {
198
+ // productSlugAndCategoryTree with the prioritized order. [link-skuId/p, subcategory tree, category tree, department]
199
+ const productSlugAndCategoryTree = [...itemListElement]
200
+ .reverse()
201
+ .map(({ item }) => item)
202
+
203
+ // PDP slug comes from FastStore API with the format `${link}-${skuId}/p`, the most specific for multiple page templates,
204
+ // so it should be the first element
205
+ const slugWithSkuId = productSlugAndCategoryTree[0]
206
+
207
+ // PDP slug without skuId `${link}/p`, should be the second element
208
+ const slugsWithoutSkuId = getSlugsWithoutSkuIdFromPDP(slugWithSkuId)
209
+
210
+ // removes duplicated and undefined
211
+ return [
212
+ slugWithSkuId,
213
+ ...slugsWithoutSkuId,
214
+ ...productSlugAndCategoryTree.slice(1),
215
+ ].filter((item, index, arr) => item && arr.indexOf(item) === index)
216
+ }
@@ -1,8 +1,27 @@
1
1
  import type { Rewrite, RewritesConfig } from '../../src/utils/multipleTemplates'
2
- import { hasRewritesConfigForSlug } from '../../src/utils/multipleTemplates'
2
+ import {
3
+ getPDPTemplateValues,
4
+ hasRewritesConfigForSlug,
5
+ } from '../../src/utils/multipleTemplates'
6
+
7
+ const productItemListElementMock = [
8
+ { item: '/department/', name: 'test', position: 1 }, // Department
9
+ { item: '/department/category/', name: 'test', position: 1 }, // Category tree
10
+ { item: '/department/category/subcategory/', name: 'test', position: 1 }, // Subcategory tree
11
+ {
12
+ item: '/department/category/subcategory/subcategory2/',
13
+ name: 'test',
14
+ position: 1,
15
+ }, // Subcategory tree tree
16
+ {
17
+ item: '/department/category/subcategory/subcategory2/subcategory3/',
18
+ name: 'test',
19
+ position: 1,
20
+ }, // Subcategory tree
21
+ ]
3
22
 
4
23
  describe('Multiple page templates', () => {
5
- describe('hasRewritesConfigForSlug', () => {
24
+ describe('PLP hasRewritesConfigForSlug', () => {
6
25
  it('should return true when rewrites is an array of objects containing the desired destination and source', () => {
7
26
  const rewritesArr: Rewrite[] = [
8
27
  { source: '/test/my-office', destination: '/office' },
@@ -63,4 +82,63 @@ describe('Multiple page templates', () => {
63
82
  expect(result).toBe(false)
64
83
  })
65
84
  })
85
+
86
+ describe('PDP getPDPTemplateValues', () => {
87
+ it('should return correct template values when productItemListElement first item has skuId and numbers', () => {
88
+ const mock = [
89
+ ...productItemListElementMock,
90
+ { item: '/slug-product-test-111111-2222/p', name: 'test', position: 1 },
91
+ ] // PDP slug with skuId and number
92
+ const result = getPDPTemplateValues({
93
+ itemListElement: mock,
94
+ })
95
+ expect(result).toEqual([
96
+ '/slug-product-test-111111-2222/p', // PDP slug with skuId
97
+ '/slug-product-test-111111/p', // PDP slug without skuId
98
+ '/slug-product-test/p', // PDP slug without number
99
+ '/department/category/subcategory/subcategory2/subcategory3/', // Subcategory tree
100
+ '/department/category/subcategory/subcategory2/', // Subcategory tree
101
+ '/department/category/subcategory/', // Subcategory
102
+ '/department/category/', // Category
103
+ '/department/', // Department
104
+ ])
105
+ })
106
+
107
+ it('should return correct template values when productItemListElement first item have skuId', () => {
108
+ const mock = [
109
+ ...productItemListElementMock,
110
+ { item: '/slug-product-test-111111/p', name: 'test', position: 1 },
111
+ ] // PDP slug with skuId
112
+ const result = getPDPTemplateValues({
113
+ itemListElement: mock,
114
+ })
115
+ expect(result).toEqual([
116
+ '/slug-product-test-111111/p', // PDP slug with skuId
117
+ '/slug-product-test/p', // PDP slug without number
118
+ '/department/category/subcategory/subcategory2/subcategory3/', // Subcategory tree
119
+ '/department/category/subcategory/subcategory2/', // Subcategory tree
120
+ '/department/category/subcategory/', // Subcategory
121
+ '/department/category/', // Category
122
+ '/department/', // Department
123
+ ])
124
+ })
125
+
126
+ it('should return correct template values productItemListElement first item do not have skuId and other number', () => {
127
+ const mock = [
128
+ ...productItemListElementMock,
129
+ { item: '/slug-product-test/p', name: 'test', position: 1 },
130
+ ] // PDP slug with skuId
131
+ const result = getPDPTemplateValues({
132
+ itemListElement: mock,
133
+ })
134
+ expect(result).toEqual([
135
+ '/slug-product-test/p', // PDP slug without skuId
136
+ '/department/category/subcategory/subcategory2/subcategory3/', // Subcategory tree
137
+ '/department/category/subcategory/subcategory2/', // Subcategory tree
138
+ '/department/category/subcategory/', // Subcategory
139
+ '/department/category/', // Category
140
+ '/department/', // Department
141
+ ])
142
+ })
143
+ })
66
144
  })