Skip to content

Conversation

@sitammeur
Copy link
Contributor

@sitammeur sitammeur commented Jan 8, 2026

Summary by CodeRabbit

  • New Features
    • Full Amazon product analysis widget with rich UI: product card, image gallery (zoom/navigation), pricing/deal assessment, features, specs, delivery, seller info, and customer review highlights.
    • Server APIs: image proxy and product analysis endpoint backed by BrightData/OpenAI, plus a client hook for easy data fetching.
  • Documentation
    • Added comprehensive README with setup, usage, and troubleshooting.
  • Chores
    • Project scaffolding: package config, env template, .gitignore, TypeScript config.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

📝 Walkthrough

Walkthrough

Adds a new MCP server and React widget for Amazon product analysis: server entrypoint with image proxy and analysis endpoint, Bright Data integration, OpenAI orchestration, Zod schemas, a React hook, eight UI components, styles, build/config files, and documentation.

Changes

Cohort / File(s) Summary
Project config & metadata
amazon-product-analysis-server/.env.example, amazon-product-analysis-server/.gitignore, amazon-product-analysis-server/tsconfig.json, amazon-product-analysis-server/package.json, amazon-product-analysis-server/README.md
New env template and .gitignore; TypeScript config; package.json with scripts/deps; and a full README.
Server entrypoint & endpoints
amazon-product-analysis-server/index.ts
New MCP server bootstrap, /api/image-proxy with Amazon host whitelist and proxying, /api/analyze-amazon-product delegating to analyzeAmazonProduct, Brand Info tool, and error handling/logging.
Bright Data integration
resources/amazon-product-analysis/brightdata-tools.ts
Factory brightDataTools(config) creating a BrightData client and an amazonProduct tool with input schema and execute logic; supports tool exclusion.
Product analysis orchestration (server)
resources/amazon-product-analysis/server.ts
Exports analyzeAmazonProduct(url, zipcode?) that invokes BrightData tooling and OpenAI helpers (generateText/generateObject) to produce and validate ProductAnalysisData.
Schemas & types
resources/amazon-product-analysis/types.ts
Zod input/output schemas and exported types: ProductAnalysisData, Specification, DeliveryOption, SellerInfo, Ranking, and the input props schema.
Utilities & hooks
resources/amazon-product-analysis/utils.ts, resources/amazon-product-analysis/hooks/useProductAnalysis.ts, resources/amazon-product-analysis/hooks/index.ts
getProxiedImageUrl helper to map Amazon images to MCP proxy; useProductAnalysis React hook (react-query) calling /api/analyze-amazon-product; barrel export for the hook.
Widget, styling & metadata
resources/amazon-product-analysis/widget.tsx, resources/styles.css
Widget component using QueryClientProvider and useProductAnalysis; widgetMetadata export; Tailwind/OpenAI UI and carousel styles.
UI components (barrel)
resources/amazon-product-analysis/components/index.ts
Barrel file exporting the eight new UI components.
UI components (individual)
resources/amazon-product-analysis/components/*
ProductCard.tsx, PricingDeal.tsx, Features.tsx, ImageGallery.tsx, ProductSpecs.tsx, DeliveryInfo.tsx, CustomerReviews.tsx, SellerInfo.tsx
Eight presentational components: product card, pricing/deal assessment, feature badges with truncation, proxied image gallery with zoom, specs with dedupe/priority ordering, delivery info with badges, customer reviews with toggle, and seller/rankings UI.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Widget (Browser)
    participant MCP as MCP Server
    participant BD as BrightData
    participant OpenAI as OpenAI

    Client->>MCP: GET /api/analyze-amazon-product?url=...&zipcode=...
    MCP->>BD: amazonProduct.collectProducts({ url, zipcode })
    BD-->>MCP: Raw product data (JSON)
    MCP->>OpenAI: generateText / generateObject with raw data + schema
    OpenAI-->>MCP: Structured ProductAnalysisData
    MCP->>MCP: Validate/map to Zod schema
    MCP-->>Client: 200 ProductAnalysisData (JSON)
    Client->>Client: Render components (ProductCard, ImageGallery, PricingDeal, etc.)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Poem

🐰 I hopped through lines of code and clay,

BrightData dug while OpenAI had its say,
Images proxied, specs arranged with care,
Widgets bloom with deals and reviews to share,
A joyful hop—product stories in the air!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Add Amazon Product Analysis MCP Server' accurately summarizes the main change—it introduces a complete MCP server implementation for Amazon product analysis with multiple components, utilities, and configuration files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

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: 12

🤖 Fix all issues with AI agents
In @amazon-product-analysis-server/.env.example:
- Around line 1-2: Add a POSIX-compliant trailing newline to the end of the
environment example by ensuring the file finishes with a blank line after the
last variable (after the OPENAI_API_KEY line); simply append a single newline
character so the file ends with an empty line following BRIGHTDATA_API_KEY and
OPENAI_API_KEY.

In @amazon-product-analysis-server/.gitignore:
- Line 43: tsconfig.json currently includes "script.ts" in its "include" array
although that file is ignored and absent; open tsconfig.json, remove "script.ts"
from the "include" array (the string "script.ts") so TypeScript isn't configured
to compile a non-existent/ignored file and save the updated tsconfig.json.

In @amazon-product-analysis-server/index.ts:
- Around line 28-80: The hostname check in the image proxy (server.get handler)
is vulnerable because url.hostname.includes(host) allows crafted hostnames like
evil-m.media-amazon.com.attacker.com; update the validation in the handler that
builds allowedHosts to instead normalize url.hostname to lowercase and check for
exact matches (hostname === host) or proper subdomain suffixes using
hostname.endsWith('.' + host) for entries that should allow subdomains (e.g.,
"media-amazon.com"), and remove the includes(...) usage across the validation
logic (refer to url.hostname and allowedHosts in the image-proxy route).

In
@amazon-product-analysis-server/resources/amazon-product-analysis/brightdata-tools.ts:
- Around line 24-33: The inputSchema's url field currently only checks it's a
valid URL but not that the path contains Amazon product indicators; update the
url validator (the z.object inputSchema -> url field) to include an additional
check (z.refine or regex) that the URL path includes either "/dp/" or
"/gp/product/" (you can test either against the full string or by parsing new
URL(url).pathname) and return a clear validation message if it fails so the
schema matches its description.
- Around line 34-47: The catch in the execute async function currently returns
the raw error string (exposing internals); change it to log the full error
details internally (e.g., console.error or processLogger) when
client.datasets.amazon.collectProducts fails, then return a sanitized, generic
error message to the caller such as "Error fetching Amazon product data"
(optionally with a non-sensitive error code). Keep the JSON result return path
intact and ensure the catch does not include sensitive info like API keys, stack
traces, or file paths.
- Around line 15-18: Replace the hardcoded autoCreateZones:true when
instantiating bdclient with a configurable option on BrightDataToolsConfig so
callers can opt in/out; update the constructor or factory that builds bdclient
(the code creating new bdclient({...})) to read config.autoCreateZones
(defaulting to false or to current behavior) and pass that value through, and
add a brief comment near BrightDataToolsConfig and the bdclient instantiation
explaining why automatic zone creation is used and the potential
$5/month-per-zone cost and bandwidth/IP charges so reviewers can choose explicit
pre-provisioning instead of automatic provisioning.

In
@amazon-product-analysis-server/resources/amazon-product-analysis/components/CustomerReviews.tsx:
- Around line 84-87: The UI is rendering a hardcoded five-star display; update
the CustomerReviews component to read the actual rating from topReview (e.g.,
topReview.rating) and render that many filled StarIcon components (and
optionally remaining empty/outlined stars) instead of always mapping
[...Array(5)]; modify the JSX that currently maps StarIcon to use the rating
value (or a new rating prop) so the visual stars reflect the actual numeric
score.

In
@amazon-product-analysis-server/resources/amazon-product-analysis/components/PricingDeal.tsx:
- Around line 196-215: The discount string format is undocumented and the
current parsing in PricingDeal (safeDiscount -> savingsPercent using Math.abs)
silently turns negative discounts (price increases) into positive savings;
update documentation/comments for the discount prop to state accepted formats
(e.g., "20%", "20", "-5%") and change the parsing flow in the PricingDeal
component: remove Math.abs, normalize the string by stripping
non-numeric/decimal/sign characters, use parseFloat to get a signed percentage
(allow negatives), handle NaN by defaulting to 0, and pass that signed
savingsPercent into categorizeDeal (or branch to treat negative percentages as
price increases—e.g., set safeSavings or a flag) so price increases are not
misrepresented as discounts; reference functions/vars: PricingDeal,
safeDiscount, savingsPercent, safeSavings, safeInitialPrice, categorizeDeal, and
isGoodDealOrBetter when making these changes.
- Around line 217-297: The Tailwind utility classes used in PricingDeal.tsx
(bg-surface, border-default, text-default, text-secondary, bg-surface-elevated)
are not defined in the project's Tailwind theme; update the Tailwind
configuration (open-agent-builder/tailwind.config.ts) to either add these custom
color tokens under theme.extend.colors or ensure the
amazon-product-analysis-server directory is included in the config's content
paths so its styles.css @apply usages are picked up, then define the
corresponding color keys (surface, surface-elevated, default, secondary,
border-default, etc.) matching the design system names so the classes referenced
in PricingDeal.tsx and resources/styles.css resolve correctly.

In
@amazon-product-analysis-server/resources/amazon-product-analysis/components/ProductCard.tsx:
- Around line 14-49: StarIcon uses a hard-coded gradient id ("halfStar") which
causes SVG ID collisions when multiple StarIcon(half=true) instances render;
update the StarIcon component to generate a unique gradient id (e.g., via
React's useId() or a per-instance unique string) and replace the hard-coded id
and the path's fill reference (fill="url(#halfStar)") with that unique id so
each instance renders its own gradient; ensure the generated id is used both in
<linearGradient id={gradientId}> and in the corresponding path's fill attribute.

In @amazon-product-analysis-server/resources/amazon-product-analysis/server.ts:
- Around line 7-9: The code uses process.env.BRIGHTDATA_API_KEY! directly when
creating bdTools via brightDataTools; add a pre-check that validates
process.env.BRIGHTDATA_API_KEY is present and non-empty before calling
brightDataTools, and if missing throw an explicit Error or log a clear message
and exit so the failure is fast and informative; update the bdTools
initialization to use the validated value (referencing bdTools and
brightDataTools and the env var name BRIGHTDATA_API_KEY).

In @amazon-product-analysis-server/tsconfig.json:
- Around line 19-21: Remove the unused "@/*" path alias from the "paths" section
in tsconfig.json (the "paths": { "@/*": ["src/*"] } entry) and also remove the
non-existent "src/**/*" entry from the "include" array; if the "paths" object
becomes empty after removal, delete the entire "paths" section to keep
tsconfig.json clean.
🧹 Nitpick comments (17)
amazon-product-analysis-server/resources/styles.css (1)

