Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: use ctx config #37

Merged
merged 1 commit into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/catalog/fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@ import { fetchProduct } from '../utils/r2.js';
/**
* Handles a GET request for a product.
* @param {Context} ctx - The context object containing request information and utilities.
* @param {Config} config - The configuration object with application settings.
* @returns {Promise<Response>} - A promise that resolves to the product response.
*/
export async function handleProductFetchRequest(ctx, config) {
export async function handleProductFetchRequest(ctx) {
try {
const sku = ctx.url.pathname.split('/').pop();
const product = await fetchProduct(ctx, config, sku);
const product = await fetchProduct(ctx, sku);

return new Response(JSON.stringify(product), {
headers: { 'Content-Type': 'application/json' },
Expand Down
10 changes: 5 additions & 5 deletions src/catalog/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ const ALLOWED_METHODS = ['GET', 'PUT'];
/**
* Handles the catalog request.
* @param {Context} ctx - The context object containing request information and utilities.
* @param {Config} config - The configuration object with application settings.
* @param {Request} request - The request object.
* @returns {Promise<Response>} - A promise that resolves to the catalog response.
*/
export default async function catalogHandler(ctx, config, request) {
export default async function catalogHandler(ctx, request) {
const { config } = ctx;
const { method } = ctx.info;

// Split the pathname into segments and filter out empty strings
Expand Down Expand Up @@ -56,13 +56,13 @@ export default async function catalogHandler(ctx, config, request) {

if (subRoute === 'lookup') {
if (ctx.info.method === 'GET') {
return handleProductLookupRequest(ctx, config);
return handleProductLookupRequest(ctx);
}
return errorResponse(405, 'method not allowed');
}

if (ctx.info.method === 'PUT') {
return handleProductSaveRequest(ctx, config, request);
return handleProductSaveRequest(ctx, request);
}
return handleProductFetchRequest(ctx, config);
return handleProductFetchRequest(ctx);
}
8 changes: 4 additions & 4 deletions src/catalog/lookup.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ import { listAllProducts, lookupSku } from '../utils/r2.js';
/**
* Handles a product lookup request.
* @param {Context} ctx - The context object.
* @param {Config} config - The configuration object.
* @returns {Promise<Response>} - A promise that resolves to the product response.
*/
export async function handleProductLookupRequest(ctx, config) {
export async function handleProductLookupRequest(ctx) {
try {
const { config } = ctx;
const { search } = ctx.url;
const params = new URLSearchParams(search);

if (params.has('urlKey') || params.has('urlkey')) {
const urlkey = params.get('urlKey') || params.get('urlkey');
const sku = await lookupSku(ctx, config, urlkey);
const sku = await lookupSku(ctx, urlkey);
return new Response(undefined, {
status: 301,
headers: {
Expand All @@ -35,7 +35,7 @@ export async function handleProductLookupRequest(ctx, config) {
});
}

const products = await listAllProducts(ctx, config);
const products = await listAllProducts(ctx);

const response = {
total: products.length,
Expand Down
11 changes: 5 additions & 6 deletions src/catalog/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,27 @@ import { saveProducts } from '../utils/r2.js';
/**
* Saves a product to R2.
* @param {Context} ctx - The context object containing request information and utilities.
* @param {Config} config - The configuration object with application settings.
* @param {Object} product - The product object to be saved.
* @returns {Promise<Object>} - A promise that resolves to the saved product.
*/
export async function putProduct(ctx, config, product) {
export async function putProduct(ctx, product) {
if (!product.sku) {
throw errorWithResponse(400, 'invalid request body: missing sku');
}

await saveProducts(ctx, config, [product]);
await saveProducts(ctx, [product]);
return product;
}

/**
* Handles a PUT request to update a product.
* @param {Context} ctx - The context object containing request information and utilities.
* @param {Config} config - The configuration object with application settings.
* @param {Request} request - The request object.
* @returns {Promise<Response>} - A promise that resolves to the product response.
*/
export async function handleProductSaveRequest(ctx, config, request) {
export async function handleProductSaveRequest(ctx, request) {
try {
const { config } = ctx;
let product;

if (config.sku === '*') {
Expand Down Expand Up @@ -74,7 +73,7 @@ export async function handleProductSaveRequest(ctx, config, request) {
return errorResponse(404, 'no path patterns found');
}

await putProduct(ctx, config, product);
await putProduct(ctx, product);

const purgePaths = matchedPathPatterns.map(
(pattern) => pattern
Expand Down
4 changes: 2 additions & 2 deletions src/content/adobe-commerce.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ async function lookupProductSKU(urlkey, config) {

/**
* @param {Context} ctx
* @param {Config} config
* @returns {Promise<Response>}
*/
export async function handle(ctx, config) {
export async function handle(ctx) {
const { config } = ctx;
const { urlkey } = config.params;
let { sku } = config.params;

Expand Down
8 changes: 4 additions & 4 deletions src/content/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ const ALLOWED_METHODS = ['GET'];

/**
* @param {Context} ctx
* @param {Config} config
* @returns {Promise<Response>}
*/
export default async function contentHandler(ctx, config) {
export default async function contentHandler(ctx) {
if (!ALLOWED_METHODS.includes(ctx.info.method)) {
return errorResponse(405, 'method not allowed');
}

const { config } = ctx;
if (!config.pageType) {
return errorResponse(400, 'invalid config for tenant site (missing pageType)');
}
console.log('config: ', JSON.stringify(config, null, 2));

if (config.catalogSource === 'helix') {
return handleHelixCommerce(ctx, config);
return handleHelixCommerce(ctx);
}
return handleAdobeCommerce(ctx, config);
return handleAdobeCommerce(ctx);
}
6 changes: 3 additions & 3 deletions src/content/helix-commerce.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ import htmlTemplateFromContext from '../templates/html/index.js';

/**
* @param {Context} ctx
* @param {Config} config
* @returns {Promise<Response>}
*/
export async function handle(ctx, config) {
export async function handle(ctx) {
const { config } = ctx;
const { urlkey } = config.params;
const { sku } = config.params;

if (!sku && !urlkey) {
return errorResponse(404, 'missing sku or urlkey');
}

const product = await fetchProduct(ctx, config, sku);
const product = await fetchProduct(ctx, sku);
const html = htmlTemplateFromContext(ctx, product, product.variants).render();
return new Response(html, {
status: 200,
Expand Down
6 changes: 3 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import content from './content/handler.js';
import catalog from './catalog/handler.js';

/**
* @type {Record<string, (ctx: Context, config: Config, request: Request) => Promise<Response>>}
* @type {Record<string, (ctx: Context, request: Request) => Promise<Response>>}
*/
const handlers = {
content,
catalog,
// eslint-disable-next-line no-unused-vars
graphql: async (ctx, config) => errorResponse(501, 'not implemented'),
graphql: async (ctx) => errorResponse(501, 'not implemented'),
};

/**
Expand Down Expand Up @@ -67,7 +67,7 @@ export default {
return errorResponse(404, 'config not found');
}

return await handlers[config.route](ctx, config, request);
return await handlers[config.route](ctx, request);
} catch (e) {
if (e.response) {
return e.response;
Expand Down
16 changes: 8 additions & 8 deletions src/utils/r2.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ import { errorWithResponse } from './http.js';
/**
* Load product by SKU
* @param {Context} ctx - The context object.
* @param {Config} config - The config object.
* @param {string} sku - The SKU of the product.
* @returns {Promise<Product>} - A promise that resolves to the product.
*/
export async function fetchProduct(ctx, config, sku) {
export async function fetchProduct(ctx, sku) {
const { config } = ctx;
const { log } = ctx;
const key = `${config.org}/${config.site}/${config.storeCode}/${config.storeViewCode}/products/${sku}.json`;
log.debug('Fetching product from R2:', key);
Expand All @@ -42,11 +42,11 @@ export async function fetchProduct(ctx, config, sku) {
/**
* Save products
* @param {Context} ctx - The context object.
* @param {Config} config - The config object.
* @param {Product[]} products - The products to save.
* @returns {Promise<void>} - A promise that resolves when the products are saved.
*/
export async function saveProducts(ctx, config, products) {
export async function saveProducts(ctx, products) {
const { config } = ctx;
const { log } = ctx;
const BATCH_SIZE = 50;

Expand Down Expand Up @@ -92,11 +92,11 @@ export async function saveProducts(ctx, config, products) {
/**
* Resolve SKU from a URL key
* @param {Context} ctx - The context object.
* @param {Config} config - The config object.
* @param {string} urlKey - The URL key.
* @returns {Promise<string>} - A promise that resolves to the SKU.
*/
export async function lookupSku(ctx, config, urlKey) {
export async function lookupSku(ctx, urlKey) {
const { config } = ctx;
// Make a HEAD request to retrieve the SKU from metadata based on the URL key
const urlKeyPath = `${config.org}/${config.site}/${config.storeCode}/${config.storeViewCode}/urlkeys/${urlKey}`;
const headResponse = await ctx.env.CATALOG_BUCKET.head(urlKeyPath);
Expand All @@ -112,10 +112,10 @@ export async function lookupSku(ctx, config, urlKey) {
/**
* List all products from R2
* @param {Context} ctx - The context object.
* @param {Config} config - The config object.
* @returns {Promise<Product[]>} - A promise that resolves to the products.
*/
export async function listAllProducts(ctx, config) {
export async function listAllProducts(ctx) {
const { config } = ctx;
const bucket = ctx.env.CATALOG_BUCKET;

const listResponse = await bucket.list({ prefix: `${config.org}/${config.site}/${config.storeCode}/${config.storeViewCode}/products/` });
Expand Down
11 changes: 5 additions & 6 deletions test/catalog/fetch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ describe('handleProductFetchRequest', () => {
let fetchProductStub;
let errorResponseStub;
let ctx;
let config;

beforeEach(async () => {
fetchProductStub = sinon.stub();
Expand All @@ -38,8 +37,8 @@ describe('handleProductFetchRequest', () => {
log: {
error: sinon.stub(),
},
config: {},
};
config = {};
});

afterEach(async () => {
Expand All @@ -52,20 +51,20 @@ describe('handleProductFetchRequest', () => {
const product = { id: sku, name: 'Test Product' };
fetchProductStub.resolves(product);

const response = await handleProductFetchRequest(ctx, config);
const response = await handleProductFetchRequest(ctx);

assert.equal(response.headers.get('Content-Type'), 'application/json');
const responseBody = await response.text();
assert.equal(responseBody, JSON.stringify(product));
sinon.assert.calledWith(fetchProductStub, ctx, config, sku);
sinon.assert.calledWith(fetchProductStub, ctx, sku);
});

it('should return e.response when fetchProduct throws an error with a response property', async () => {
const errorResponse = new Response('Not Found', { status: 404 });
const error = new ResponseError('Product not found', errorResponse);
fetchProductStub.rejects(error);

const response = await handleProductFetchRequest(ctx, config);
const response = await handleProductFetchRequest(ctx);

assert.strictEqual(response, errorResponse);
sinon.assert.notCalled(ctx.log.error);
Expand All @@ -77,7 +76,7 @@ describe('handleProductFetchRequest', () => {
const errorResp = new Response('Internal Server Error', { status: 500 });
errorResponseStub.returns(errorResp);

const response = await handleProductFetchRequest(ctx, config);
const response = await handleProductFetchRequest(ctx);

assert.equal(response.status, 500);
const responseBody = await response.text();
Expand Down
Loading