Skip to content

Conversation

@yuriassuncx
Copy link
Contributor

@yuriassuncx yuriassuncx commented Sep 10, 2025

What is this Contribution About?

This PR introduces internationalization (i18n) support for the main Shopify queries and loaders used in Deco.cx. With this update, it's now possible to dynamically pass languageCode and countryCode values via the @inContext directive, allowing the Shopify Storefront API to return localized content for different languages and regions.

Additionally, this PR enhances the sitemap handling logic by introducing the ability to exclude specific URLs from the sitemap response using a new exclude prop in the proxy handler.


🧩 How It Works

✅ Loaders

Most loaders now accept the following optional props:

/**
 * @title Language Code
 * @description Language code for the storefront API
 * @example "EN" for English, "FR" for French, etc.
 */
languageCode?: LanguageCode;

/**
 * @title Country Code
 * @description Country code for the storefront API
 * @example "US" for United States, "FR" for France, etc.
 */
countryCode?: CountryCode;

These values are passed as variables to GraphQL queries and injected using the @inContext directive.


✅ Queries

All core Shopify queries have been refactored to use GraphQL variables in the @inContext directive (instead of interpolated JavaScript), making them fully compatible with GraphQL tooling and static code analysis like GraphQL Codegen.

Example:

query GetProduct(
  $handle: String, 
  $identifiers: [HasMetafieldsIdentifier!]!,
  $languageCode: LanguageCode,
  $countryCode: CountryCode
) @inContext(language: $languageCode, country: $countryCode) {
  product(handle: $handle) {
    ...Product
  }
}

On the TypeScript side:

variables: {
  handle,
  identifiers: metafields,
  languageCode,
  countryCode,
}

🗺️ Sitemap Enhancements

The sitemap proxy handler now accepts two optional props:

include?: string[];
exclude?: string[];

This enables:

  • Injecting custom sitemap entries (include)
  • 🚫 Removing unwanted URLs from the proxied Shopify sitemap (exclude)

Example usage:

{
  "include": ["/sitemap_pages_custom.xml"],
  "exclude": [
    "/sitemap_products_1.xml",
    "/sitemap_pages_1.xml",
    "/sitemap_collections_1.xml",
    "/sitemap_blogs_1.xml"
  ]
}

This resolves issues where Shopify includes non-localized or duplicated sitemap entries that should not be indexed, allowing more control over SEO structure.


🛠 Affected Queries

This pattern has been applied consistently across:

  • ListProducts
  • SearchProducts
  • ProductsByCollection
  • ProductRecommendations
  • GetProduct and related queries
  • Shop
  • Cart

🌍 Impact

  • ✅ Native internationalization support
  • 📈 Improved SEO control with sitemap inclusion/exclusion
  • 🌐 Global readiness: Better scaling for multilingual/multiregional stores
  • 🛡️ Backward compatible: All new props are optional
  • 🔧 Improved DX: Cleaner GraphQL with full tooling compatibility

🎥 Loom Video

https://www.loom.com/share/8a8f204de9a745528ac2f84f44f428fa

Summary by CodeRabbit

  • New Features

    • Locale-aware storefront across product pages, listings, related products, cart, and shop (defaults PT/BR, optional overrides).
    • Cart buyer identity can be set/updated for locale-aware pricing/taxes.
    • Option to exclude specific paths from Shopify sitemap and inject additional sitemap entries.
  • Improvements

    • Search, collections, recommendations, and shop data respect language/country context.
    • Breadcrumbs include collection id and handle and handle deeper paths better.
    • More robust metafield image handling and clearer cart/auth error surfaces.
  • Chores

    • Backward-compatible proxy path handling with deprecation notice for legacy option.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

Walkthrough

Threads optional languageCode and countryCode (defaults PT/BR) through multiple Shopify loaders and storefront GraphQL queries via @inContext; expands cart buyerIdentity and adds CartBuyerIdentityUpdate; introduces sitemap include/exclude handling and proxy sitemap routing; simplifies metafield image transform; adjusts collection breadcrumb/path behavior and proxy route sitemap handling.

Changes

Cohort / File(s) Summary of Changes
Locale context in loaders
shopify/loaders/ProductDetailsPage.ts, shopify/loaders/ProductList.ts, shopify/loaders/ProductListingPage.ts, shopify/loaders/RelatedProducts.ts, shopify/loaders/shop.ts
Add optional Props languageCode?: LanguageCode, countryCode?: CountryCode (defaults PT/BR); import LanguageCode, CountryCode, LanguageContextArgs; extend GraphQL typings to include LanguageContextArgs; pass language/country in query variables.
Product listing path & breadcrumb
shopify/loaders/ProductListingPage.ts
Use last non-empty URL segment for collection path, capture collectionId from response, add @id to breadcrumb, and derive breadcrumb name from last path segment for non-search results.
Cart loader & buyer identity
shopify/loaders/cart.ts, shopify/utils/storefront/queries.ts, shopify/utils/storefront/storefront.graphql.gen.ts
Export Props with language/country; change loader signature to accept props and default locales; CreateCart accepts countryCode; GetCart types accept languageCode/countryCode; cart surfaces include buyerIdentity; add CartBuyerIdentityUpdate mutation and types.
Proxy routes & sitemap exclusions
shopify/loaders/proxy.ts
Add excludePathsFromShopifySiteMap?: string[] to Props; introduce extraPathsToProxy with deprecation handling for extraPaths; compute finalExtraPathsToProxy; set route __resolveType based on pathTemplate including "sitemap"; expose sitemap exclude on /sitemap.xml.
Storefront queries & mutations
shopify/utils/storefront/queries.ts
Thread languageCode/countryCode into many queries/mutations with @inContext; expand Cart fragment to include buyerIdentity; update CreateCart, GetProduct, ListProducts, SearchProducts, ProductsByCollection, ProductRecommendations, GetShopInfo and various cart/auth mutations to accept localization args and return richer payloads/errors.
Generated GraphQL types
shopify/utils/storefront/storefront.graphql.gen.ts
Regenerated types: many Query/Mutation variables now accept languageCode/countryCode; cart types include buyerIdentity; added CartBuyerIdentityUpdate types; AllProductsQuery collection includes id.
Metafield image transform
shopify/utils/transform.ts
Simplify image extraction using optional chaining and array checks; build metafield value as reference image URL or comma-separated edge image URLs; reduce branching.
Shared types
shopify/utils/types.ts
Import LanguageCode/CountryCode from generated types; add exported LanguageContextArgs interface.
Sitemap handler include/exclude pipeline
shopify/handlers/sitemap.ts
Add exclude?: string[] to Props; introduce buildIncludeSitemaps and excludeSitemaps helpers; normalize origin replacement; apply exclusions to proxied sitemap and inject includes; adjust headers/response handling.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant App as UI/App
  participant Loader as Page Loader
  participant SF as Storefront API

  User->>App: navigate
  App->>Loader: loader({ languageCode?, countryCode? })
  note right of Loader `#E8F8F5`: defaults language=PT, country=BR
  Loader->>SF: GraphQL query with `@inContext`(languageCode, countryCode)
  SF-->>Loader: localized response (cart may include buyerIdentity)
  Loader-->>App: localized data
  App-->>User: render
Loading
sequenceDiagram
  autonumber
  participant CartLoader as Cart Loader
  participant SF as Storefront API

  CartLoader->>SF: CreateCart(countryCode?) / GetCart(id, languageCode?, countryCode?)
  SF-->>CartLoader: cart { id, buyerIdentity, lines... }
  CartLoader->>SF: CartBuyerIdentityUpdate(cartId, buyerIdentity)
  SF-->>CartLoader: updated cart + userErrors
  CartLoader-->>Client: Cart with buyerIdentity context
Loading
sequenceDiagram
  autonumber
  participant Proxy as Proxy Loader
  participant Builder as buildProxyRoutes
  participant Routes as Route Output

  Proxy->>Builder: { extraPathsToProxy?, extraPaths?, excludePathsFromShopifySiteMap? }
  Builder-->>Proxy: routes (uses finalExtraPathsToProxy)
  note right of Routes `#F7F9F9`: `/sitemap.xml` route includes `exclude` and __resolveType based on pathTemplate
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Points needing extra attention:

  • GraphQL type alignment between modified queries/mutations and regenerated typings.
  • Cart buyerIdentity flows and CartBuyerIdentityUpdate error propagation.
  • Backwards-compatibility and deprecation handling between extraPaths and extraPathsToProxy.
  • Sitemap include/exclude normalization and response header preservation.
  • Breadcrumb collectionId plumbing and any consumers of the breadcrumb @id field.

Possibly related PRs

  • fix check #1418 — touches shopify/loaders/ProductList.ts with import/type/props updates; likely overlaps with locale-context changes.

Suggested reviewers

  • guitavano
  • viktormarinho

Poem

Thump-thump I hop through code and rails,
PT whispers, BR sets compass sails.
Sitemaps pruned and breadcrumbs steer,
Image-strings gleam like carrots near.
Hooray — locales snug, the build prevails! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'Feat [Shopify]: Internationalization Support for Shopify Loaders and Queries' accurately and concisely summarizes the main change—adding i18n support to Shopify loaders and GraphQL queries.
Description check ✅ Passed The PR description comprehensively covers the changes: it explains the i18n feature, provides code examples, documents the sitemap enhancements, lists affected queries, and includes a Loom video link demonstrating the implementation.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

Tagging Options

Should a new tag be published when this PR is merged?

  • 👍 for Patch 0.121.6 update
  • 🎉 for Minor 0.122.0 update
  • 🚀 for Major 1.0.0 update

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
shopify/utils/transform.ts (1)

353-370: Bug: URLSearchParams API misused; toggle logic never works

URLSearchParams.has and .delete don’t accept a value argument. As written, removing a single selected filter never happens.

Apply:

   const label = getFilterValue(value);
-
-  if (params.has(filter.id, label)) {
-    params.delete(filter.id, label);
-  } else {
-    params.append(filter.id, label);
-  }
+  const existing = params.getAll(filter.id);
+  const idx = existing.indexOf(label);
+  if (idx >= 0) {
+    existing.splice(idx, 1);
+    params.delete(filter.id);
+    for (const v of existing) params.append(filter.id, v);
+  } else {
+    params.append(filter.id, label);
+  }
shopify/loaders/ProductListingPage.ts (1)

249-251: Canonical uses zero-based page.

Use currentPage (or page + currentPageoffset) to avoid emitting ?page=1 for the second page request of ?page=2.

Apply:

-      canonical: `${url.origin}${url.pathname}${
-        page >= 1 ? `?page=${page}` : ""
-      }`,
+      canonical: `${url.origin}${url.pathname}${
+        currentPage > 1 ? `?page=${currentPage}` : ""
+      }`,
shopify/loaders/RelatedProducts.ts (1)

99-109: Include locale in cacheKey to prevent cross-locale cache mixups

Even with no-cache today, adding these guards against future caching or upstream overrides.