75-93: Consider performance impact of heavy filter effects.

The carousel background layer applies multiple intensive filter operations (blur(28px) saturate(5) brightness(1.3)) combined with 3D transforms and dynamic calc() expressions tied to pointer position. While visually impressive, this could impact performance on lower-end devices or when multiple carousel items are rendered.

Consider adding a @media (prefers-reduced-motion: reduce) query to simplify or disable these effects for users who prefer reduced motion, or test performance with multiple carousel instances.

♻️ Optional: Add reduced motion support
+@media (prefers-reduced-motion: reduce) {
+  .carousel-item-bg {
+    filter: blur(28px) saturate(2) brightness(1.1);
+    transition: none;
+  }
+}
amazon-product-analysis-server/package.json (2)

39-39: Move node-mocks-http to devDependencies.

node-mocks-http is a testing utility and should not be shipped with production dependencies.

Suggested fix
  "dependencies": {
    "@ai-sdk/openai": "^2.0.89",
    "@brightdata/sdk": "^0.2.0",
    "@openai/apps-sdk-ui": "^0.2.1",
    "@tanstack/react-query": "^5.90.12",
    "ai": "^5.0.118",
    "cors": "^2.8.5",
    "dotenv": "^17.2.3",
    "express": "^5.2.1",
    "mcp-use": "^1.12.1",
-   "node-mocks-http": "^1.17.2",
    "react": "^19.2.3",
    "react-dom": "^19.2.3",
    "react-router": "^7.10.1",
    "tailwindcss": "^4.1.18",
    "zod": "^4.2.0"
  },
  "devDependencies": {
    "@tailwindcss/vite": "^4.1.18",
    "@types/node": "^25.0.3",
    "@vitejs/plugin-react": "^5.1.2",
+   "node-mocks-http": "^1.17.2",
    "tsx": "^4.21.0",
    "typescript": "^5.9.3",
    "vite": "^7.3.0"
  },

46-53: Add missing TypeScript type definitions for express and cors.

Both express (^5.2.1) and cors (^2.8.5) are in dependencies and require TypeScript type packages for proper type support.

Suggested additions
  "devDependencies": {
    "@tailwindcss/vite": "^4.1.18",
    "@types/node": "^25.0.3",
+   "@types/cors": "^2.8.19",
+   "@types/express": "^5.0.3",
    "@vitejs/plugin-react": "^5.1.2",
    "tsx": "^4.21.0",
    "typescript": "^5.9.3",
    "vite": "^7.3.0"
  },
amazon-product-analysis-server/resources/amazon-product-analysis/utils.ts (1)

27-29: Minor: Redundant hostname check.

The url.hostname.endsWith(".media-amazon.com") check is redundant since amazonHosts already includes ".media-amazon.com" which will match via url.hostname.includes(host).

Simplified check
         const isAmazonImage = amazonHosts.some(
-            (host) => url.hostname.includes(host) || url.hostname.endsWith(".media-amazon.com")
+            (host) => url.hostname.includes(host)
         );
amazon-product-analysis-server/resources/amazon-product-analysis/hooks/useProductAnalysis.ts (1)

19-23: Handle potential trailing slash in mcpUrl and JSON parsing errors.

Two edge cases to consider:

  1. If mcpUrl ends with /, the constructed URL becomes https://example.com//api/...
  2. If the error response body is not valid JSON, response.json() will throw an unhelpful error
Suggested improvement
       const params = new URLSearchParams({ url: url! });
       if (zipcode) params.append("zipcode", zipcode);

-      const response = await fetch(`${mcpUrl}/api/analyze-amazon-product?${params}`);
+      const baseUrl = mcpUrl!.endsWith("/") ? mcpUrl!.slice(0, -1) : mcpUrl;
+      const response = await fetch(`${baseUrl}/api/analyze-amazon-product?${params}`);
       if (!response.ok) {
-        const errorData = await response.json();
-        throw new Error(errorData.error || "Failed to analyze product");
+        let errorMessage = "Failed to analyze product";
+        try {
+          const errorData = await response.json();
+          errorMessage = errorData.error || errorMessage;
+        } catch {
+          // Response body is not JSON, use default message
+        }
+        throw new Error(errorMessage);
       }
       return response.json();
amazon-product-analysis-server/resources/amazon-product-analysis/server.ts (1)

15-66: Add error handling for external API calls.

The generateText and generateObject calls can fail due to network issues, rate limits, or API errors. Without error handling, failures will propagate with potentially unclear messages.

Suggested improvement
 export async function analyzeAmazonProduct(
     url: string,
     zipcode?: string
 ): Promise<ProductAnalysisData> {
+    try {
         // Step 1: Fetch product data using brightDataTools (same as script.ts)
         const fetchResult = await generateText({
             // ... existing config
         });

         // Step 2: Structure data for widgets (same as script.ts)
         const result = await generateObject({
             // ... existing config
         });

         return result.object;
+    } catch (error) {
+        const message = error instanceof Error ? error.message : String(error);
+        throw new Error(`Failed to analyze Amazon product: ${message}`);
+    }
 }
amazon-product-analysis-server/resources/amazon-product-analysis/components/Features.tsx (1)

28-46: Consider edge case handling in text truncation.

The regex /^[^.!?]*[.!?]/ will match very short sentences (even a single character followed by punctuation like "A."), which may not provide meaningful truncation. Additionally, the function doesn't handle edge cases like empty strings, whitespace-only strings, or strings that are entirely punctuation.

🔍 Suggested improvements for robustness
 const truncateText = (text: string, maxLength: number = 200): { truncated: string; isTruncated: boolean } => {
+    // Handle edge cases
+    if (!text || !text.trim()) {
+        return { truncated: text, isTruncated: false };
+    }
+
     // First try to get first sentence
     const firstSentenceMatch = text.match(/^[^.!?]*[.!?]/);
-    if (firstSentenceMatch && firstSentenceMatch[0].length <= maxLength) {
+    // Only use first sentence if it's meaningful (more than 10 chars)
+    if (firstSentenceMatch && firstSentenceMatch[0].length >= 10 && firstSentenceMatch[0].length <= maxLength) {
         return {
             truncated: firstSentenceMatch[0],
             isTruncated: text.length > firstSentenceMatch[0].length
         };
     }
amazon-product-analysis-server/resources/amazon-product-analysis/components/DeliveryInfo.tsx (1)

79-91: Consider potential duplicate stock quantity display.

The stock quantity appears in the availability badge (lines 85-89: ({stockQuantity} left)) and again in the stock indicator section below (lines 137-148). When stockQuantity is between 1-10, users will see the same information twice, which might be redundant.

Consider either:

  • Removing the inline count from the availability badge and relying solely on the detailed stock indicator section, or
  • Only showing the detailed stock indicator when stockQuantity > 10 to avoid duplication
amazon-product-analysis-server/index.ts (1)

69-75: Consider shorter cache duration for product images.

The 24-hour cache duration (line 72) might be aggressive for product images that could change (e.g., when sellers update product photos). Consider reducing to 1-6 hours for better freshness while still providing caching benefits.

💡 Suggested cache duration adjustment
         headers: {
           "Content-Type": contentType,
-          "Cache-Control": "public, max-age=86400", // Cache for 24 hours
+          "Cache-Control": "public, max-age=21600", // Cache for 6 hours
           "Access-Control-Allow-Origin": "*",
         },
amazon-product-analysis-server/resources/amazon-product-analysis/widget.tsx (1)

30-30: Configure QueryClient with sensible defaults.

The QueryClient is instantiated without any configuration, which means it will use default retry behavior and error handling that might not be optimal for this use case. Consider adding explicit configuration for better control over query behavior.

⚙️ Recommended QueryClient configuration
-const queryClient = new QueryClient();
+const queryClient = new QueryClient({
+    defaultOptions: {
+        queries: {
+            retry: 2,
+            refetchOnWindowFocus: false,
+            staleTime: 5 * 60 * 1000, // 5 minutes
+        },
+    },
+});

This configuration:

  • Limits retries to 2 attempts (instead of default 3)
  • Prevents automatic refetch when window regains focus (unnecessary for product analysis)
  • Sets staleTime to avoid redundant fetches for the same product within 5 minutes
amazon-product-analysis-server/resources/amazon-product-analysis/components/ImageGallery.tsx (2)

64-79: Consider accessibility improvement for image zoom toggle.

The zoom functionality works well, but keyboard users cannot access it since it's only triggered by click. Consider adding keyboard support for better accessibility.

♻️ Proposed enhancement for keyboard accessibility
                <div
                    className={`relative bg-white rounded-xl overflow-hidden transition-all duration-300 ${isZoomed ? "cursor-zoom-out" : "cursor-zoom-in"
                        }`}
                    onClick={() => setIsZoomed(!isZoomed)}
+                   onKeyDown={(e) => {
+                       if (e.key === 'Enter' || e.key === ' ') {
+                           e.preventDefault();
+                           setIsZoomed(!isZoomed);
+                       }
+                   }}
+                   tabIndex={0}
+                   role="button"
+                   aria-label={isZoomed ? "Zoom out" : "Zoom in"}
                >

84-98: Stop propagation may interfere with zoom toggle.

Lines 85 and 92 use e.stopPropagation() to prevent the navigation buttons from triggering the parent's zoom toggle. However, the parent div's onClick is at line 68, not wrapping these buttons. The buttons are siblings to the zoom container, so stopPropagation is unnecessary here and may cause confusion.

♻️ Simplify by removing unnecessary stopPropagation
                        <button
-                           onClick={(e) => { e.stopPropagation(); handlePrevious(); }}
+                           onClick={handlePrevious}
                            className="absolute left-2 top-1/2 -translate-y-1/2 w-10 h-10 bg-black/50 hover:bg-black/70 text-white rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity"
                            aria-label="Previous image"
                        >
                            <ChevronLeftIcon />
                        </button>
                        <button
-                           onClick={(e) => { e.stopPropagation(); handleNext(); }}
+                           onClick={handleNext}
                            className="absolute right-2 top-1/2 -translate-y-1/2 w-10 h-10 bg-black/50 hover:bg-black/70 text-white rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity"
                            aria-label="Next image"
                        >
amazon-product-analysis-server/resources/amazon-product-analysis/components/ProductCard.tsx (1)

65-75: Enhance price formatting with proper locale handling.

The current implementation uses a hardcoded symbol map and toLocaleString() without specifying a locale. This could lead to inconsistent formatting across different regions.

♻️ Use Intl.NumberFormat for proper currency formatting
 const formatPrice = (price: number, currency: string): string => {
-    const currencySymbols: Record<string, string> = {
-        USD: "$",
-        INR: "₹",
-        EUR: "€",
-        GBP: "£",
-        JPY: "¥",
-    };
-    const symbol = currencySymbols[currency] || currency;
-    return `${symbol}${price.toLocaleString()}`;
+    try {
+        return new Intl.NumberFormat('en-US', {
+            style: 'currency',
+            currency: currency,
+            minimumFractionDigits: 0,
+            maximumFractionDigits: 2,
+        }).format(price);
+    } catch {
+        // Fallback for invalid currency codes
+        return `${currency} ${price.toLocaleString()}`;
+    }
 };
amazon-product-analysis-server/resources/amazon-product-analysis/components/SellerInfo.tsx (2)

107-116: Redundant seller name display logic needs clarification.

Line 107 checks seller.name !== seller.soldBy to avoid displaying duplicate information. However, this assumes that when they're equal, showing only "Sold by" is sufficient. If soldBy is missing but name exists, the seller name won't be displayed at all.

Consider this edge case handling:

-                           {seller.name && seller.name !== seller.soldBy && (
+                           {seller.name && (!seller.soldBy || seller.name !== seller.soldBy) && (
                                <div className="flex items-center gap-2">
                                    <span className="text-xs text-secondary uppercase tracking-wide min-w-[70px]">
                                        Seller
                                    </span>

140-157: Missing key uniqueness guarantee for rankings.

Line 144 uses index as the React key for ranking items. If rankings can be reordered or filtered, this could cause React reconciliation issues. Consider using a more stable identifier.

If rankings have unique identifiers or the combination of rank + category is unique:

                            {rankings.map((ranking, index) => {
                                const colors = getRankColor(ranking.rank);
                                return (
                                    <div
-                                       key={index}
+                                       key={`${ranking.rank}-${ranking.category}`}
                                        className="flex items-center gap-3 p-3 bg-surface-elevated rounded-lg"
                                    >
amazon-product-analysis-server/resources/amazon-product-analysis/components/PricingDeal.tsx (2)

57-181: Consider consistent use of dealScore across all categories.

The dealScore variable (lines 67-68) combines percentage and absolute savings but is only used for the "fair" category (line 128). Other categories (hot, great, good) use discountPercent and savings directly in their conditions. While this works, it creates an inconsistency in the evaluation logic.

Consider either:

  1. Using dealScore consistently across all category thresholds
  2. Removing dealScore and using the direct OR conditions everywhere

The current hybrid approach is functional but may make future maintenance less intuitive.


217-297: Add accessibility attributes for visual indicators.

The component uses several visual indicators (savings bar, deal badges, ribbon) without corresponding ARIA labels or screen reader support. Users relying on assistive technologies won't receive information about the deal quality or savings visualization.

♿ Proposed accessibility improvements
 {/* Savings bar - only show if there are actual savings */}
 {savingsPercent > 0 && safeSavings > 0 && (
-    <div className="relative pt-2">
+    <div className="relative pt-2" role="region" aria-label={`Savings indicator: ${safeDiscount} off`}>
         <div className="flex justify-between text-sm mb-2">
             <span className="text-secondary">Savings</span>
             <span className={`font-semibold ${dealInfo.colors.accent}`}>
                 {formatPrice(safeSavings, currency)} ({safeDiscount})
             </span>
         </div>
-        <div className="h-3 bg-surface-elevated rounded-full overflow-hidden">
+        <div className="h-3 bg-surface-elevated rounded-full overflow-hidden" role="progressbar" aria-valuenow={Math.min(savingsPercent * 2, 100)} aria-valuemin={0} aria-valuemax={100}>
             <div
                 className={`h-full bg-gradient-to-r ${dealInfo.colors.bar} rounded-full transition-all duration-1000 ease-out relative`}
                 style={{ width: `${Math.min(savingsPercent * 2, 100)}%` }}

 {/* Deal assessment badge */}
-<div className={`flex items-center gap-2 p-3 ${dealInfo.colors.bg} border ${dealInfo.colors.border} rounded-xl`}>
+<div className={`flex items-center gap-2 p-3 ${dealInfo.colors.bg} border ${dealInfo.colors.border} rounded-xl`} role="status" aria-label={`Deal quality: ${dealInfo.label}`}>
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4fd2d28 and 249a0b7.

⛔ Files ignored due to path filters (1)
  • amazon-product-analysis-server/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (23)
  • amazon-product-analysis-server/.env.example
  • amazon-product-analysis-server/.gitignore
  • amazon-product-analysis-server/README.md
  • amazon-product-analysis-server/index.ts
  • amazon-product-analysis-server/package.json
  • amazon-product-analysis-server/resources/amazon-product-analysis/brightdata-tools.ts
  • amazon-product-analysis-server/resources/amazon-product-analysis/components/CustomerReviews.tsx
  • amazon-product-analysis-server/resources/amazon-product-analysis/components/DeliveryInfo.tsx
  • amazon-product-analysis-server/resources/amazon-product-analysis/components/Features.tsx
  • amazon-product-analysis-server/resources/amazon-product-analysis/components/ImageGallery.tsx
  • amazon-product-analysis-server/resources/amazon-product-analysis/components/PricingDeal.tsx
  • amazon-product-analysis-server/resources/amazon-product-analysis/components/ProductCard.tsx
  • amazon-product-analysis-server/resources/amazon-product-analysis/components/ProductSpecs.tsx
  • amazon-product-analysis-server/resources/amazon-product-analysis/components/SellerInfo.tsx
  • amazon-product-analysis-server/resources/amazon-product-analysis/components/index.ts
  • amazon-product-analysis-server/resources/amazon-product-analysis/hooks/index.ts
  • amazon-product-analysis-server/resources/amazon-product-analysis/hooks/useProductAnalysis.ts
  • amazon-product-analysis-server/resources/amazon-product-analysis/server.ts
  • amazon-product-analysis-server/resources/amazon-product-analysis/types.ts
  • amazon-product-analysis-server/resources/amazon-product-analysis/utils.ts
  • amazon-product-analysis-server/resources/amazon-product-analysis/widget.tsx
  • amazon-product-analysis-server/resources/styles.css
  • amazon-product-analysis-server/tsconfig.json
🧰 Additional context used
🧬 Code graph analysis (10)
amazon-product-analysis-server/resources/amazon-product-analysis/hooks/useProductAnalysis.ts (2)
amazon-product-analysis-server/resources/amazon-product-analysis/hooks/index.ts (1)
  • useProductAnalysis (1-1)
amazon-product-analysis-server/resources/amazon-product-analysis/types.ts (1)
  • ProductAnalysisData (78-78)
amazon-product-analysis-server/resources/amazon-product-analysis/types.ts (1)
amazon-product-analysis-server/resources/amazon-product-analysis/components/SellerInfo.tsx (1)
  • SellerInfo (80-188)
amazon-product-analysis-server/resources/amazon-product-analysis/components/ProductSpecs.tsx (2)
amazon-product-analysis-server/resources/amazon-product-analysis/types.ts (1)
  • Specification (79-79)
amazon-product-analysis-server/resources/amazon-product-analysis/components/index.ts (1)
  • ProductSpecs (5-5)
amazon-product-analysis-server/resources/amazon-product-analysis/components/SellerInfo.tsx (2)
amazon-product-analysis-server/resources/amazon-product-analysis/types.ts (1)
  • SellerInfo (81-81)
amazon-product-analysis-server/resources/amazon-product-analysis/components/index.ts (1)
  • SellerInfo (8-8)
amazon-product-analysis-server/resources/amazon-product-analysis/components/DeliveryInfo.tsx (2)
amazon-product-analysis-server/resources/amazon-product-analysis/types.ts (1)
  • DeliveryOption (80-80)
amazon-product-analysis-server/resources/amazon-product-analysis/components/index.ts (1)
  • DeliveryInfo (6-6)
amazon-product-analysis-server/resources/amazon-product-analysis/components/PricingDeal.tsx (1)
amazon-product-analysis-server/resources/amazon-product-analysis/components/index.ts (1)
  • PricingDeal (2-2)
amazon-product-analysis-server/index.ts (1)
amazon-product-analysis-server/resources/amazon-product-analysis/server.ts (1)
  • analyzeAmazonProduct (15-66)
amazon-product-analysis-server/resources/amazon-product-analysis/server.ts (2)
amazon-product-analysis-server/resources/amazon-product-analysis/brightdata-tools.ts (1)
  • brightDataTools (12-59)
amazon-product-analysis-server/resources/amazon-product-analysis/types.ts (2)
  • ProductAnalysisData (78-78)
  • productAnalysisSchema (45-76)
amazon-product-analysis-server/resources/amazon-product-analysis/widget.tsx (7)
amazon-product-analysis-server/resources/amazon-product-analysis/types.ts (3)
  • propSchema (4-13)
  • AmazonProductAnalysisProps (15-15)
  • SellerInfo (81-81)
amazon-product-analysis-server/resources/amazon-product-analysis/hooks/useProductAnalysis.ts (1)
  • useProductAnalysis (8-28)
amazon-product-analysis-server/resources/amazon-product-analysis/components/ProductCard.tsx (1)
  • ProductCard (83-152)
amazon-product-analysis-server/resources/amazon-product-analysis/components/ImageGallery.tsx (1)
  • ImageGallery (30-133)
amazon-product-analysis-server/resources/amazon-product-analysis/components/PricingDeal.tsx (1)
  • PricingDeal (196-298)
amazon-product-analysis-server/resources/amazon-product-analysis/components/DeliveryInfo.tsx (1)
  • DeliveryInfo (62-152)
amazon-product-analysis-server/resources/amazon-product-analysis/components/SellerInfo.tsx (1)
  • SellerInfo (80-188)
amazon-product-analysis-server/resources/amazon-product-analysis/components/ImageGallery.tsx (2)
amazon-product-analysis-server/resources/amazon-product-analysis/components/index.ts (1)
  • ImageGallery (4-4)
amazon-product-analysis-server/resources/amazon-product-analysis/utils.ts (1)
  • getProxiedImageUrl (10-42)
🪛 dotenv-linter (4.0.0)
amazon-product-analysis-server/.env.example

[warning] 2-2: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

🪛 markdownlint-cli2 (0.18.1)
amazon-product-analysis-server/README.md

62-62: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (21)
amazon-product-analysis-server/README.md (1)

1-476: LGTM! Comprehensive and well-structured documentation.

The README provides excellent coverage of the MCP server template features, usage patterns, and migration guidance. The structure is clear and includes helpful examples throughout.

Note: The static analysis hint about line 62 missing a language specifier is a false positive—the fenced code block contains a directory tree structure, not executable code.

amazon-product-analysis-server/resources/styles.css (1)

1-6: LGTM! Correct Tailwind v4 syntax.

The imports and @source directives follow the new Tailwind v4 conventions as documented. The configuration properly enables scanning of the OpenAI Apps SDK UI components and project files.

amazon-product-analysis-server/resources/amazon-product-analysis/components/CustomerReviews.tsx (2)

46-48: Review truncation logic handles word boundaries correctly.

The truncation implementation properly avoids cutting words mid-way by using a regex to remove the last partial word before adding the ellipsis. This ensures a clean reading experience.


1-2: LGTM! React 19 compatible imports.

The component correctly uses React 19 with the useState hook. The import syntax is clean and appropriate.

amazon-product-analysis-server/resources/amazon-product-analysis/components/ProductSpecs.tsx (1)

46-118: LGTM!

The component implementation is well-structured with proper handling of edge cases:

  • Graceful early return for empty specifications
  • Case-insensitive deduplication preserving first occurrence
  • Priority-based sorting with KEY_SPEC_TYPES followed by alphabetical fallback
  • Clean expand/collapse UX with proper state management
amazon-product-analysis-server/resources/amazon-product-analysis/hooks/index.ts (1)

1-1: LGTM!

Clean barrel export with correct .js extension for ESM module resolution.

amazon-product-analysis-server/resources/amazon-product-analysis/components/DeliveryInfo.tsx (1)

1-151: LGTM - Well-structured delivery information component.

The component properly handles null/empty data, provides clear visual feedback for different availability states, and offers good UX with appropriate icons and badges.

amazon-product-analysis-server/index.ts (1)

82-98: LGTM - Product analysis endpoint properly structured.

The endpoint correctly validates required parameters, handles errors appropriately, and returns structured responses with proper HTTP status codes.

amazon-product-analysis-server/resources/amazon-product-analysis/widget.tsx (2)

32-178: LGTM - Excellent widget composition and error handling.

The component demonstrates solid React practices:

  • Proper loading, error, and success states
  • Conditional rendering with appropriate null checks
  • Clean composition of subcomponents
  • Good UX with informative loading/error messages
  • Responsive grid layouts

21-28: Well-defined widget metadata.

The widgetMetadata properly describes the widget's purpose and inputs using Zod schema validation, which enables automatic type-safe tool registration in the MCP framework.

amazon-product-analysis-server/resources/amazon-product-analysis/types.ts (3)

43-76: LGTM - Well-designed schema with appropriate validation.

The schema design demonstrates good practices:

  • All fields are optional for graceful handling of partial LLM responses
  • Appropriate constraints (rating 0-5, positive integers for reviews, enums for delivery types)
  • Nested structures properly organized
  • Clear separation of concerns (product, pricing, features, etc.)

Based on library documentation, this aligns well with Zod 4's unified error customization and validation patterns.


4-13: Input schema properly validates Amazon URLs.

The propSchema correctly validates the URL format and provides clear descriptions for both required and optional fields. The URL description helpfully specifies expected Amazon URL patterns.


45-55: The schema validation at line 48 (imageUrl: z.string().url().optional()) and line 65 (images: z.array(z.string().url()).optional()) correctly requires valid URLs or undefined values—empty strings would fail validation. The server-side code in server.ts properly handles this by using Zod schema validation with the explicit instruction to "Fill fields ONLY if they are explicitly present in tool output." The generateObject function enforces this constraint, ensuring missing URLs result in undefined fields rather than empty strings. No changes needed.

amazon-product-analysis-server/resources/amazon-product-analysis/components/ImageGallery.tsx (2)

30-37: LGTM! Clean proxied image handling.

The component correctly uses useMemo to avoid re-proxying images on every render, and properly handles undefined/null images with a fallback to an empty array.


41-51: LGTM! Circular navigation implemented correctly.

The navigation handlers properly wrap around using modulo logic for a seamless circular experience.

amazon-product-analysis-server/resources/amazon-product-analysis/components/ProductCard.tsx (1)

97-102: LGTM! Defensive null checks for price and rating.

The component correctly validates that price and rating are not undefined or null before rendering, with proper currency requirement for price display.

amazon-product-analysis-server/resources/amazon-product-analysis/components/SellerInfo.tsx (1)

44-71: LGTM! Well-structured rank color mapping.

The getRankColor helper provides a clear visual hierarchy for rankings with appropriate color gradients and badges for top performers.

amazon-product-analysis-server/resources/amazon-product-analysis/components/index.ts (1)

1-8: LGTM! Clean barrel export pattern.

The barrel file properly consolidates all UI component exports for easy consumption by other modules.

amazon-product-analysis-server/resources/amazon-product-analysis/components/PricingDeal.tsx (3)

1-28: LGTM: Well-structured type definitions.

The type definitions are comprehensive and properly typed. The optional properties in PricingDealProps provide flexibility, and the DealInfo interface with color tokens supports dynamic theming effectively.


30-49: LGTM: Clean currency handling.

The currency-specific thresholds and formatting logic are well-implemented. Using toLocaleString() for number formatting is a good practice, and the fallback for unknown currencies is appropriate.


183-194: LGTM: Clean icon components.

Simple and effective SVG icon implementations.

Comment on lines +1 to +2
BRIGHTDATA_API_KEY=
OPENAI_API_KEY= No newline at end of file
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

Add trailing newline for POSIX compliance.

Per the static analysis hint, add a blank line at the end of the file. This ensures POSIX text file compliance and avoids issues with some tools.

Suggested fix
 BRIGHTDATA_API_KEY=
 OPENAI_API_KEY=
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
BRIGHTDATA_API_KEY=
OPENAI_API_KEY=
BRIGHTDATA_API_KEY=
OPENAI_API_KEY=
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 2-2: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

🤖 Prompt for AI Agents
In @amazon-product-analysis-server/.env.example around lines 1 - 2, Add a
POSIX-compliant trailing newline to the end of the environment example by
ensuring the file finishes with a blank line after the last variable (after the
OPENAI_API_KEY line); simply append a single newline character so the file ends
with an empty line following BRIGHTDATA_API_KEY and OPENAI_API_KEY.

*.tsbuildinfo

# Other files
script.ts
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

🏁 Script executed:

#!/bin/bash
# Check if script.ts exists
fd -t f "script.ts"

# Check for imports/references to script.ts (excluding .gitignore and tsconfig.json)
rg -n "script\.ts" -g "!.gitignore" -g "!tsconfig.json" --no-heading -C 2

Repository: patchy631/ai-engineering-hub

Length of output: 1777


🏁 Script executed:

# Check tsconfig.json content around line 23
head -30 tsconfig.json | cat -n

# Check .gitignore content around line 43
head -50 .gitignore | cat -n

Repository: patchy631/ai-engineering-hub

Length of output: 214


🏁 Script executed:

#!/bin/bash
# Find tsconfig.json and .gitignore in the subdirectory
fd -t f tsconfig.json amazon-product-analysis-server/
fd -t f ".gitignore" amazon-product-analysis-server/

# Check if script.ts exists anywhere
fd -t f "script.ts" amazon-product-analysis-server/

Repository: patchy631/ai-engineering-hub

Length of output: 116


🏁 Script executed:

#!/bin/bash
# Read tsconfig.json around line 23
echo "=== tsconfig.json content ==="
cat -n amazon-product-analysis-server/tsconfig.json | head -30

# Read .gitignore around line 43
echo -e "\n=== .gitignore content ==="
cat -n amazon-product-analysis-server/.gitignore | head -50

Repository: patchy631/ai-engineering-hub

Length of output: 1713


🏁 Script executed:

#!/bin/bash
# Check for any actual imports of script.ts
rg "import.*script\.ts|from.*script\.ts" amazon-product-analysis-server/

# Check if script.ts is mentioned in any documentation
rg "script\.ts" amazon-product-analysis-server/ -g "*.md" -g "*.txt" -g "*.json"

# List files in amazon-product-analysis-server to see actual structure
echo "=== Files in amazon-product-analysis-server/ ===" 
find amazon-product-analysis-server/ -maxdepth 1 -type f -name "*.ts" | sort

Repository: patchy631/ai-engineering-hub

Length of output: 271


Remove script.ts from tsconfig.json's include array.

The file script.ts is listed in both tsconfig.json's include array (line 23) and .gitignore (line 43), creating an inconsistency. Since script.ts does not exist in the repository and has no usages in the codebase, it should be removed from tsconfig.json's include array to avoid configuring TypeScript to compile a non-existent file.

🤖 Prompt for AI Agents
In @amazon-product-analysis-server/.gitignore at line 43, tsconfig.json
currently includes "script.ts" in its "include" array although that file is
ignored and absent; open tsconfig.json, remove "script.ts" from the "include"
array (the string "script.ts") so TypeScript isn't configured to compile a
non-existent/ignored file and save the updated tsconfig.json.

Comment on lines +28 to +80
// Image proxy endpoint to bypass CORS restrictions for Amazon images
server.get("/api/image-proxy", async (c) => {
const imageUrl = c.req.query("url");

if (!imageUrl) {
return c.json({ error: "URL parameter is required" }, 400);
}

try {
// Validate that the URL is from Amazon's CDN
const url = new URL(imageUrl);
const allowedHosts = [
"m.media-amazon.com",
"images-na.ssl-images-amazon.com",
"images-eu.ssl-images-amazon.com",
"images-fe.ssl-images-amazon.com",
"ecx.images-amazon.com",
];

if (!allowedHosts.some((host) => url.hostname.includes(host) || url.hostname.endsWith(".media-amazon.com"))) {
return c.json({ error: "Only Amazon image URLs are allowed" }, 403);
}

// Fetch the image from Amazon
const response = await fetch(imageUrl, {
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "image/webp,image/apng,image/*,*/*;q=0.8",
"Referer": "https://www.amazon.com/",
},
});

if (!response.ok) {
return c.json({ error: "Failed to fetch image" }, 502);
}

// Get the content type and body
const contentType = response.headers.get("content-type") || "image/jpeg";
const imageBuffer = await response.arrayBuffer();

// Return the image with appropriate headers
return new Response(imageBuffer, {
headers: {
"Content-Type": contentType,
"Cache-Control": "public, max-age=86400", // Cache for 24 hours
"Access-Control-Allow-Origin": "*",
},
});
} catch (error) {
console.error("Error proxying image:", error);
return c.json({ error: `Failed to proxy image: ${String(error)}` }, 500);
}
});
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 | 🔴 Critical

Critical: Fix hostname validation to prevent SSRF vulnerability.

Line 47 uses url.hostname.includes(host) which is vulnerable to subdomain bypass attacks. An attacker could use a URL like https://evil-m.media-amazon.com.attacker.com/malicious.jpg which would pass the validation since it contains "m.media-amazon.com" as a substring.

🔒 Proposed fix using exact hostname matching
-    if (!allowedHosts.some((host) => url.hostname.includes(host) || url.hostname.endsWith(".media-amazon.com"))) {
+    if (!allowedHosts.some((host) => url.hostname === host) && !url.hostname.endsWith(".media-amazon.com")) {
       return c.json({ error: "Only Amazon image URLs are allowed" }, 403);
     }

This ensures exact hostname matching for entries in the allowedHosts array and properly validates the .media-amazon.com suffix.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Image proxy endpoint to bypass CORS restrictions for Amazon images
server.get("/api/image-proxy", async (c) => {
const imageUrl = c.req.query("url");
if (!imageUrl) {
return c.json({ error: "URL parameter is required" }, 400);
}
try {
// Validate that the URL is from Amazon's CDN
const url = new URL(imageUrl);
const allowedHosts = [
"m.media-amazon.com",
"images-na.ssl-images-amazon.com",
"images-eu.ssl-images-amazon.com",
"images-fe.ssl-images-amazon.com",
"ecx.images-amazon.com",
];
if (!allowedHosts.some((host) => url.hostname.includes(host) || url.hostname.endsWith(".media-amazon.com"))) {
return c.json({ error: "Only Amazon image URLs are allowed" }, 403);
}
// Fetch the image from Amazon
const response = await fetch(imageUrl, {
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "image/webp,image/apng,image/*,*/*;q=0.8",
"Referer": "https://www.amazon.com/",
},
});
if (!response.ok) {
return c.json({ error: "Failed to fetch image" }, 502);
}
// Get the content type and body
const contentType = response.headers.get("content-type") || "image/jpeg";
const imageBuffer = await response.arrayBuffer();
// Return the image with appropriate headers
return new Response(imageBuffer, {
headers: {
"Content-Type": contentType,
"Cache-Control": "public, max-age=86400", // Cache for 24 hours
"Access-Control-Allow-Origin": "*",
},
});
} catch (error) {
console.error("Error proxying image:", error);
return c.json({ error: `Failed to proxy image: ${String(error)}` }, 500);
}
});
// Image proxy endpoint to bypass CORS restrictions for Amazon images
server.get("/api/image-proxy", async (c) => {
const imageUrl = c.req.query("url");
if (!imageUrl) {
return c.json({ error: "URL parameter is required" }, 400);
}
try {
// Validate that the URL is from Amazon's CDN
const url = new URL(imageUrl);
const allowedHosts = [
"m.media-amazon.com",
"images-na.ssl-images-amazon.com",
"images-eu.ssl-images-amazon.com",
"images-fe.ssl-images-amazon.com",
"ecx.images-amazon.com",
];
if (!allowedHosts.some((host) => url.hostname === host) && !url.hostname.endsWith(".media-amazon.com")) {
return c.json({ error: "Only Amazon image URLs are allowed" }, 403);
}
// Fetch the image from Amazon
const response = await fetch(imageUrl, {
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "image/webp,image/apng,image/*,*/*;q=0.8",
"Referer": "https://www.amazon.com/",
},
});
if (!response.ok) {
return c.json({ error: "Failed to fetch image" }, 502);
}
// Get the content type and body
const contentType = response.headers.get("content-type") || "image/jpeg";
const imageBuffer = await response.arrayBuffer();
// Return the image with appropriate headers
return new Response(imageBuffer, {
headers: {
"Content-Type": contentType,
"Cache-Control": "public, max-age=86400", // Cache for 24 hours
"Access-Control-Allow-Origin": "*",
},
});
} catch (error) {
console.error("Error proxying image:", error);
return c.json({ error: `Failed to proxy image: ${String(error)}` }, 500);
}
});
🤖 Prompt for AI Agents
In @amazon-product-analysis-server/index.ts around lines 28 - 80, The hostname
check in the image proxy (server.get handler) is vulnerable because
url.hostname.includes(host) allows crafted hostnames like
evil-m.media-amazon.com.attacker.com; update the validation in the handler that
builds allowedHosts to instead normalize url.hostname to lowercase and check for
exact matches (hostname === host) or proper subdomain suffixes using
hostname.endsWith('.' + host) for entries that should allow subdomains (e.g.,
"media-amazon.com"), and remove the includes(...) usage across the validation
logic (refer to url.hostname and allowedHosts in the image-proxy route).

Comment on lines +15 to +18
const client = new bdclient({
apiKey: config.apiKey,
autoCreateZones: true
})
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 | 🟠 Major

🧩 Analysis chain

🌐 Web query:

BrightData SDK autoCreateZones option cost implications documentation

💡 Result:

Short answer: autoCreateZones just creates the required Bright Data zones automatically — but created zones can affect billing. Specifically:

  • The SDK option autoCreateZones = true will create zones when needed. [1][4]
  • Bright Data allows up to 50 zones free; any additional zone costs $5/month. [2]
  • Beyond per-zone fees you can still incur standard usage charges (bandwidth, dedicated IPs, pre‑commit/minimum plans, product-specific charges) for traffic or features enabled on those zones. See your zone billing/usage in the Control Panel or via the Zones cost API. [2][3]

If you want, I can: (a) check how many zones your account currently has, or (b) show the exact SDK code paths that create zones.


🏁 Script executed:

# First, let's look at the file in question and its context
fd brightdata-tools.ts -x cat -n {}

Repository: patchy631/ai-engineering-hub

Length of output: 2476


🏁 Script executed:

# Search for how the bdclient is used throughout the codebase
rg "bdclient|autoCreateZones" -A 3 -B 3

Repository: patchy631/ai-engineering-hub

Length of output: 1785


🏁 Script executed:

# Look for any configuration files or documentation about BrightData setup
fd -e md -e txt -e json | xargs grep -l -i "brightdata\|bdclient" 2>/dev/null | head -20

Repository: patchy631/ai-engineering-hub

Length of output: 327


🏁 Script executed:

# Check README files for BrightData configuration guidance
rg -A 5 -B 5 -i "brightdata|bright.data" README.md amazon-product-analysis-server/README.md 2>/dev/null || echo "No BrightData documentation found in READMEs"

Repository: patchy631/ai-engineering-hub

Length of output: 1936


Consider making autoCreateZones configurable and document cost implications.

Line 17 hardcodes autoCreateZones: true, which automatically creates BrightData zones when needed. This has real cost implications: while the first 50 zones are free, each additional zone costs $5/month, and standard usage charges (bandwidth, IPs, etc.) apply on top. Without visibility into zone creation or a configuration option, this could lead to unexpected costs.

Recommendations:

  • Make autoCreateZones configurable via the BrightDataToolsConfig object rather than hardcoding it
  • Document in comments or README why automatic zone creation is necessary for this use case
  • Consider whether explicit zone pre-configuration would be safer than automatic provisioning
🤖 Prompt for AI Agents
In
@amazon-product-analysis-server/resources/amazon-product-analysis/brightdata-tools.ts
around lines 15 - 18, Replace the hardcoded autoCreateZones:true when
instantiating bdclient with a configurable option on BrightDataToolsConfig so
callers can opt in/out; update the constructor or factory that builds bdclient
(the code creating new bdclient({...})) to read config.autoCreateZones
(defaulting to false or to current behavior) and pass that value through, and
add a brief comment near BrightDataToolsConfig and the bdclient instantiation
explaining why automatic zone creation is used and the potential
$5/month-per-zone cost and bandwidth/IP charges so reviewers can choose explicit
pre-provisioning instead of automatic provisioning.

Comment on lines +24 to +33
inputSchema: z.object({
url: z
.string()
.url()
.describe('Amazon product URL (must contain /dp/ or /gp/product/)'),
zipcode: z
.string()
.optional()
.describe('ZIP code for location-specific pricing and availability'),
}),
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 | 🟠 Major

Input validation needs URL path verification.

The schema requires the URL to contain /dp/ or /gp/product/ per the description (line 28), but the actual validation only checks that it's a valid URL. This mismatch could lead to API errors when invalid Amazon URLs are passed.

🐛 Add URL path validation
            inputSchema: z.object({
                url: z
                    .string()
                    .url()
-                   .describe('Amazon product URL (must contain /dp/ or /gp/product/)'),
+                   .refine(
+                       (url) => url.includes('/dp/') || url.includes('/gp/product/'),
+                       { message: 'URL must be a valid Amazon product URL containing /dp/ or /gp/product/' }
+                   )
+                   .describe('Amazon product URL (must contain /dp/ or /gp/product/)'),
                zipcode: z
                    .string()
                    .optional()
                    .describe('ZIP code for location-specific pricing and availability'),
            }),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
inputSchema: z.object({
url: z
.string()
.url()
.describe('Amazon product URL (must contain /dp/ or /gp/product/)'),
zipcode: z
.string()
.optional()
.describe('ZIP code for location-specific pricing and availability'),
}),
inputSchema: z.object({
url: z
.string()
.url()
.refine(
(url) => url.includes('/dp/') || url.includes('/gp/product/'),
{ message: 'URL must be a valid Amazon product URL containing /dp/ or /gp/product/' }
)
.describe('Amazon product URL (must contain /dp/ or /gp/product/)'),
zipcode: z
.string()
.optional()
.describe('ZIP code for location-specific pricing and availability'),
}),
🤖 Prompt for AI Agents
In
@amazon-product-analysis-server/resources/amazon-product-analysis/brightdata-tools.ts
around lines 24 - 33, The inputSchema's url field currently only checks it's a
valid URL but not that the path contains Amazon product indicators; update the
url validator (the z.object inputSchema -> url field) to include an additional
check (z.refine or regex) that the URL path includes either "/dp/" or
"/gp/product/" (you can test either against the full string or by parsing new
URL(url).pathname) and return a clear validation message if it fails so the
schema matches its description.

Comment on lines +196 to +215
export const PricingDeal: React.FC<PricingDealProps> = ({
initialPrice,
finalPrice,
discount,
savings,
currency,
}) => {
// If we don't have at least a final price and currency, don't render
if (finalPrice === undefined || finalPrice === null || !currency) {
return null;
}

const safeInitialPrice = initialPrice ?? finalPrice;
const safeSavings = savings ?? 0;
const safeDiscount = discount ?? "0%";

const savingsPercent = Math.abs(parseFloat(safeDiscount.replace(/[^0-9.-]/g, ""))) || 0;
const dealInfo = categorizeDeal(savingsPercent, safeSavings, safeInitialPrice, currency);
const isGoodDealOrBetter = ["hot", "great", "good"].includes(dealInfo.category);

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

🏁 Script executed:

#!/bin/bash
# First, find the PricingDealProps type definition
find . -type f \( -name "*.ts" -o -name "*.tsx" \) -exec grep -l "PricingDealProps" {} \;

Repository: patchy631/ai-engineering-hub

Length of output: 165


🏁 Script executed:

#!/bin/bash
# Search for where PricingDeal component is used
rg -n "PricingDeal" --type ts --type tsx -A 2 -B 2 | head -100

Repository: patchy631/ai-engineering-hub

Length of output: 99


🏁 Script executed:

#!/bin/bash
# Search for categorizeDeal function definition
rg -n "categorizeDeal" --type ts --type tsx -A 10

Repository: patchy631/ai-engineering-hub

Length of output: 99


🏁 Script executed:

#!/bin/bash
# Look for discount prop patterns and formats
rg -n "discount.*:" --type ts --type tsx | head -50

Repository: patchy631/ai-engineering-hub

Length of output: 99


🏁 Script executed:

#!/bin/bash
# Look at the PricingDeal.tsx file directly to find the type definition
cat -n amazon-product-analysis-server/resources/amazon-product-analysis/components/PricingDeal.tsx | head -200

Repository: patchy631/ai-engineering-hub

Length of output: 8165


🏁 Script executed:

#!/bin/bash
# Search for PricingDealProps and categorizeDeal without type filters
rg -n "PricingDealProps|interface.*Pricing|type.*Pricing" --max-count 20

Repository: patchy631/ai-engineering-hub

Length of output: 349


🏁 Script executed:

#!/bin/bash
# Search for categorizeDeal function
rg -n "categorizeDeal" -A 15

Repository: patchy631/ai-engineering-hub

Length of output: 4908


🏁 Script executed:

#!/bin/bash
# Search for all usages of PricingDeal component (the component being called)
rg -n "<PricingDeal" -A 5 -B 2

Repository: patchy631/ai-engineering-hub

Length of output: 2281


Document discount string format and handle potential price increases.

The discount prop type is string? with no documentation of expected format. The parsing on line 212 uses Math.abs() to convert any parsed value to positive—if the discount represents a price increase (negative value), it would be silently converted to a discount, misrepresenting markup as savings to the categorizeDeal function.

Clarify:

  1. What discount formats are valid? (e.g., "20%", "20", "-5%")
  2. Are price increases (negative discounts) expected in analysis.pricing.discount? If yes, they need explicit handling rather than silent Math.abs() conversion.
🤖 Prompt for AI Agents
In
@amazon-product-analysis-server/resources/amazon-product-analysis/components/PricingDeal.tsx
around lines 196 - 215, The discount string format is undocumented and the
current parsing in PricingDeal (safeDiscount -> savingsPercent using Math.abs)
silently turns negative discounts (price increases) into positive savings;
update documentation/comments for the discount prop to state accepted formats
(e.g., "20%", "20", "-5%") and change the parsing flow in the PricingDeal
component: remove Math.abs, normalize the string by stripping
non-numeric/decimal/sign characters, use parseFloat to get a signed percentage
(allow negatives), handle NaN by defaulting to 0, and pass that signed
savingsPercent into categorizeDeal (or branch to treat negative percentages as
price increases—e.g., set safeSavings or a flag) so price increases are not
misrepresented as discounts; reference functions/vars: PricingDeal,
safeDiscount, savingsPercent, safeSavings, safeInitialPrice, categorizeDeal, and
isGoodDealOrBetter when making these changes.

Comment on lines +217 to +297
<div className="p-6 bg-surface border border-default rounded-2xl overflow-hidden relative">
{/* Deal ribbon - only show for actual deals */}
{dealInfo.showRibbon && (
<div className={`absolute -right-8 top-6 rotate-45 bg-gradient-to-r ${dealInfo.colors.ribbon} text-white text-xs font-bold py-1 px-10 shadow-lg`}>
{dealInfo.ribbonText}
</div>
)}

<h4 className="text-lg font-semibold text-default mb-5 flex items-center gap-2">
<svg className={`w-5 h-5 ${dealInfo.colors.accent}`} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" strokeLinecap="round" strokeLinejoin="round" />
</svg>
Price Breakdown
</h4>

<div className="space-y-4">
{/* Price comparison */}
<div className="flex items-end gap-4">
<div className="flex flex-col">
<span className="text-xs text-secondary uppercase tracking-wide mb-1">You Pay</span>
<span className={`text-3xl font-bold ${dealInfo.colors.accent}`}>
{formatPrice(finalPrice, currency)}
</span>
</div>
{safeInitialPrice !== finalPrice && safeInitialPrice > 0 && (
<div className="flex flex-col pb-1">
<span className="text-xs text-secondary uppercase tracking-wide mb-1">Was</span>
<span className="text-xl text-secondary line-through">
{formatPrice(safeInitialPrice, currency)}
</span>
</div>
)}
</div>

{/* Savings bar - only show if there are actual savings */}
{savingsPercent > 0 && safeSavings > 0 && (
<div className="relative pt-2">
<div className="flex justify-between text-sm mb-2">
<span className="text-secondary">Savings</span>
<span className={`font-semibold ${dealInfo.colors.accent}`}>
{formatPrice(safeSavings, currency)} ({safeDiscount})
</span>
</div>
<div className="h-3 bg-surface-elevated rounded-full overflow-hidden">
<div
className={`h-full bg-gradient-to-r ${dealInfo.colors.bar} rounded-full transition-all duration-1000 ease-out relative`}
style={{ width: `${Math.min(savingsPercent * 2, 100)}%` }}
>
{isGoodDealOrBetter && (
<div className="absolute inset-0 bg-white/20 animate-pulse" />
)}
</div>
</div>
</div>
)}

{/* Deal assessment badge */}
<div className={`flex items-center gap-2 p-3 ${dealInfo.colors.bg} border ${dealInfo.colors.border} rounded-xl`}>
<div className={`w-10 h-10 bg-gradient-to-br ${dealInfo.colors.ribbon} rounded-full flex items-center justify-center shrink-0`}>
{isGoodDealOrBetter ? <CheckIcon /> : <InfoIcon />}
</div>
<div>
<p className={`text-sm font-semibold ${dealInfo.colors.text}`}>
{dealInfo.label}
</p>
<p className="text-xs text-secondary">
{dealInfo.description}
</p>
</div>
</div>

{/* Deal score indicator for transparency - only show if there are savings */}
{savingsPercent > 0 && safeSavings > 0 && (
<div className="flex items-center justify-between text-xs text-secondary pt-2 border-t border-default">
<span>Discount: {savingsPercent.toFixed(0)}%</span>
<span>Savings: {formatPrice(safeSavings, currency)}</span>
</div>
)}
</div>
</div>
);
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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find Tailwind configuration files
fd -type f \( -name "tailwind.config.*" -o -name "tailwind.js" \)

Repository: patchy631/ai-engineering-hub

Length of output: 242


🏁 Script executed:

# Search for where these custom classes might be defined
rg -n "bg-surface|border-default|text-default|text-secondary|bg-surface-elevated" --type-list | head -20

Repository: patchy631/ai-engineering-hub

Length of output: 461


🏁 Script executed:

# Look for theme or styles configuration
find . -type f \( -name "theme*" -o -name "*theme*" \) | grep -E "\.(ts|tsx|js|jsx|json)$" | head -20

Repository: patchy631/ai-engineering-hub

Length of output: 151


🏁 Script executed:

# Check for CSS/SCSS files that might define custom classes
fd -type f \( -name "*.css" -o -name "*.scss" \) | head -20

Repository: patchy631/ai-engineering-hub

Length of output: 242


🏁 Script executed:

# Find Tailwind config files with correct syntax
find . -type f \( -name "tailwind.config.js" -o -name "tailwind.config.ts" \)

Repository: patchy631/ai-engineering-hub

Length of output: 111


🏁 Script executed:

# Search for the custom classes in all files
rg "bg-surface|border-default|text-default|text-secondary|bg-surface-elevated"

Repository: patchy631/ai-engineering-hub

Length of output: 14260


🏁 Script executed:

# Check the theme provider file that was found
cat -n ./stock-portfolio-analysis-agent/frontend/src/app/components/theme-provider.tsx

Repository: patchy631/ai-engineering-hub

Length of output: 467


🏁 Script executed:

# Find all CSS/SCSS files in the project
find . -type f \( -name "*.css" -o -name "*.scss" \) | head -30

Repository: patchy631/ai-engineering-hub

Length of output: 1541


🏁 Script executed:

cat -n amazon-product-analysis-server/resources/styles.css

Repository: patchy631/ai-engineering-hub

Length of output: 3406


🏁 Script executed:

# Check if there's a tailwind config in the amazon-product-analysis-server directory
find amazon-product-analysis-server -type f \( -name "tailwind.config.*" -o -name "postcss.config.*" \)

Repository: patchy631/ai-engineering-hub

Length of output: 54


🏁 Script executed:

# Check the structure of amazon-product-analysis-server directory
ls -la amazon-product-analysis-server/

Repository: patchy631/ai-engineering-hub

Length of output: 714


🏁 Script executed:

# Check the tailwind config
cat -n ./open-agent-builder/tailwind.config.ts

Repository: patchy631/ai-engineering-hub

Length of output: 12116


🏁 Script executed:

# Search for color definitions or theme configuration
rg "text-default|bg-surface" --type ts --type css -A 2 -B 2 | head -60

Repository: patchy631/ai-engineering-hub

Length of output: 7112


🏁 Script executed:

# Check if amazon-product-analysis-server has any config files
find amazon-product-analysis-server -type f -name "*.config.*"

Repository: patchy631/ai-engineering-hub

Length of output: 54


🏁 Script executed:

# Check how the amazon-product-analysis-server uses the styles
cat -n amazon-product-analysis-server/index.ts | head -50

Repository: patchy631/ai-engineering-hub

Length of output: 2223


🏁 Script executed:

# Find colors.json file
find . -name "colors.json" -type f

Repository: patchy631/ai-engineering-hub

Length of output: 144


🏁 Script executed:

# Check if colors.json contains the custom color definitions
if [ -f "./open-agent-builder/colors.json" ]; then
  cat -n ./open-agent-builder/colors.json
fi

Repository: patchy631/ai-engineering-hub

Length of output: 5793


🏁 Script executed:

# Check the tailwind config content paths to see if amazon-product-analysis-server is included
rg "amazon-product-analysis" ./open-agent-builder/tailwind.config.ts

Repository: patchy631/ai-engineering-hub

Length of output: 54


🏁 Script executed:

# Look for any separate tailwind or configuration in amazon-product-analysis-server
ls -la amazon-product-analysis-server/resources/

Repository: patchy631/ai-engineering-hub

Length of output: 315


🏁 Script executed:

# Search for definitions of the custom classes in CSS files
rg "bg-surface|border-default|text-default|text-secondary|bg-surface-elevated" --type css -B 3 -A 3

Repository: patchy631/ai-engineering-hub

Length of output: 728


🏁 Script executed:

# Check if there's a CSS variables definition anywhere
rg "\-\-.*surface|\-\-.*default|\-\-.*secondary" -B 2 -A 2

Repository: patchy631/ai-engineering-hub

Length of output: 50384


🏁 Script executed:

# Look at the full tailwind config content paths again to confirm
grep -A 10 "content:" ./open-agent-builder/tailwind.config.ts

Repository: patchy631/ai-engineering-hub

Length of output: 413


🏁 Script executed:

# Search for where these custom colors might be defined as CSS variables
rg "surface|default|secondary" ./open-agent-builder/styles/design-system/colors.css | head -40

Repository: patchy631/ai-engineering-hub

Length of output: 193


🏁 Script executed:

# Check if there's a global theme or design tokens file that defines these
find amazon-product-analysis-server -type f \( -name "*.css" -o -name "*.scss" -o -name "*.json" \) -exec grep -l "surface\|default\|secondary" {} \;

Repository: patchy631/ai-engineering-hub

Length of output: 172


🏁 Script executed:

# Verify the complete colors.json to see all available colors
cat ./open-agent-builder/colors.json | head -100

Repository: patchy631/ai-engineering-hub

Length of output: 2498


Define custom Tailwind color tokens for the design system.

The component uses custom Tailwind classes that are not defined in the project's Tailwind configuration:

  • bg-surface (line 217)
  • border-default (line 217)
  • text-default (line 225)
  • text-secondary (lines 236, 243, 255, 282, 290)
  • bg-surface-elevated (line 260)

These classes are referenced in amazon-product-analysis-server/resources/styles.css via @apply directives, but no corresponding color definitions exist in open-agent-builder/tailwind.config.ts or the project's color configuration. Add these colors to your Tailwind theme or extend the configuration to include the amazon-product-analysis-server directory in the content paths if this module has its own theme definitions.

🤖 Prompt for AI Agents
In
@amazon-product-analysis-server/resources/amazon-product-analysis/components/PricingDeal.tsx
around lines 217 - 297, The Tailwind utility classes used in PricingDeal.tsx
(bg-surface, border-default, text-default, text-secondary, bg-surface-elevated)
are not defined in the project's Tailwind theme; update the Tailwind
configuration (open-agent-builder/tailwind.config.ts) to either add these custom
color tokens under theme.extend.colors or ensure the
amazon-product-analysis-server directory is included in the config's content
paths so its styles.css @apply usages are picked up, then define the
corresponding color keys (surface, surface-elevated, default, secondary,
border-default, etc.) matching the design system names so the classes referenced
in PricingDeal.tsx and resources/styles.css resolve correctly.

Comment on lines +14 to +49
const StarIcon: React.FC<{ filled: boolean; half?: boolean }> = ({ filled, half }) => (
<svg
className="w-5 h-5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
{half ? (
<>
<defs>
<linearGradient id="halfStar">
<stop offset="50%" stopColor="#FBBF24" />
<stop offset="50%" stopColor="transparent" />
</linearGradient>
</defs>
<path
d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"
fill="url(#halfStar)"
stroke="#FBBF24"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</>
) : (
<path
d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"
fill={filled ? "#FBBF24" : "transparent"}
stroke={filled ? "#FBBF24" : "#9CA3AF"}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
)}
</svg>
);
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 | 🔴 Critical

Critical: Non-unique gradient ID causes rendering conflicts.

Line 24 defines a gradient with id="halfStar". If multiple StarIcon components with half={true} are rendered on the same page (which happens in StarRating on line 57), all half-stars will share the same gradient ID, causing SVG rendering conflicts.

🐛 Fix by generating unique IDs
+import React, { useId } from "react";
 import { getProxiedImageUrl } from "../utils";

-const StarIcon: React.FC<{ filled: boolean; half?: boolean }> = ({ filled, half }) => (
+const StarIcon: React.FC<{ filled: boolean; half?: boolean }> = ({ filled, half }) => {
+    const gradientId = useId();
+    return (
     <svg
         className="w-5 h-5"
         viewBox="0 0 24 24"
         fill="none"
         xmlns="http://www.w3.org/2000/svg"
     >
         {half ? (
             <>
                 <defs>
-                    <linearGradient id="halfStar">
+                    <linearGradient id={gradientId}>
                         <stop offset="50%" stopColor="#FBBF24" />
                         <stop offset="50%" stopColor="transparent" />
                     </linearGradient>
                 </defs>
                 <path
                     d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"
-                    fill="url(#halfStar)"
+                    fill={`url(#${gradientId})`}
                     stroke="#FBBF24"
                     strokeWidth="1.5"
                     strokeLinecap="round"
                     strokeLinejoin="round"
                 />
             </>
         ) : (
             <path
                 d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"
                 fill={filled ? "#FBBF24" : "transparent"}
                 stroke={filled ? "#FBBF24" : "#9CA3AF"}
                 strokeWidth="1.5"
                 strokeLinecap="round"
                 strokeLinejoin="round"
             />
         )}
     </svg>
-);
+    );
+};
🤖 Prompt for AI Agents
In
@amazon-product-analysis-server/resources/amazon-product-analysis/components/ProductCard.tsx
around lines 14 - 49, StarIcon uses a hard-coded gradient id ("halfStar") which
causes SVG ID collisions when multiple StarIcon(half=true) instances render;
update the StarIcon component to generate a unique gradient id (e.g., via
React's useId() or a per-instance unique string) and replace the hard-coded id
and the path's fill reference (fill="url(#halfStar)") with that unique id so
each instance renders its own gradient; ensure the generated id is used both in
<linearGradient id={gradientId}> and in the corresponding path's fill attribute.

Comment on lines +7 to +9
const bdTools = brightDataTools({
apiKey: process.env.BRIGHTDATA_API_KEY!,
});
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 | 🟠 Major

Validate environment variable before use.

Using process.env.BRIGHTDATA_API_KEY! will cause a cryptic runtime error if the variable is not set. Add validation to fail fast with a clear message.

Suggested fix
+const BRIGHTDATA_API_KEY = process.env.BRIGHTDATA_API_KEY;
+if (!BRIGHTDATA_API_KEY) {
+    throw new Error("BRIGHTDATA_API_KEY environment variable is required");
+}
+
 // Initialize Bright Data tools
 const bdTools = brightDataTools({
-    apiKey: process.env.BRIGHTDATA_API_KEY!,
+    apiKey: BRIGHTDATA_API_KEY,
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const bdTools = brightDataTools({
apiKey: process.env.BRIGHTDATA_API_KEY!,
});
const BRIGHTDATA_API_KEY = process.env.BRIGHTDATA_API_KEY;
if (!BRIGHTDATA_API_KEY) {
throw new Error("BRIGHTDATA_API_KEY environment variable is required");
}
// Initialize Bright Data tools
const bdTools = brightDataTools({
apiKey: BRIGHTDATA_API_KEY,
});
🤖 Prompt for AI Agents
In @amazon-product-analysis-server/resources/amazon-product-analysis/server.ts
around lines 7 - 9, The code uses process.env.BRIGHTDATA_API_KEY! directly when
creating bdTools via brightDataTools; add a pre-check that validates
process.env.BRIGHTDATA_API_KEY is present and non-empty before calling
brightDataTools, and if missing throw an explicit Error or log a clear message
and exit so the failure is fast and informative; update the bdTools
initialization to use the validated value (referencing bdTools and
brightDataTools and the env var name BRIGHTDATA_API_KEY).

Comment on lines +19 to +21
"paths": {
"@/*": ["src/*"]
}
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

🏁 Script executed:

#!/bin/bash
# Check if src directory exists
echo "=== Checking for src directory ==="
fd -t d "^src$" -d 1

echo ""
echo "=== Searching for imports using @/* alias ==="
rg -n "from ['\"]@/" --type ts --type tsx

echo ""
echo "=== Also checking for require statements with @/ ==="
rg -n "require\(['\"]@/" --type ts --type tsx

Repository: patchy631/ai-engineering-hub

Length of output: 280


🏁 Script executed:

#!/bin/bash
# Check for src directory anywhere in the repo
echo "=== Checking for src directory (anywhere) ==="
fd -t d "src" 

echo ""
echo "=== Searching for @/ imports without file type restriction ==="
rg -n "from ['\"]@/" 

echo ""
echo "=== Checking what TypeScript/JavaScript files exist ==="
git ls-files | grep -E "\.(ts|js|tsx|jsx)$" | head -20

echo ""
echo "=== List top-level directories ==="
ls -la | grep "^d" | awk '{print $NF}'

Repository: patchy631/ai-engineering-hub

Length of output: 43578


🏁 Script executed:

#!/bin/bash
# Check amazon-product-analysis-server specifically
echo "=== amazon-product-analysis-server directory structure ==="
find amazon-product-analysis-server -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" \) | head -30

echo ""
echo "=== Checking for @/ imports in amazon-product-analysis-server ==="
rg -n "from ['\"]@/" amazon-product-analysis-server/

echo ""
echo "=== Checking for src directory in amazon-product-analysis-server ==="
find amazon-product-analysis-server -type d -name "src"

echo ""
echo "=== tsconfig.json content ==="
cat amazon-product-analysis-server/tsconfig.json

Repository: patchy631/ai-engineering-hub

Length of output: 2356


Remove the unused @/* path alias configuration.

The src/ directory does not exist in this project, and there are no imports using the @/* alias. The alias configuration at lines 19-21 should be removed, along with the reference to "src/**/*" in the include array (line 22).

🤖 Prompt for AI Agents
In @amazon-product-analysis-server/tsconfig.json around lines 19 - 21, Remove
the unused "@/*" path alias from the "paths" section in tsconfig.json (the
"paths": { "@/*": ["src/*"] } entry) and also remove the non-existent "src/**/*"
entry from the "include" array; if the "paths" object becomes empty after
removal, delete the entire "paths" section to keep tsconfig.json clean.

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

🤖 Fix all issues with AI agents
In @amazon-product-analysis-server/README.md:
- Around line 163-187: The README.md directory tree code fence lacks a language
specifier; update the fenced code block that shows
"amazon-product-analysis-server/" (the directory tree block) to include a
language tag such as "text" (i.e., change ``` to ```text) so the block is
consistently annotated and satisfies linters and formatting tools.
- Around line 147-159: The fenced code block containing the data flow diagram
lacks a language specifier; update the triple-backtick fence to include a
language (e.g., "plaintext") so the block becomes ```plaintext ... ``` ensuring
the markdown linter accepts it and rendering is explicit for the diagram in
README.md.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 094b489 and c768dd2.

📒 Files selected for processing (1)
  • amazon-product-analysis-server/README.md
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
amazon-product-analysis-server/README.md

147-147: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


163-163: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


229-229: Bare URL used

(MD034, no-bare-urls)

🔇 Additional comments (1)
amazon-product-analysis-server/README.md (1)

1-256: Comprehensive README with clear structure and helpful guidance.

The documentation effectively covers setup, configuration, development, deployment, and troubleshooting. The examples are practical (like the Amazon URL on line 229), and the architecture section clearly explains the data flow. The widget component breakdown and available tools are well documented.

One minor note: Line 249 references ensuring widgetMetadata is exported as a troubleshooting step—this could benefit from a brief explanation of what this object is or where developers should export it from (presumably widget.tsx), but this is optional as context from other files would clarify it.

Comment on lines +147 to +159
```
User → ChatGPT → MCP Server → amazon-product-analysis tool
Bright Data SDK
Amazon Website
GPT-4o Data Extraction
Widget Display
Product Insights UI
```
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

Add language specifier to data flow diagram code block.

The fenced code block for the data flow diagram is missing a language specifier. Update it to make the markdown linter happy and improve rendering clarity.

📝 Proposed fix
-```
+```plaintext
 User → ChatGPT → MCP Server → amazon-product-analysis tool
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

147-147: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In @amazon-product-analysis-server/README.md around lines 147 - 159, The fenced
code block containing the data flow diagram lacks a language specifier; update
the triple-backtick fence to include a language (e.g., "plaintext") so the block
becomes ```plaintext ... ``` ensuring the markdown linter accepts it and
rendering is explicit for the diagram in README.md.

Comment on lines +163 to +187
```
amazon-product-analysis-server/
├── index.ts # Main server file with API endpoints
├── resources/
│ └── amazon-product-analysis/
│ ├── widget.tsx # Main widget component
│ ├── types.ts # Zod schemas and TypeScript types
│ ├── server.ts # Server-side analysis logic
│ ├── brightdata-tools.ts # Bright Data integration
│ ├── utils.ts # Utility functions (image proxy)
│ ├── hooks/
│ │ └── useProductAnalysis.ts # React Query hook
│ └── components/
│ ├── ProductCard.tsx # Product display
│ ├── ImageGallery.tsx # Image carousel
│ ├── PricingDeal.tsx # Price info
│ ├── Features.tsx # Features list
│ ├── DeliveryInfo.tsx # Shipping options
│ ├── SellerInfo.tsx # Seller details
│ ├── CustomerReviews.tsx # Reviews summary
│ └── ProductSpecs.tsx # Specifications
├── package.json # Dependencies
├── tsconfig.json # TypeScript configuration
└── README.md # This file
```
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

Add language specifier to project structure code block.

The fenced code block for the directory tree is missing a language specifier. Add one for consistency and proper linting.

📝 Proposed fix
-```
+```text
 amazon-product-analysis-server/
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```
amazon-product-analysis-server/
├── index.ts # Main server file with API endpoints
├── resources/
│ └── amazon-product-analysis/
│ ├── widget.tsx # Main widget component
│ ├── types.ts # Zod schemas and TypeScript types
│ ├── server.ts # Server-side analysis logic
│ ├── brightdata-tools.ts # Bright Data integration
│ ├── utils.ts # Utility functions (image proxy)
│ ├── hooks/
│ │ └── useProductAnalysis.ts # React Query hook
│ └── components/
│ ├── ProductCard.tsx # Product display
│ ├── ImageGallery.tsx # Image carousel
│ ├── PricingDeal.tsx # Price info
│ ├── Features.tsx # Features list
│ ├── DeliveryInfo.tsx # Shipping options
│ ├── SellerInfo.tsx # Seller details
│ ├── CustomerReviews.tsx # Reviews summary
│ └── ProductSpecs.tsx # Specifications
├── package.json # Dependencies
├── tsconfig.json # TypeScript configuration
└── README.md # This file
```
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

163-163: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In @amazon-product-analysis-server/README.md around lines 163 - 187, The
README.md directory tree code fence lacks a language specifier; update the
fenced code block that shows "amazon-product-analysis-server/" (the directory
tree block) to include a language tag such as "text" (i.e., change ``` to
```text) so the block is consistently annotated and satisfies linters and
formatting tools.

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: 0

🧹 Nitpick comments (3)
amazon-product-analysis-server/README.md (3)

147-159: Add language specifier to code block (MD040).

The data flow diagram is ASCII art and should have a language specifier for consistency with markdown linting standards.

📝 Proposed fix
-```
+```text
 User → ChatGPT → MCP Server → amazon-product-analysis tool
                                        ↓
                               Bright Data SDK
                                        ↓
                                  Amazon Website
                                        ↓
                               GPT-4o Data Extraction
                                        ↓
                                 Widget Display
                                        ↓
                             Product Insights UI
-```
+```

163-187: Add language specifier to code block (MD040).

The project structure tree diagram should have a language specifier for markdown linting compliance.

📝 Proposed fix
-```
+```text
 amazon-product-analysis-server/
 ├── index.ts                              # Main server file with API endpoints
 ├── resources/
 │   └── amazon-product-analysis/
 │       ├── widget.tsx                    # Main widget component
 │       ├── types.ts                      # Zod schemas and TypeScript types
 │       ├── server.ts                     # Server-side analysis logic
 │       ├── brightdata-tools.ts           # Bright Data integration
 │       ├── utils.ts                      # Utility functions (image proxy)
 │       ├── hooks/
 │       │   └── useProductAnalysis.ts     # React Query hook
 │       └── components/
 │           ├── ProductCard.tsx           # Product display
 │           ├── ImageGallery.tsx          # Image carousel
 │           ├── PricingDeal.tsx           # Price info
 │           ├── Features.tsx              # Features list
 │           ├── DeliveryInfo.tsx          # Shipping options
 │           ├── SellerInfo.tsx            # Seller details
 │           ├── CustomerReviews.tsx       # Reviews summary
 │           └── ProductSpecs.tsx          # Specifications
 ├── package.json                          # Dependencies
 ├── tsconfig.json                         # TypeScript configuration
 └── README.md                             # This file
-```
+```

229-229: Wrap bare URL in markdown link format (MD034).

Line 229 contains a bare URL that should be wrapped in a markdown link to comply with linting standards.

📝 Proposed fix
-5. Try: "Analyze this Amazon product: https://www.amazon.in/iPhone-Pro-Max-512-Promotion/dp/B0FQG8XCJ1?ref_=ast_sto_dp"
+5. Try: "Analyze this Amazon product: [https://www.amazon.in/iPhone-Pro-Max-512-Promotion/dp/B0FQG8XCJ1?ref_=ast_sto_dp](https://www.amazon.in/iPhone-Pro-Max-512-Promotion/dp/B0FQG8XCJ1?ref_=ast_sto_dp)"
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c768dd2 and 2adb54f.

📒 Files selected for processing (1)
  • amazon-product-analysis-server/README.md
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
amazon-product-analysis-server/README.md

147-147: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


163-163: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


229-229: Bare URL used

(MD034, no-bare-urls)

🔇 Additional comments (1)
amazon-product-analysis-server/README.md (1)

1-264: Documentation is comprehensive and well-structured.

The README provides clear guidance on setup, configuration, development, deployment, and usage. The architecture section effectively explains the integration of mcp-use, Bright Data, and OpenAI. Project structure is well-documented with clear descriptions of each file's purpose. The troubleshooting section will be helpful for users encountering common issues.

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