From bef6d60c958b40a8d1ecf85c8ef0e6dedd42039c Mon Sep 17 00:00:00 2001 From: vitorflg Date: Mon, 1 Jun 2026 15:28:19 -0300 Subject: [PATCH] feat: paginate listEntries with scroll (#3282) `ContentService.getPage` was returning only the first page of entries from Content Platform because `listEntries` wasn't following the `scroll` token. Result: pages backed by CP silently missed content beyond the first batch. In `packages/core/src/server/content/service.ts`, the single `listEntries` call is replaced by a loop that accumulates entries while a `scroll` token is returned, then passes the full list to `fillEntriesWithData`. - On a store using the CP data source, create enough entries for a given content type to exceed a single page. - Request that page and verify all entries are returned (not just the first batch). - Confirm non-CP (hCMS) path is unaffected. N/A N/A * **Bug Fixes** * Content retrieval now fully paginates via scrolling, accumulating entries across pages and avoiding truncated results (stops safely with a max-page cap and logs a warning if reached). * **Enhancements** * Product listing (PLP) and product detail (PDP) now attempt a direct single-item fetch first and return immediately on direct matches, improving accuracy and performance. * **Notes** * No changes to public APIs or exported entities. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/vtex/faststore/pull/3282?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) --- packages/core/package.json | 2 +- packages/core/src/server/content/service.ts | 35 +++++++++++++++++++-- pnpm-lock.yaml | 10 +++--- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index ff18de174c..6758095ba3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -75,7 +75,7 @@ "@parcel/watcher": "^2.4.0", "@types/react": "^18.2.42", "@vtex/client-cms": "^0.2.16", - "@vtex/client-cp": "0.3.5", + "@vtex/client-cp": "0.6.0", "@vtex/prettier-config": "1.0.0", "autoprefixer": "^10.4.0", "cookie": "^0.7.0", diff --git a/packages/core/src/server/content/service.ts b/packages/core/src/server/content/service.ts index e550873f78..f078cca630 100644 --- a/packages/core/src/server/content/service.ts +++ b/packages/core/src/server/content/service.ts @@ -46,8 +46,29 @@ export class ContentService { if (isContentPlatformSource()) { const serviceParams = this.convertOptionsToParams(options) - const { entries } = await this.clientCP.listEntries(serviceParams) - return this.fillEntriesWithData(entries, serviceParams, options.isPreview) + // TODO: This should be temporary until the cp data-plane have a search engine. + const MAX_PAGES = 25 + const allEntries: ContentEntry[] = [] + let scroll: string | undefined + let pages = 0 + + do { + const result = await this.clientCP.listEntries(serviceParams, scroll) + allEntries.push(...result.entries) + const next = result.scroll ?? undefined + if (next && next === scroll) break + scroll = next + } while (scroll && ++pages < MAX_PAGES) + + if (pages >= MAX_PAGES) { + console.warn('listEntries pagination hit MAX_PAGES cap', serviceParams) + } + + return this.fillEntriesWithData( + allEntries, + serviceParams, + options.isPreview + ) } return getCMSPage(options.cmsOptions) } @@ -60,6 +81,11 @@ export class ContentService { const options = this.createContentOptions(plpParams) if (isContentPlatformSource()) { + const directMatch = await this.getSingleContent(plpParams) + if (directMatch) { + return directMatch + } + const pages = (await this.getMultipleContent(plpParams)).data if (!pages?.length) throw new MissingContentError(options.cmsOptions) return findBestPLPTemplate( @@ -79,6 +105,11 @@ export class ContentService { const options = this.createContentOptions(pdpParams) if (isContentPlatformSource()) { + const directMatch = await this.getSingleContent(pdpParams) + if (directMatch) { + return directMatch + } + const pages = (await this.getMultipleContent(pdpParams)).data if (!pages.length) throw new MissingContentError(options.cmsOptions) return findBestPDPTemplate( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5edb65f638..7acec9c496 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -375,8 +375,8 @@ importers: specifier: ^0.2.16 version: 0.2.16(encoding@0.1.13) "@vtex/client-cp": - specifier: 0.3.5 - version: 0.3.5 + specifier: 0.6.0 + version: 0.6.0 "@vtex/prettier-config": specifier: 1.0.0 version: 1.0.0(prettier@2.8.3) @@ -6161,10 +6161,10 @@ packages: integrity: sha512-mK5OiaaGHItVuispyy8yXLILnMx4aOJj7HkamOmAL12+KbnkiKKpO1vJEb3hRB16lK1rHtl7Q5H3aTFsMqrf0w==, } - "@vtex/client-cp@0.3.5": + "@vtex/client-cp@0.6.0": resolution: { - integrity: sha512-uzvpYz1LHiPxBc0FmVVG0azfGWiYJhIJf2JgcNSsi3V5oxR/dwM6tbh+JigSNQpp6bNn9GglLvMpYboxORMsnQ==, + integrity: sha512-+ijNI8uOIB84oOSZFiEmEcjXe23sK9lwTyvyoB72y1gS7Xfqgwn93F9gzrbYjxerPNZTb8ZSlsGBLWxCx1ONBw==, } engines: { node: ">=16" } @@ -23583,7 +23583,7 @@ snapshots: transitivePeerDependencies: - encoding - "@vtex/client-cp@0.3.5": + "@vtex/client-cp@0.6.0": dependencies: axios: 1.9.0 transitivePeerDependencies: