-
Notifications
You must be signed in to change notification settings - Fork 13
USF-3785: ACO PDP support #265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
a4a4b1d
Add PDP pre-render support for Commerce Optimizer
rossbrandon b3655ca
Cleanup getAllSkus functions
rossbrandon 43bd63f
Improved ACO PDP pre-rendering by category families
rossbrandon 447bce2
Account for optional ac-price-book-id header
rossbrandon 640da83
Address PR feedback: better env var array input handling; comment unu…
rossbrandon 364d12b
Reword ACO_CATEGORY_FAMILIES input in README
rossbrandon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| /* | ||
|
|
||
| Copyright 2026 Adobe. All rights reserved. | ||
| This file is licensed to you under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. You may obtain a copy | ||
| of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software distributed under | ||
| the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | ||
| OF ANY KIND, either express or implied. See the License for the specific language | ||
| governing permissions and limitations under the License. | ||
|
|
||
| */ | ||
|
|
||
| const { requestSaaS } = require("./utils"); | ||
| const { | ||
| CategoriesQuery, | ||
| CategoryTreeQuery, | ||
| CategoryTreeBySlugsQuery, | ||
| } = require("./queries"); | ||
|
|
||
| const MAX_TREE_DEPTH = 3; | ||
|
|
||
| /** | ||
| * Checks whether category families are configured (not the [null] default). | ||
| * | ||
| * @param {Array} families - The categoryFamilies array from runtime config. | ||
| * @returns {boolean} | ||
| */ | ||
| function hasFamilies(families) { | ||
| return Array.isArray(families) && families.length > 0 && families[0] !== null; | ||
| } | ||
|
|
||
| /** | ||
| * Resolves all category slugs belonging to the given ACO category families. | ||
| * | ||
| * Uses BFS traversal of the categoryTree API: | ||
| * 1. Query each family's root categories and their immediate childrenSlugs. | ||
| * 2. Query those children (with depth) to retrieve their descendants. | ||
| * 3. Repeat until no unresolved childrenSlugs remain. | ||
| * | ||
| * Handles trees of arbitrary depth even when the API caps depth at | ||
| * MAX_TREE_DEPTH per call — each iteration advances up to that many levels. | ||
| * | ||
| * @param {Object} context - Request context (config, logger, headers, etc.). | ||
| * @param {string[]} families - ACO category family identifiers. | ||
| * @returns {Promise<string[]>} Flat array of all unique category slugs. | ||
| */ | ||
| async function getCategorySlugsFromFamilies(context, families) { | ||
| console.debug("Getting category slugs from families:", families); | ||
| const allSlugs = new Set(); | ||
|
|
||
| for (const family of families) { | ||
| console.debug("Getting category slugs from family:", family); | ||
| // Get root-level categories for this family | ||
| const firstLevel = await requestSaaS( | ||
| CategoryTreeQuery, | ||
| "getCategoryTree", | ||
| { family }, | ||
| context, | ||
| ); | ||
|
|
||
| let pending = []; | ||
| for (const cat of firstLevel.data.categoryTree) { | ||
| allSlugs.add(cat.slug); | ||
| pending.push(...(cat.childrenSlugs || [])); | ||
| } | ||
|
|
||
| // BFS: resolve children level by level until no new slugs remain | ||
| while (pending.length) { | ||
| // Mark pending as seen before querying to prevent re-processing | ||
| for (const slug of pending) allSlugs.add(slug); | ||
|
|
||
| const childrenRes = await requestSaaS( | ||
| CategoryTreeBySlugsQuery, | ||
| "getCategoryTreeBySlugs", | ||
| { family, slugs: pending, depth: MAX_TREE_DEPTH }, | ||
| context, | ||
| ); | ||
|
|
||
| // First pass: capture any descendant slugs included due to depth traversal | ||
| for (const cat of childrenRes.data.categoryTree) { | ||
| allSlugs.add(cat.slug); | ||
| } | ||
|
|
||
| // Second pass: collect only new childrenSlugs for next iteration | ||
| pending = []; | ||
| for (const cat of childrenRes.data.categoryTree) { | ||
| for (const child of cat.childrenSlugs || []) { | ||
| if (!allSlugs.has(child)) pending.push(child); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| console.debug("Category slugs resolved:", [...allSlugs]); | ||
|
|
||
| return [...allSlugs]; | ||
| } | ||
|
|
||
| /** | ||
| * Retrieves all ACCS categories grouped by level. | ||
| * | ||
| * Returns a sparse array indexed by category level so callers can iterate | ||
| * shallowest levels first (used for the early-exit optimization when | ||
| * fetching products by category). | ||
| * | ||
| * @param {Object} context - Request context (config, logger, headers, etc.). | ||
| * @returns {Promise<string[][]>} Sparse array where index N holds urlPath strings at level N. | ||
| */ | ||
| async function getCategories(context) { | ||
| const categoriesRes = await requestSaaS( | ||
| CategoriesQuery, | ||
| "getCategories", | ||
| {}, | ||
| context, | ||
| ); | ||
| const byLevel = []; | ||
| for (const { urlPath, level } of categoriesRes.data.categories) { | ||
| const idx = parseInt(level); | ||
| byLevel[idx] = byLevel[idx] || []; | ||
| byLevel[idx].push(urlPath); | ||
| } | ||
| return byLevel; | ||
| } | ||
|
|
||
| module.exports = { getCategorySlugsFromFamilies, getCategories, hasFamilies }; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.