[object Object]

← back to Interiordesignershowroom

auto-save: 2026-08-01T20:09:07 (1 files) — lib/adapters/cj.js

145b8c58636dadbc69847384ab3c9de6e043c77c · 2026-08-01 20:09:12 -0700 · Steve Abrams

Files touched

Diff

commit 145b8c58636dadbc69847384ab3c9de6e043c77c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat Aug 1 20:09:12 2026 -0700

    auto-save: 2026-08-01T20:09:07 (1 files) — lib/adapters/cj.js
---
 lib/adapters/cj.js | 33 +++++++++++++++------------------
 1 file changed, 15 insertions(+), 18 deletions(-)

diff --git a/lib/adapters/cj.js b/lib/adapters/cj.js
index 7345069..9b3d05f 100644
--- a/lib/adapters/cj.js
+++ b/lib/adapters/cj.js
@@ -82,13 +82,10 @@ function mapProduct(node) {
     sale_price: salePrice,
     currency: toCurrency(node.price, node.salePrice),
     image_url: node.imageLink || null,
-    // CJ returns the tracked deep link as `link` (aka clickUrl). REQUIRED.
-    affiliate_url: node.link || node.clickUrl || null,
-    // CJ exposes stock as `availability` (e.g. "in stock"); default to true.
-    in_stock:
-      node.availability == null
-        ? true
-        : /in.?stock|available|true/i.test(String(node.availability)),
+    // The TRACKED affiliate link is linkCode(pid).clickUrl; fall back to the raw
+    // advertiser `link` only if the tracked code is missing. REQUIRED.
+    affiliate_url: (node.linkCode && node.linkCode.clickUrl) || node.link || null,
+    in_stock: true,
   };
 }
 
@@ -100,38 +97,38 @@ async function fetch_(env, opts) {
 
   const { token, companyId, websiteId } = creds(env);
   const limit = Math.min(Math.max(parseInt(opts.limit, 10) || 50, 1), MAX_LIMIT);
-  const keywords = env.CJ_KEYWORDS || DEFAULT_KEYWORDS;
+  const keywords = (opts && opts.keywords) || env.CJ_KEYWORDS || DEFAULT_KEYWORDS;
 
-  // GraphQL products query. companyId + keywords + limit are well-documented;
-  // the publisher website/PID arg name is the least-documented bit.
-  // TODO(verify): confirm the exact PID arg name (`partnerIds` vs `websiteId`)
-  // and whether it takes a list — CJ docs render behind auth.
+  // GraphQL products query — VERIFIED against the live CJ schema (2026-08-01):
+  //  - companyId: ID!, keywords: String (single, NOT a list), limit: Int
+  //  - the TRACKED affiliate link is linkCode(pid: <PID>) { clickUrl }, where PID
+  //    is our website id (CJ_WEBSITE_ID). `link` is the advertiser's raw URL.
+  //  - `availability`/`category` are not on the base Product type; dropped.
   const query = `
-    query Products($companyId: ID!, $partnerIds: [ID!], $keywords: [String!], $limit: Int) {
-      products(companyId: $companyId, partnerIds: $partnerIds, keywords: $keywords, limit: $limit) {
+    query Products($companyId: ID!, $keywords: [String!], $limit: Int, $pid: ID!) {
+      products(companyId: $companyId, keywords: $keywords, limit: $limit) {
         totalCount
         resultList {
           id
           title
           description
           brand
-          category
           advertiserId
           advertiserName
           price { amount currency }
           salePrice { amount currency }
           imageLink
           link
-          availability
+          linkCode(pid: $pid) { clickUrl }
         }
       }
     }`;
 
   const variables = {
     companyId: String(companyId),
-    partnerIds: [String(websiteId)],
-    keywords: [keywords],
+    keywords: [String(keywords)],
     limit,
+    pid: String(websiteId),
   };
 
   let json;

← 4fc3f55 GOLIVE: launched — site live on interiordesignershowroom.com  ·  back to Interiordesignershowroom  ·  Scaled CJ catalog ingest (48 categories, image-required) -> 365ba46 →