-export const cacheKey = (props: Props, req: Request): string => {
-  const { slug, count } = props;
+export const cacheKey = (props: Props, req: Request): string => {
+  const { slug, count, languageCode, countryCode } = props;
   const searchParams = new URLSearchParams({
     slug,
     count: count.toString(),
+    languageCode: (languageCode ?? "PT"),
+    countryCode: (countryCode ?? "BR"),
   });
🧹 Nitpick comments (22)
shopify/utils/transform.ts (2)

165-173: Use type guards instead of casts when reading metafield reference images

The current casts can hide shape issues at runtime. Narrow by checking for an image property on the union node to avoid undefined access.

-      const referenceImageUrl =
-        (reference as { image?: { url?: string } } | undefined)?.image?.url ?? null;
+      let referenceImageUrl: string | null = null;
+      const refAny = reference as unknown;
+      if (refAny && typeof refAny === "object" && "image" in refAny) {
+        referenceImageUrl =
+          (refAny as { image?: { url?: string } }).image?.url ?? null;
+      }
@@
-      const edgeImages = Array.isArray(references?.edges)
-        ? references.edges.map(
-            (edge) =>
-              (edge?.node as { image?: { url?: string } } | undefined)?.image
-                ?.url ?? null
-          )
-        : null;
+      const edgeImages = Array.isArray(references?.edges)
+        ? references.edges.map((edge) => {
+            const node = edge?.node as unknown;
+            if (node && typeof node === "object" && "image" in node) {
+              return (node as { image?: { url?: string } }).image?.url ?? null;
+            }
+            return null;
+          })
+        : null;

176-183: Joining multiple image URLs into a comma string can be brittle

Downstream code may expect a single string; comma-joining also makes parsing ambiguous. Consider serializing arrays as JSON strings for multi-image values, or add a separate field for images while preserving the original value.

If you choose JSON, a minimal change is:

-      const valueToReturn =
+      const valueToReturn =
         referenceImageUrl ??
         (validEdgeImages && validEdgeImages.length > 0
-          ? validEdgeImages.join(",")
+          ? JSON.stringify(validEdgeImages)
           : value);

Please confirm no consumer relies on comma-splitting today. I can scan usages of additionalProperty/PropertyValue.value to de-risk before changing.

shopify/loaders/proxy.ts (3)

63-64: Avoid substring match for route type selection

includes("sitemap") may misclassify unrelated paths (e.g., custom routes containing “sitemap”). Match only Shopify sitemap endpoints.

-          __resolveType: pathTemplate.includes("sitemap") ? "shopify/handlers/sitemap.ts" : "website/handlers/proxy.ts",
+          __resolveType: /^\/sitemap(\.xml.*|\/.*)$/i.test(pathTemplate)
+            ? "shopify/handlers/sitemap.ts"
+            : "website/handlers/proxy.ts",

127-134: Doc titles don’t match actual routes

  • Deco sitemap path is /sitemap/deco.xml (not /deco-sitemap.xml).
  • Shopify sitemap lives at /sitemap.xml (title says /shopify-sitemap.xml).
   /**
-   * @title If deco site map should be exposed at /deco-sitemap.xml
+   * @title If deco site map should be exposed at /sitemap/deco.xml
    */
@@
   /**
-   * @title Exclude paths from /shopify-sitemap.xml
+   * @title Exclude paths from /sitemap.xml
    */

6-25: Duplicate entry in PATHS_TO_PROXY

"/services/*" appears twice.

   "/services/*",
-  "/.well-known/*",
-  "/services/*",
+  "/.well-known/*",
shopify/utils/types.ts (1)

193-196: Make LanguageContextArgs optional to match GraphQL InputMaybe and improve reuse

Your queries pass defaults, but keeping these optional aligns with codegen types and lets other operations omit them without widening intersections.

-export interface LanguageContextArgs {
-  languageCode: LanguageCode;
-  countryCode: CountryCode;
-}
+export interface LanguageContextArgs {
+  languageCode?: LanguageCode;
+  countryCode?: CountryCode;
+}

Side note: CartBuyerIdentity.countryCode is a string in this file; consider CountryCode for consistency.

shopify/loaders/ProductList.ts (3)

16-18: Imports look good; consider aliasing Metafield to avoid name collision

Metafield here represents identifiers (namespace/key) while GraphQL also defines a Metafield type. Aliasing can reduce confusion.

-import { LanguageContextArgs, Metafield } from "../utils/types.ts";
+import { LanguageContextArgs, Metafield as MetafieldIdentifier } from "../utils/types.ts";

Then update type uses (metafields?: MetafieldIdentifier[]; and identifiers: metafields).

Also applies to: 26-26


75-87: Include locale in cacheKey to prevent cross-locale collisions

Even with cache = "no-cache" today, future changes or upstream caching could serve the wrong locale. Add languageCode/countryCode to cacheKey.

TypeScript snippet (outside the changed range) showing the minimal addition:

export const cacheKey = (expandedProps: Props, req: Request): string => {
  // ...existing code...
  const languageCode = expandedProps.languageCode ?? "PT";
  const countryCode = expandedProps.countryCode ?? "BR";
  searchParams.append("languageCode", languageCode);
  searchParams.append("countryCode", countryCode);
  // ...existing code...
}

109-111: Narrow types on defaults for stronger inference

Explicitly annotate to keep these as LanguageCode/CountryCode (not widened unions).

-const languageCode = expandedProps?.languageCode ?? "PT";
-const countryCode = expandedProps?.countryCode ?? "BR";
+const languageCode: LanguageCode = expandedProps.languageCode ?? "PT";
+const countryCode: CountryCode = expandedProps.countryCode ?? "BR";
shopify/loaders/ProductDetailsPage.ts (2)

22-34: Add locale to cacheKey to avoid mixing pages across locales

Slug-only cache keys risk serving the wrong localized PDP later if caching is enabled.

TypeScript snippet (outside the changed range):

export const cacheKey = (props: Props, req: Request): string => {
  const { slug } = props;
  const languageCode = props.languageCode ?? "PT";
  const countryCode = props.countryCode ?? "BR";
  const searchParams = new URLSearchParams({ slug, languageCode, countryCode });
  const url = new URL(req.url);
  url.search = searchParams.toString();
  return url.href;
};

46-47: Preserve literal types on defaults

Minor: explicitly annotate to keep these as the enum literal types.

-const { slug, languageCode = "PT", countryCode = "BR" } = props;
+const { slug } = props;
+const languageCode: LanguageCode = props.languageCode ?? "PT";
+const countryCode: CountryCode = props.countryCode ?? "BR";
shopify/loaders/shop.ts (2)

17-28: Document defaults on new locale props.

Add JSDoc @default tags so CMS/UI surfaces the implicit PT/BR defaults.

Apply:

   /**
    * @title Language Code
    * @description Language code for the storefront API
    * @example "EN" for English, "FR" for French, etc.
+   * @default "PT"
    */
   languageCode?: LanguageCode;
   /**
    * @title Country Code
    * @description Country code for the storefront API
    * @example "US" for United States, "FR" for France, etc.
+   * @default "BR"
    */
   countryCode?: CountryCode;

39-39: Default locale derivation.

Optional: derive defaults from ctx (storefront/shop defaults or request Accept-Language) to avoid surprising PT/BR fallback in non-BR stores.

shopify/loaders/ProductListingPage.ts (4)

74-86: Include locale in cache key or confirm no-cache.

If caching is enabled later, include languageCode/countryCode in cacheKey; otherwise different locales can collide. Current export sets cache="no-cache", but please confirm this won’t change.

Proposed cacheKey patch:

-  const searchParams = new URLSearchParams({
+  const searchParams = new URLSearchParams({
     count,
     query,
     page,
     endCursor,
     startCursor,
     sort,
+    languageCode: (props.languageCode ?? "PT"),
+    countryCode: (props.countryCode ?? "BR"),
   });

111-113: Locale defaults OK; consider specificity.

Minor: with countryCode "BR", using languageCode "PT_BR" may better match most Brazilian stores.


158-161: Handle edge cases in last-segment collection handle extraction.

Guard against trailing “collections” or “products” segments to avoid querying invalid handles.

Apply:

-const pathname = props.collectionName || url.pathname.split("/").filter(Boolean).pop();
+const segments = (props.collectionName
+  ? [props.collectionName]
+  : url.pathname.split("/").filter(Boolean));
+let pathname = segments.at(-1);
+if (pathname === "collections" || pathname === "products") {
+  pathname = segments.at(-2);
+}

227-227: Breadcrumb @id should be a page URL, not a Shopify GID.

Use a stable canonical URL so search engines can reconcile entities.

Apply:

-      "@id": collectionId,
+      "@id": isSearch ? url.href : `${url.origin}${url.pathname}`,
shopify/loaders/cart.ts (2)

30-35: Locale defaults OK; consider specificity.

Optional: prefer PT_BR when country BR to better align language/country.


34-45: Optional: normalize existing carts to new country.

If a cookie cart exists with a different buyerIdentity.countryCode than props.countryCode, consider issuing cartBuyerIdentityUpdate to keep pricing consistent with the chosen locale.

I can draft the mutation wiring if you want it added in this PR.

shopify/loaders/RelatedProducts.ts (2)

56-57: Consider sourcing defaults from config, not hardcoding "PT"/"BR"

If multiple shops/locales coexist, pulling defaults from a central config (or ctx) avoids drift.


63-69: Avoid intersecting generated variables with local types

GetProductQueryVariables and ProductRecommendationsQueryVariables already include identifiers, languageCode, and countryCode. The intersections with HasMetafieldsMetafieldsArgs and LanguageContextArgs unnecessarily tighten the contract (e.g., making optionals required) and can drift from the generated schema.

Apply:

-  const query = await storefront.query<
-    GetProductQuery,
-    GetProductQueryVariables & HasMetafieldsMetafieldsArgs & LanguageContextArgs
-  >({
+  const query = await storefront.query<
+    GetProductQuery,
+    GetProductQueryVariables
+  >({
     variables: { handle, identifiers: metafields, languageCode, countryCode },
     ...GetProduct,
   });

-  const data = await storefront.query<
-    ProductRecommendationsQuery,
-    ProductRecommendationsQueryVariables & HasMetafieldsMetafieldsArgs & LanguageContextArgs
-  >({
+  const data = await storefront.query<
+    ProductRecommendationsQuery,
+    ProductRecommendationsQueryVariables
+  >({
     variables: {
       productId: query.product.id,
       identifiers: metafields,
       languageCode,
       countryCode
     },
     ...ProductRecommendations,
   });

Also applies to: 75-87

shopify/utils/storefront/queries.ts (1)

273-282: CreateCart: optional

Returning only id is fine; consider adding buyerIdentity.countryCode if you plan to display locale-specific cart state immediately after creation.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8824dc7 and 5cc3c6d.

📒 Files selected for processing (11)
  • shopify/loaders/ProductDetailsPage.ts (4 hunks)
  • shopify/loaders/ProductList.ts (6 hunks)
  • shopify/loaders/ProductListingPage.ts (10 hunks)
  • shopify/loaders/RelatedProducts.ts (5 hunks)
  • shopify/loaders/cart.ts (1 hunks)
  • shopify/loaders/proxy.ts (6 hunks)
  • shopify/loaders/shop.ts (2 hunks)
  • shopify/utils/storefront/queries.ts (2 hunks)
  • shopify/utils/storefront/storefront.graphql.gen.ts (6 hunks)
  • shopify/utils/transform.ts (1 hunks)
  • shopify/utils/types.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (10)
shopify/utils/types.ts (1)
shopify/utils/storefront/storefront.graphql.gen.ts (2)
  • LanguageCode (3911-4199)
  • CountryCode (2138-2628)
shopify/loaders/shop.ts (2)
shopify/utils/types.ts (2)
  • Metafield (188-191)
  • LanguageContextArgs (193-196)
shopify/utils/storefront/storefront.graphql.gen.ts (3)
  • LanguageCode (3911-4199)
  • CountryCode (2138-2628)
  • ShopMetafieldsArgs (7233-7235)
shopify/loaders/RelatedProducts.ts (2)
shopify/utils/storefront/storefront.graphql.gen.ts (5)
  • LanguageCode (3911-4199)
  • CountryCode (2138-2628)
  • GetProductQueryVariables (7745-7750)
  • HasMetafieldsMetafieldsArgs (3752-3754)
  • ProductRecommendationsQueryVariables (7801-7806)
shopify/utils/types.ts (1)
  • LanguageContextArgs (193-196)
shopify/loaders/ProductDetailsPage.ts (2)
shopify/utils/storefront/storefront.graphql.gen.ts (4)
  • LanguageCode (3911-4199)
  • CountryCode (2138-2628)
  • GetProductQueryVariables (7745-7750)
  • HasMetafieldsMetafieldsArgs (3752-3754)
shopify/utils/types.ts (1)
  • LanguageContextArgs (193-196)
shopify/loaders/ProductListingPage.ts (2)
shopify/utils/storefront/storefront.graphql.gen.ts (2)
  • LanguageCode (3911-4199)
  • CountryCode (2138-2628)
shopify/utils/types.ts (1)
  • LanguageContextArgs (193-196)
shopify/loaders/cart.ts (3)
shopify/utils/storefront/storefront.graphql.gen.ts (6)
  • LanguageCode (3911-4199)
  • CountryCode (2138-2628)
  • GetCartQuery (7743-7743)
  • CreateCartMutation (7734-7734)
  • CreateCartMutationVariables (7729-7731)
  • GetCartQueryVariables (7736-7740)
shopify/utils/storefront/queries.ts (1)
  • CreateCart (272-282)
shopify/utils/types.ts (1)
  • LanguageContextArgs (193-196)
shopify/loaders/proxy.ts (2)
website/handlers/proxy.ts (1)
  • Props (44-89)
shopify/handlers/sitemap.ts (1)
  • Props (31-33)
shopify/loaders/ProductList.ts (2)
shopify/utils/storefront/storefront.graphql.gen.ts (5)
  • LanguageCode (3911-4199)
  • CountryCode (2138-2628)
  • QueryRoot (6476-6579)
  • QueryRootSearchArgs (6798-6810)
  • HasMetafieldsMetafieldsArgs (3752-3754)
shopify/utils/types.ts (1)
  • LanguageContextArgs (193-196)
shopify/utils/storefront/storefront.graphql.gen.ts (1)
wake/utils/graphql/storefront.graphql.gen.ts (7)
  • CreateCartMutationVariables (5028-5028)
  • Exact (12-12)
  • InputMaybe (11-11)
  • CreateCartMutation (5031-5031)
  • GetCartQueryVariables (5021-5023)
  • Scalars (18-33)
  • GetCartQuery (5026-5026)
shopify/utils/storefront/queries.ts (1)
shopify/utils/storefront/storefront.graphql.gen.ts (6)
  • Cart (527-578)
  • Product (5933-6018)
  • ProductVariant (6333-6386)
  • Collection (1881-1912)
  • Filter (3596-3605)
  • Customer (3022-3061)
🔇 Additional comments (22)
shopify/utils/storefront/storefront.graphql.gen.ts (3)

7725-7744: Verify that all GraphQL callers handle the new optional i18n variables
I didn’t find any direct references to the generated query hooks or documents (e.g. useGetCartQuery, GetCartDocument), so please manually confirm that every GraphQL call now provides the optional countryCode/languageCode arguments or correctly falls back to defaults.


7729-7731: Confirm CreateCart country scoping is actually used

CreateCartMutationVariables gained countryCode, but many implementations instead set buyerIdentity.countryCode in the input. Ensure the mutation or its wrapper applies the variable (via @inContext or input.buyerIdentity), otherwise it’s unused.

#!/bin/bash
rg -nP -C3 'CreateCartMutation\W' && rg -nP -C3 'cartCreate\W' shopify | sed -n '1,200p'

7862-7869: New CartBuyerIdentityUpdate mutation: wire through loaders and add basic error handling

Ensure a public function wraps this mutation and maps userErrors into your app’s error model. Also add a timeout/retry policy in the caller.

#!/bin/bash
rg -nP -C2 'CartBuyerIdentityUpdateMutation' &&
rg -nP -C2 'buyerIdentityUpdate' shopify
shopify/utils/types.ts (1)

7-7: LGTM: source-of-truth for locale enums

Importing LanguageCode and CountryCode from the generated GraphQL types removes drift risk vs hand-rolled enums. No concerns.

shopify/loaders/ProductList.ts (1)

141-142: Locale threading verified All storefront queries declare and use $languageCode and $countryCode with @inContext across search, collection, and recommendation paths.

shopify/loaders/ProductDetailsPage.ts (2)

9-11: Imports align with codegen and shared types

Bringing LanguageCode/CountryCode from codegen and LanguageContextArgs from utils is consistent with the rest of the PR.

Also applies to: 13-13


56-56: Approve locale variables usage

Verified that the GetProduct query in shopify/utils/storefront/queries.ts declares both $languageCode and $countryCode and applies them in the @incontext(language: $languageCode, country: $countryCode) directive.

shopify/loaders/shop.ts (2)

4-9: Imports look good.

Types are sourced from the generated schema and shared types. No issues.


41-47: Approve code changes

GetShopInfo query declares $languageCode and $countryCode and applies @incontext; the type intersection with ShopMetafieldsArgs & LanguageContextArgs is correct and future-proof.

shopify/loaders/ProductListingPage.ts (4)

133-145: Search query: locale variables threaded correctly.

Intersection with LanguageContextArgs looks good; variable bag is consistent.


167-168: Collection query: locale variables—LGTM.

Types and variable wiring are correct.

Also applies to: 177-179


192-192: Storing collectionId—LGTM.

Used later for breadcrumb; see note below on @id value.


230-230: Breadcrumb name derivation—LGTM.

Using the last path segment for non-search pages is reasonable.

shopify/loaders/cart.ts (3)

14-27: Props + docs—LGTM.

Public API looks clear and consistent with other loaders.


47-53: GetCart with locale—LGTM.

Variable typing via intersection ensures both codes are required at callsite.


55-55: Verify cookie encoding consistency.

We decode before querying and then write raw cartId back. Ensure getCartCookie/setCartCookie agree on encoding to avoid double-encoding or invalid IDs.

Run:

#!/bin/bash
rg -nC2 'getCartCookie|setCartCookie' shopify | sed -n '1,200p'
shopify/loaders/RelatedProducts.ts (2)

32-44: Props for locale look good

Optional props + docs read well.


18-19: Confirming Metafield aligns with GraphQL HasMetafieldsIdentifier; no changes needed. The Metafield interface (namespace: string; key: string) exactly matches the identifier shape expected by the query.

shopify/utils/storefront/queries.ts (4)

286-297: Consistent @incontext adoption across queries

Nice job threading languageCode/countryCode and moving to variable-based @inContext. This will play well with tooling and typed vars.

Also applies to: 301-313, 316-333, 335-379, 380-426, 428-442, 444-502


172-181: Cart fragment enrichment looks good

Including buyerIdentity.countryCode/email is useful for UI and pricing diagnostics.


506-513: Customer query doesn’t need @incontext

Fields returned aren’t localized; keeping it simple here makes sense.


528-556: Good UX: surface user errors

Explicitly returning customerUserErrors on registration and sign-in is 👍.

Also applies to: 608-623

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
shopify/handlers/sitemap.ts (3)

64-68: Use a resilient insertion anchor

Relying on an exact opening-tag string is brittle. Insert before the closing instead.

-    const finalXml = includeBlock
-      ? excludedXml.replace(XML_HEADER, `${XML_HEADER}\n${includeBlock}`)
-      : excludedXml;
+    const finalXml = includeBlock
+      ? excludedXml.replace("</sitemapindex>", `${includeBlock}\n</sitemapindex>`)
+      : excludedXml;

59-63: Simplify origin handling

URL.origin never ends with “/”; the extra normalization and the variable name are misleading.

-    const originWithSlash = reqOrigin.endsWith("/") ? reqOrigin.slice(0, -1) : reqOrigin;
-    const originReplacedXml = originalXml.replaceAll(shopifyUrl, originWithSlash);
+    const originReplacedXml = originalXml.replaceAll(shopifyUrl, reqOrigin);

38-38: Document exclude semantics

Add JSDoc to clarify expected values (path prefixes, leading “/”, examples).

 export interface Props {
   include?: string[];
-  exclude?: string[];
+  /** @description Path prefixes to remove from the Shopify sitemap index (e.g., "/sitemap_blogs", "/sitemap_pages"). Leading "/" optional. */
+  exclude?: string[];
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5cc3c6d and ce35c85.

📒 Files selected for processing (1)
  • shopify/handlers/sitemap.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
shopify/handlers/sitemap.ts (3)
shopify/mod.ts (2)
  • Props (13-41)
  • AppContext (10-10)
website/handlers/proxy.ts (2)
  • Props (44-89)
  • Proxy (94-235)
shopify/utils/password.ts (1)
  • withDigestCookie (3-9)
🔇 Additional comments (3)
shopify/handlers/sitemap.ts (3)

45-45: Signature change LGTM

Threading exclude into the handler signature looks good and is backward compatible.


50-56: Proxy integration looks correct

Forwarding digest cookie via customHeaders and preserving upstream headers/status is aligned with existing proxy behavior.


57-57: Early return on non-OK is appropriate

Avoids touching body/headers for error responses.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
shopify/handlers/sitemap.ts (1)

8-8: Remove unused TODAY constant.

The module-level TODAY constant is declared but never used. Line 13 correctly computes a fresh today value at runtime inside buildIncludeSitemaps, which is the proper approach to avoid staleness on long-lived workers.

Apply this diff to remove the unused constant:

 const XML_HEADER = '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
-const TODAY = new Date().toISOString().substring(0, 10);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ce35c85 and f0178dd.

📒 Files selected for processing (2)
  • shopify/handlers/sitemap.ts (1 hunks)
  • shopify/loaders/cart.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
shopify/loaders/cart.ts (3)
shopify/utils/storefront/storefront.graphql.gen.ts (6)
  • LanguageCode (3911-4199)
  • CountryCode (2138-2628)
  • GetCartQuery (7743-7743)
  • CreateCartMutation (7734-7734)
  • CreateCartMutationVariables (7729-7731)
  • GetCartQueryVariables (7736-7740)
shopify/utils/storefront/queries.ts (1)
  • CreateCart (272-282)
shopify/utils/types.ts (1)
  • LanguageContextArgs (193-196)
shopify/handlers/sitemap.ts (3)
shopify/mod.ts (2)
  • Props (13-41)
  • AppContext (10-10)
website/handlers/proxy.ts (2)
  • Props (44-89)
  • Proxy (94-235)
shopify/utils/password.ts (1)
  • withDigestCookie (3-9)
🪛 ast-grep (0.39.5)
shopify/handlers/sitemap.ts

[warning] 14-17: Manual HTML sanitization detected using string replacement methods. Manual sanitization is error-prone and can be bypassed. Use dedicated HTML sanitization libraries like 'sanitize-html' or 'DOMPurify' instead.
Context: s
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
- https://cwe.mitre.org/data/definitions/79.html

(manual-html-sanitization)


[warning] 14-16: Manual HTML sanitization detected using string replacement methods. Manual sanitization is error-prone and can be bypassed. Use dedicated HTML sanitization libraries like 'sanitize-html' or 'DOMPurify' instead.
Context: s
.replaceAll("&", "&")
.replaceAll("<", "<")
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
- https://cwe.mitre.org/data/definitions/79.html

(manual-html-sanitization)

🪛 Biome (2.1.2)
shopify/loaders/cart.ts

[error] 39-39: Expected an expression but instead found 'const'.

Expected an expression here.

(parse)


[error] 39-39: Shouldn't redeclare 'cartId'. Consider to delete it or rename it.

'cartId' is defined here:

(lint/suspicious/noRedeclare)

🪛 GitHub Actions: ci
shopify/loaders/cart.ts

[error] 39-39: Deno fmt failed: Expression expected at cart.ts:39:3 during 'deno task check'.

🔇 Additional comments (8)
shopify/loaders/cart.ts (4)

14-27: LGTM! Well-documented Props interface.

The Props interface is well-structured with clear JSDoc annotations and examples. The optional nature of both properties maintains backward compatibility.


30-30: LGTM! Loader signature correctly accepts Props.

The signature change from _props: unknown to props: Props properly enables typed access to the new locale parameters.


34-34: LGTM! Locale defaults are consistent with PR objectives.

The default values (PT/BR) align with the stated internationalization strategy and the pattern used across other loaders in this PR.


49-55: LGTM! GetCart query properly includes locale context.

The query correctly extends GetCartQueryVariables with LanguageContextArgs and passes all required variables including the new locale parameters. The typing is explicit and correct.

shopify/handlers/sitemap.ts (4)

10-29: LGTM! XML escaping and fresh timestamp correctly implemented.

The function properly addresses previous review concerns:

  • Computes today fresh at runtime (line 13) to avoid staleness
  • Correctly escapes XML entities in proper order (& first, lines 14-20)
  • Uses escaped URLs in <loc> elements (line 25)

Note: The static analysis warning about "manual HTML sanitization" is a false positive. This code performs standard XML entity escaping for sitemap <loc> elements, which is the correct approach for this use case. The escaping sequence properly handles all required XML entities.


31-53: LGTM! Robust URL handling and prefix normalization.

The function correctly implements all previously requested improvements:

  • Normalizes exclude prefixes to ensure they start with "/" (line 35)
  • Safely parses URLs with try-catch, using origin as base to support both absolute and relative URLs (lines 41-44)
  • Falls back gracefully on parse errors, leaving entries untouched (lines 45-47)
  • Uses normalized prefixes for consistent matching (line 50)

55-58: LGTM! Clean API extension.

The exclude property follows the same pattern as include, maintaining consistency and backward compatibility.


63-101: LGTM! Proper header handling and clean XML pipeline.

The implementation correctly addresses the previous header passthrough concerns:

  • Response headers are cloned (line 88)
  • Body-specific headers are removed to prevent mismatches (lines 89-92): content-length, content-encoding, etag, accept-ranges
  • Content-type is set appropriately for XML (lines 93-95)

The XML processing pipeline is well-structured:

  1. Proxy to Shopify
  2. Replace origin URLs (line 80)
  3. Apply exclusions (line 81)
  4. Inject inclusions (lines 84-86)

The origin normalization (line 79) correctly handles trailing slashes.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
shopify/utils/storefront/storefront.graphql.gen.ts (1)

7736-7750: Remove duplicate CartFragment type alias at line 7737

Verification confirms two consecutive export type CartFragment declarations exist at lines 7736–7737. TypeScript does not permit duplicate type alias exports in the same module—the second declaration will cause a compile error and shadow the first.

Keep the definition at line 7736 (which includes buyerIdentity) and remove the second definition starting at line 7737.

♻️ Duplicate comments (1)
shopify/loaders/ProductListingPage.ts (1)

112-113: Verify the hardcoded locale defaults are appropriate.

The defaults "PT"/"BR" (Portuguese/Brazil) are hardcoded, same as in ProductList.ts. Ensure these defaults align with your primary market and consider whether they should be configurable at the application level.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0220c31 and 1110e3a.

📒 Files selected for processing (3)
  • shopify/loaders/ProductList.ts (6 hunks)
  • shopify/loaders/ProductListingPage.ts (11 hunks)
  • shopify/utils/storefront/storefront.graphql.gen.ts (7 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
shopify/utils/storefront/storefront.graphql.gen.ts (1)
wake/utils/graphql/storefront.graphql.gen.ts (8)
  • CreateCartMutationVariables (5028-5028)
  • Exact (12-12)
  • InputMaybe (11-11)
  • CreateCartMutation (5031-5031)
  • GetCartQueryVariables (5021-5023)
  • Scalars (18-33)
  • GetCartQuery (5026-5026)
  • GetProductQueryVariables (5012-5016)
shopify/loaders/ProductList.ts (2)
shopify/utils/storefront/storefront.graphql.gen.ts (4)
  • LanguageCode (3911-4199)
  • CountryCode (2138-2628)
  • QueryRootSearchArgs (6798-6810)
  • HasMetafieldsMetafieldsArgs (3752-3754)
shopify/utils/types.ts (1)
  • LanguageContextArgs (196-199)
shopify/loaders/ProductListingPage.ts (3)
shopify/utils/storefront/storefront.graphql.gen.ts (7)
  • LanguageCode (3911-4199)
  • CountryCode (2138-2628)
  • QueryRootSearchArgs (6798-6810)
  • HasMetafieldsMetafieldsArgs (3752-3754)
  • QueryRoot (6476-6579)
  • QueryRootCollectionArgs (6638-6641)
  • CollectionProductsArgs (1951-1959)
shopify/utils/types.ts (1)
  • LanguageContextArgs (196-199)
shopify/utils/utils.ts (2)
  • searchSortShopify (39-55)
  • sortShopify (57-92)
🪛 GitHub Actions: ci
shopify/loaders/ProductListingPage.ts

[error] 12-12: Deno lint: 'Product' is defined but never used. (no-unused-vars)

🪛 GitHub Check: Bundle & Check Apps (ubuntu-latest)
shopify/loaders/ProductList.ts

[failure] 12-12:
�[0m�[1mProductShopify is never used

shopify/loaders/ProductListingPage.ts

[failure] 12-12:
�[0m�[1mProduct is never used

🔇 Additional comments (11)
shopify/loaders/ProductList.ts (4)

76-87: LGTM!

The new optional locale props are well-documented with clear examples and maintain backward compatibility.


110-111: Verify the hardcoded locale defaults are appropriate.

The defaults "PT"/"BR" (Portuguese/Brazil) are hardcoded. Ensure these defaults align with your primary market and consider whether they should be configurable at the application level rather than hardcoded in the loader.

If these defaults need to be more flexible, consider accepting them from the app context or configuration:

const languageCode = expandedProps?.languageCode ?? ctx.defaultLanguageCode ?? "EN";
const countryCode = expandedProps?.countryCode ?? ctx.defaultCountryCode ?? "US";

141-150: LGTM!

The locale context is correctly threaded through the search query with proper type safety.


161-170: LGTM!

The locale context is correctly threaded through the collection query with proper type safety, maintaining consistency with the search path.

shopify/loaders/ProductListingPage.ts (6)

75-86: LGTM!

The new optional locale props are well-documented and maintain backward compatibility.


144-147: LGTM!

The locale context is correctly threaded through, and the safe spread pattern for the sort mapping (line 146) properly addresses the previous review feedback.


179-182: LGTM!

The locale context is correctly threaded through, and the safe spread pattern for the sort mapping (line 181) properly addresses the previous review feedback.


194-194: LGTM!

Capturing the collection ID enables proper entity identification in the breadcrumb.


232-242: LGTM with a note on the TODO.

The breadcrumb now includes the collection ID and uses consistent pathname extraction logic (last segment). The TODO comment on line 232 suggests this area may need further enhancement for multi-level paths, but the current changes are a step in the right direction.

Note: The @id field on BreadcrumbList is not standard schema.org. If you're using this for internal tracking, that's fine, but be aware it may not validate against schema.org specifications.


159-162: Verify collection path handling works with existing URLs and fix incomplete TODO.

The pathname extraction change is intentional (documented in comments) and consistent, but verification reveals incomplete work. Line 232 has a TODO comment indicating the breadcrumb logic still needs updating for multi-level paths. Manually test that existing single and multi-level collection URLs resolve correctly, and address the breadcrumb TODO before merging.

shopify/utils/storefront/storefront.graphql.gen.ts (1)

7754-7898: i18n variables threading looks consistent and backward‑compatible

The updates to:

  • CreateCartMutationVariables (new optional countryCode?: InputMaybe<CountryCode>)
  • GetCartQueryVariables (new optional languageCode? / countryCode?)
  • GetProductQueryVariables
  • ListProductsQueryVariables
  • SearchWithFiltersQueryVariables
  • AllProductsQueryVariables
  • ProductRecommendationsQueryVariables
  • GetShopInfoQueryVariables

all follow the same pattern: languageCode?: InputMaybe<LanguageCode> and/or countryCode?: InputMaybe<CountryCode> as optional fields. This is type-safe and backward‑compatible ({} still satisfies these types) and matches the PR goal of powering @inContext and cart localization via variables.

Just ensure the underlying .graphql documents and any codegen pipeline were the source of these changes so the operation signatures and server schema stay in sync.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
shopify/loaders/ProductList.ts (1)

192-227: Critical: Cache key missing languageCode and countryCode.

The cacheKey function doesn't include languageCode or countryCode in the cache key, causing products fetched with different locales to incorrectly share the same cache entry. For example, a request for English/US products would be cached, and a subsequent French/France request would receive the cached English/US products.

Apply this diff to include locale in the cache key:

 export const cacheKey = (expandedProps: Props, req: Request): string => {
   const props = expandedProps.props ??
     (expandedProps as unknown as Props["props"]);

   const count = (props.count ?? 12).toString();
   const sort = props.sort ?? "";
+  const languageCode = expandedProps?.languageCode ?? "PT";
+  const countryCode = expandedProps?.countryCode ?? "BR";
   const searchParams = new URLSearchParams({
     count,
     sort,
+    languageCode,
+    countryCode,
   });

   expandedProps.filters?.tags?.forEach((tag) => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1110e3a and fff74a8.

📒 Files selected for processing (3)
  • shopify/loaders/ProductList.ts (6 hunks)
  • shopify/loaders/ProductListingPage.ts (11 hunks)
  • shopify/utils/storefront/storefront.graphql.gen.ts (12 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • shopify/loaders/ProductListingPage.ts
🧰 Additional context used
🧬 Code graph analysis (2)
shopify/loaders/ProductList.ts (2)
shopify/utils/storefront/storefront.graphql.gen.ts (4)
  • LanguageCode (3911-4199)
  • CountryCode (2138-2628)
  • QueryRootSearchArgs (6798-6810)
  • HasMetafieldsMetafieldsArgs (3752-3754)
shopify/utils/types.ts (1)
  • LanguageContextArgs (196-199)
shopify/utils/storefront/storefront.graphql.gen.ts (2)
wake/utils/graphql/storefront.graphql.gen.ts (9)
  • CreateCartMutationVariables (5028-5028)
  • Exact (12-12)
  • InputMaybe (11-11)
  • CreateCartMutation (5031-5031)
  • GetCartQueryVariables (5021-5023)
  • Scalars (18-33)
  • GetCartQuery (5026-5026)
  • AddItemToCartMutation (5075-5075)
  • AddCouponMutation (5068-5068)
vtex/utils/types.ts (1)
  • FilterType (901-901)
🔇 Additional comments (8)
shopify/utils/storefront/storefront.graphql.gen.ts (5)

7736-7749: CartFragment: buyerIdentity projection looks consistent and non-breaking

Including buyerIdentity with { countryCode?: CountryCode | null; email?: string | null } in CartFragment matches the CartBuyerIdentity shape and is correctly threaded through cart types. This is additive only and should be backwards compatible for all existing fragment consumers.


7760-7764: Locale args on query variable types are well-threaded and backward compatible

Adding optional languageCode?: InputMaybe<LanguageCode> and countryCode?: InputMaybe<CountryCode> to GetCartQueryVariables, GetProductQueryVariables, ListProductsQueryVariables, SearchWithFiltersQueryVariables, AllProductsQueryVariables, ProductRecommendationsQueryVariables, and GetShopInfoQueryVariables cleanly exposes locale context without breaking existing callers (all new fields are optional). The types line up with the LanguageCode and CountryCode enums defined earlier in this file.

Also applies to: 7783-7787, 7803-7810, 7826-7838, 7857-7869, 7885-7890, 7906-7910


7872-7883: AllProductsQuery: expanded collection surface is coherent

Extending AllProductsQuery so collection now exposes id, handle, description, and title (in addition to products) matches the Collection type definition and should simplify callers that need collection metadata (e.g., breadcrumbs, SEO, sitemap) alongside products. The added fields are read-only and won’t affect existing product consumers.


7934-7947: Cart mutations now returning buyerIdentity + new CartBuyerIdentityUpdateMutation look correct

  • AddItemToCartMutation, AddCouponMutation, and UpdateItemsMutation payloads now include buyerIdentity: { countryCode?: CountryCode | null; email?: string | null } on the returned cart, consistent with the updated CartFragment.
  • CartBuyerIdentityUpdateMutationVariables and CartBuyerIdentityUpdateMutation correctly mirror CartBuyerIdentityInput and CartBuyerIdentityUpdatePayload (cart plus userErrors { field, message }), and reuse the same cart projection as other cart mutations.

These are additive result-shape changes and a new mutation type, so they shouldn’t break existing consumers while enabling the new buyer identity flow.

Also applies to: 7966-7979, 7987-8000, 8002-8021


7753-7755: The review comment makes an incorrect recommendation and should be disregarded.

The CreateCart mutation (line 274 in queries.ts) only accepts $countryCode and does not reference $languageCode anywhere. Adding languageCode to CreateCartMutationVariables would create an unused parameter, which violates GraphQL best practices.

The apparent "inconsistency" with GetCart is by design:

  • GetCart uses @inContext(language: $languageCode, country: $countryCode) to enrich query results, so it requires both variables.
  • CreateCart calls cartCreate(input: { buyerIdentity: { countryCode: $countryCode } }) and only needs country context.
  • Other mutations (AddItemToCart, AddCoupon, UpdateItems, etc.) follow the same pattern: each accepts only the variables it uses.

The generated types correctly reflect the actual GraphQL operation signatures.

Likely an incorrect or invalid review comment.

shopify/loaders/ProductList.ts (3)

75-86: LGTM! Well-documented internationalization props.

The new optional languageCode and countryCode props are well-documented with clear examples and maintain backward compatibility.


138-153: LGTM! Locale variables correctly passed to search query.

The LanguageContextArgs type extension and variable passing are implemented correctly for the search-based query path.


155-175: LGTM! Locale variables correctly passed to collection query.

The LanguageContextArgs type extension and variable passing are implemented correctly for the collection-based query path, consistent with the search query implementation.

Comment on lines +109 to +110
const languageCode = expandedProps?.languageCode ?? "PT";
const countryCode = expandedProps?.countryCode ?? "BR";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Verify the hardcoded Portuguese/Brazil defaults.

The defaults to "PT" (Portuguese) and "BR" (Brazil) may not be appropriate for all Shopify storefronts. Consider whether these should:

  • Default to undefined to let Shopify use the storefront's default locale
  • Be configurable at the app/store level
  • Have a documented business reason for the PT/BR choice

Hardcoded locale defaults could deliver incorrect localized content to international users.

Would you like to verify if there's a specific reason for the PT/BR defaults, or should these default to undefined instead?


🏁 Script executed:

#!/bin/bash
# Examine ProductList.ts file context around lines 109-110
cat shopify/loaders/ProductList.ts | head -130 | tail -50

Length of output: 1425


🏁 Script executed:

#!/bin/bash
# Search for expandedProps initialization and definition
rg -n "expandedProps" shopify/loaders/ProductList.ts -B5 -A5

Length of output: 2856


🏁 Script executed:

#!/bin/bash
# Search for any configuration or settings related to languageCode/countryCode
rg -n "languageCode|countryCode" shopify/loaders/ProductList.ts -B3 -A3

Length of output: 1177


🏁 Script executed:

#!/bin/bash
# Look for environment variables or config files that might set these defaults
fd -e "config\|env\|settings" -type f | head -20

Length of output: 170


🏁 Script executed:

#!/bin/bash
# Search for comments or documentation about PT/BR choice in the file
rg -n "PT|BR|Portuguese|Brazil|locale|language|country" shopify/loaders/ProductList.ts -B2 -A2

Length of output: 850


🏁 Script executed:

#!/bin/bash
# Search for README, docs, or comments explaining the PT/BR choice
find . -maxdepth 2 -type f \( -name "README*" -o -name "*.md" \) | xargs grep -l "PT\|BR\|Portuguese\|Brazil\|locale\|language\|country" 2>/dev/null | head -10

Length of output: 109


🏁 Script executed:

#!/bin/bash
# Search entire codebase for any configuration or context about locale defaults
rg -n "languageCode.*PT|countryCode.*BR|PT.*BR" --type-add "config:*.{json,yaml,yml,toml,env}" -t config -t ts -t js 2>/dev/null | head -20

Length of output: 92990


🏁 Script executed:

#!/bin/bash
# Check if there's an AppContext or global config that might set these
rg -n "AppContext|LanguageCode|CountryCode" shopify/ -l | head -10

Length of output: 299


Document or reconfigure the hardcoded PT/BR locale defaults.

The defaults for languageCode="PT" and countryCode="BR" are hardcoded with no documented business reason or configuration mechanism. While the interface design suggests these should be optional and configurable, there's no way for app or store-level settings to override them. This will cause incorrect localized content for non-Brazilian storefronts.

Either:

  • Add a config/environment way to override these defaults
  • Change defaults to undefined and rely on Shopify's storefront settings
  • Document why PT/BR is the required default for your use case

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant