Skip to content

Commit 918ca03

Browse files
committed
fix: pull from helix catalog
1 parent 11bb8bc commit 918ca03

File tree

7 files changed

+71
-36
lines changed

7 files changed

+71
-36
lines changed

src/catalog/product.js

+10-5
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,17 @@ export async function handleProductPutRequest(ctx, config, request) {
149149
for (const key of matchedKeys) {
150150
let path = key.replace('{{sku}}', product.sku);
151151

152-
if (key.includes('{{urlkey}}') && product.url_key) {
153-
path = path.replace('{{urlkey}}', product.url_key);
152+
if (key.includes('{{urlkey}}') && product.urlKey) {
153+
path = path.replace('{{urlkey}}', product.urlKey);
154+
}
155+
const previewResponse = await callAdmin(config, 'preview', path);
156+
if (!previewResponse.ok) {
157+
return errorResponse(400, 'failed to preview product');
158+
}
159+
const publishResponse = await callAdmin(config, 'publish', path);
160+
if (!publishResponse.ok) {
161+
return errorResponse(400, 'failed to publish product');
154162
}
155-
156-
await callAdmin(config, 'preview', path);
157-
await callAdmin(config, 'publish', path);
158163
}
159164
}
160165
return new Response(undefined, { status: 201 });

src/config.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ export async function resolveConfig(ctx, overrides = {}) {
108108
// Ensure that there are exactly 4 segments after 'catalog' (env, store, storeView, product)
109109
if (catalogIndex !== -1 && pathSegments.length >= catalogIndex + 4) {
110110
resolved.env = pathSegments[catalogIndex + 1];
111-
resolved.store = pathSegments[catalogIndex + 2];
112-
resolved.storeView = pathSegments[catalogIndex + 3];
111+
resolved.storeCode = pathSegments[catalogIndex + 2];
112+
resolved.storeViewCode = pathSegments[catalogIndex + 3];
113113
resolved.subRoute = pathSegments[catalogIndex + 4];
114114
resolved.sku = pathSegments[catalogIndex + 5];
115115
} else {

src/index.js

+32-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import getProductSKUQuery from './queries/core-product-sku.js';
1818
import HTML_TEMPLATE from './templates/html.js';
1919
import { resolveConfig } from './config.js';
2020
import { handleProductGetRequest, handleProductPutRequest } from './catalog/product.js';
21+
import { loadProductFromR2 } from './utils/r2.js';
2122

2223
const ALLOWED_METHODS = ['GET', 'PUT'];
2324

@@ -171,7 +172,7 @@ async function lookupProductSKU(urlkey, config) {
171172
* @param {Config} config
172173
*/
173174
// @ts-ignore
174-
async function handlePDPRequest(ctx, config) {
175+
async function handleMagentoPDPRequest(ctx, config) {
175176
const { urlkey } = config.params;
176177
let { sku } = config.params;
177178

@@ -201,6 +202,30 @@ async function handlePDPRequest(ctx, config) {
201202
});
202203
}
203204

205+
/**
206+
* @param {Context} ctx
207+
* @param {Config} config
208+
*/
209+
// @ts-ignore
210+
async function handleHelixPDPRequest(ctx, config) {
211+
const { urlkey } = config.params;
212+
const { sku } = config.params;
213+
214+
if (!sku && !urlkey) {
215+
return errorResponse(404, 'missing sku or urlkey');
216+
}
217+
218+
config.env = 'prod';
219+
const product = await loadProductFromR2(ctx, config, sku);
220+
const html = HTML_TEMPLATE(product, product.variants);
221+
return new Response(html, {
222+
status: 200,
223+
headers: {
224+
'content-type': 'text/html',
225+
},
226+
});
227+
}
228+
204229
/**
205230
* @type {Record<string, (ctx: Context, config: Config, request: Request) => Promise<Response>>}
206231
*/
@@ -209,7 +234,12 @@ const handlers = {
209234
if (config.pageType !== 'product') {
210235
return errorResponse(404, 'page type not supported');
211236
}
212-
return handlePDPRequest(ctx, config);
237+
238+
if (config.catalogSource === 'helix') {
239+
return handleHelixPDPRequest(ctx, config);
240+
}
241+
242+
return handleMagentoPDPRequest(ctx, config);
213243
},
214244
catalog: async (ctx, config, request) => {
215245
if (ctx.info.method !== 'PUT' && ctx.info.method !== 'GET') {

src/templates/html.js

+12-13
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ export default (product, variants) => {
5151
} = product;
5252

5353
const image = findProductImage(product, variants);
54-
5554
return /* html */`\
5655
<!DOCTYPE html>
5756
<html>
@@ -64,14 +63,14 @@ export default (product, variants) => {
6463
<meta property="og:image:secure_url" content="${image?.url}">
6564
<meta property="og:type" content="product">
6665
<meta property="product:availability" content="${inStock ? 'In stock' : 'Out of stock'}">
67-
<meta property="product:price.amount" content="${prices.final.amount}">
68-
<meta property="product:price.currency" content="${prices.final.currency}">
66+
<meta property="product:price.amount" content="${prices?.final?.amount}">
67+
<meta property="product:price.currency" content="${prices?.final?.currency}">
6968
<meta name="twitter:card" content="summary_large_image">
7069
<meta name="twitter:title" content="${name}">
7170
<meta name="twitter:image" content="${image?.url}">
7271
<meta name="twitter:description" content="${metaDescription || description}">
7372
<meta name="twitter:label1" content="Price">
74-
<meta name="twitter:data1" content="${prices.final.amount}">
73+
<meta name="twitter:data1" content="${prices?.final?.amount}">
7574
<meta name="twitter:label2" content="Availability">
7675
<meta name="twitter:data2" content="${inStock ? 'In stock' : 'Out of stock'}">
7776
<meta name="keywords" content="${metaKeyword}">
@@ -96,7 +95,7 @@ export default (product, variants) => {
9695
${description ? `<p>${description}</p>` : ''}
9796
<div class="product-images">
9897
<div>
99-
${images.map((img) => `\
98+
${images?.map((img) => `\
10099
<div>
101100
<picture>
102101
<source type="image/webp" srcset="${img.url}" alt="" media="(min-width: 600px)">
@@ -109,7 +108,7 @@ ${images.map((img) => `\
109108
</div>
110109
111110
<div class="product-attributes">
112-
${attributes.map((attr) => `\
111+
${attributes?.map((attr) => `\
113112
<div>
114113
<div>${attr.name}</div>
115114
<div>${attr.label}</div>
@@ -118,7 +117,7 @@ ${attributes.map((attr) => `\
118117
</div>
119118
120119
<div class="product-options">
121-
${options.map((opt) => `\
120+
${options?.map((opt) => `\
122121
<div>
123122
<div>${opt.id}</div>
124123
<div>${opt.label}</div>
@@ -127,7 +126,7 @@ ${options.map((opt) => `\
127126
<div>${opt.multiple ? 'multiple' : ''}</div>
128127
<div>${opt.required === true ? 'required' : ''}</div>
129128
</div>
130-
${opt.items.map((item) => `\
129+
${opt.items?.map((item) => `\
131130
<div>
132131
<div>option</div>
133132
<div>${item.id}</div>
@@ -139,23 +138,23 @@ ${opt.items.map((item) => `\
139138
</div>
140139
141140
<div class="product-variants">
142-
${variants.map((v) => `\
141+
${variants?.map((v) => `\
143142
<div>
144143
<div>${v.sku}</div>
145144
<div>${v.name}</div>
146145
<div>${v.inStock ? 'inStock' : ''}</div>
147-
<div>Regular: ${v.prices.regular.amount} ${v.prices.regular.currency}${priceRange(v.prices.regular.minimumAmount, v.prices.regular.maximumAmount)}</div>
148-
<div>Final: ${v.prices.final.amount} ${v.prices.final.currency}${priceRange(v.prices.final.minimumAmount, v.prices.final.maximumAmount)}</div>
146+
<div>Regular: ${v.prices?.regular?.amount} ${v.prices?.regular?.currency}${priceRange(v.prices?.regular?.minimumAmount, v.prices?.regular?.maximumAmount)}</div>
147+
<div>Final: ${v.prices?.final?.amount} ${v.prices?.final?.currency}${priceRange(v.prices?.final?.minimumAmount, v.prices?.final?.maximumAmount)}</div>
149148
<div>
150-
${v.images.map((img) => `\
149+
${v.images?.map((img) => `\
151150
<picture>
152151
<source type="image/webp" srcset="${img.url}" alt="" media="(min-width: 600px)">
153152
<source type="image/webp" srcset="${img.url}">
154153
<source type="image/png" srcset="${img.url}" media="(min-width: 600px)">
155154
<img loading="lazy" alt="${img.label}" src="${img.url}">
156155
</picture>`).join('\n')}
157156
</div>
158-
<div>${v.selections.join(', ')}</div>
157+
<div>${v.selections?.join(', ')}</div>
159158
</div>`).join('\n')}
160159
</div>
161160
</main>

src/templates/json-ld.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default (product, variants) => {
3333
} = product;
3434

3535
const image = images?.[0]?.url ?? findProductImage(product, variants)?.url;
36-
const brandName = attributes.find((attr) => attr.name === 'brand')?.value;
36+
const brandName = attributes?.find((attr) => attr.name === 'brand')?.value;
3737

3838
return JSON.stringify(pruneUndefined({
3939
'@context': 'http://schema.org',
@@ -51,17 +51,17 @@ export default (product, variants) => {
5151
url,
5252
image,
5353
availability: inStock ? 'InStock' : 'OutOfStock',
54-
price: prices.final.amount,
55-
priceCurrency: prices.final.currency,
54+
price: prices?.final?.amount,
55+
priceCurrency: prices?.final?.currency,
5656
},
5757
...variants.map((v) => ({
5858
'@type': 'Offer',
5959
sku: v.sku,
6060
url: v.url,
6161
image: v.images?.[0]?.url ?? image,
6262
availability: v.inStock ? 'InStock' : 'OutOfStock',
63-
price: v.prices.final.amount,
64-
priceCurrency: v.prices.final.currency,
63+
price: v.prices?.final?.amount,
64+
priceCurrency: v.prices?.final?.currency,
6565

6666
})),
6767
],

src/types.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ declare global {
1313
storeViewCode: string;
1414
storeCode: string;
1515
coreEndpoint: string;
16+
catalogSource: string;
1617
catalogEndpoint?: string;
1718
sku?: string;
1819
confMap: Record<string, Config>;

src/utils/r2.js

+9-9
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export async function getSyncTimestamp(ctx, config) {
4343

4444
// Helper function to load product from R2 using SKU
4545
export async function loadProductFromR2(ctx, config, sku) {
46-
const key = `${config.org}/${config.site}/${config.env}/${config.store}/${config.storeView}/${sku}.json`;
46+
const key = `${config.org}/${config.site}/${config.env}/${config.storeCode}/${config.storeViewCode}/${sku}.json`;
4747
const object = await ctx.env.CATALOG_BUCKET.get(key);
4848

4949
if (!object) {
@@ -65,18 +65,18 @@ export async function saveProductsToR2(ctx, config, products) {
6565
const storeProductsBatch = async (batch) => {
6666
const storePromises = batch.map(async (product) => {
6767
try {
68-
const { sku, name, url_key } = product;
69-
const key = `${config.org}/${config.site}/${config.env}/${config.store}/${config.storeView}/${sku}.json`;
68+
const { sku, name, urlKey } = product;
69+
const key = `${config.org}/${config.site}/${config.env}/${config.storeCode}/${config.storeViewCode}/${sku}.json`;
7070
const body = JSON.stringify(product);
71-
const customMetadata = { sku, name, url_key };
71+
const customMetadata = { sku, name, urlKey };
7272

7373
const productPromise = ctx.env.CATALOG_BUCKET.put(key, body, {
7474
httpMetadata: { contentType: 'application/json' },
7575
customMetadata,
7676
});
7777

78-
if (url_key) {
79-
const metadataKey = `${config.org}/${config.site}/${config.env}/${config.store}/${config.storeView}/urlkeys/${url_key}`;
78+
if (urlKey) {
79+
const metadataKey = `${config.org}/${config.site}/${config.env}/${config.storeCode}/${config.storeViewCode}/urlkeys/${urlKey}`;
8080
const metadataPromise = ctx.env.CATALOG_BUCKET.put(metadataKey, '', {
8181
httpMetadata: { contentType: 'application/octet-stream' },
8282
customMetadata,
@@ -103,14 +103,14 @@ export async function saveProductsToR2(ctx, config, products) {
103103
export async function listAllProducts(ctx, config) {
104104
const bucket = ctx.env.CATALOG_BUCKET;
105105

106-
console.log(`${config.org}/${config.site}/${config.env}/${config.store}/${config.storeView}/`);
107-
const listResponse = await bucket.list({ prefix: `${config.org}/${config.site}/${config.env}/${config.store}/${config.storeView}/ ` });
106+
console.log(`${config.org}/${config.site}/${config.env}/${config.storeCode}/${config.storeViewCode}/`);
107+
const listResponse = await bucket.list({ prefix: `${config.org}/${config.site}/${config.env}/${config.storeCode}/${config.storeViewCode}/` });
108108
const files = listResponse.objects;
109109

110110
const batchSize = 50; // Define the batch size
111111
const customMetadataArray = [];
112112

113-
const excludeDirectory = `${config.org}/${config.site}/${config.env}/${config.store}/${config.storeView}/ urlkeys/`;
113+
const excludeDirectory = `${config.org}/${config.site}/${config.env}/${config.storeCode}/${config.storeViewCode}/ urlkeys/`;
114114

115115
// Helper function to split the array into chunks of a specific size
116116
function chunkArray(array, size) {

0 commit comments

Comments
 (0)