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

chore: types cleanup #82

Merged
merged 3 commits into from
Mar 7, 2025
Merged
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
6 changes: 3 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ import { resolveConfig } from './utils/config.js';
import handlers from './routes/index.js';

/**
* @param {import("@cloudflare/workers-types/experimental").Request} req
* @param {import("@cloudflare/workers-types").Request} req
*/
async function parseData(req) {
if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) {
@@ -41,7 +41,7 @@ async function parseData(req) {

/**
* @param {import("@cloudflare/workers-types/experimental").ExecutionContext} eCtx
* @param {import("@cloudflare/workers-types/experimental").Request} req
* @param {import("@cloudflare/workers-types").Request} req
* @param {Env} env
* @returns {Promise<Context>}
*/
@@ -72,7 +72,7 @@ export async function makeContext(eCtx, req, env) {

export default {
/**
* @param {import("@cloudflare/workers-types/experimental").Request} request
* @param {import("@cloudflare/workers-types").Request} request
* @param {Env} env
* @param {import("@cloudflare/workers-types/experimental").ExecutionContext} eCtx
* @returns {Promise<Response>}
2 changes: 1 addition & 1 deletion src/routes/auth/fetch.js
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ import { assertAuthorization } from '../../utils/auth.js';
import { errorResponse } from '../../utils/http.js';

/**
* @param {Context} ctx
* @type {RouteHandler}
*/
export default async function fetch(ctx) {
const { config } = ctx;
15 changes: 2 additions & 13 deletions src/routes/auth/handler.js
Original file line number Diff line number Diff line change
@@ -16,16 +16,7 @@ import update from './update.js';
import rotate from './rotate.js';

/**
* @type {Record<
* string,
* Record<
* string,
* (
* ctx: Context,
* req: import("@cloudflare/workers-types/experimental").Request
* ) => Promise<Response>
* >
* >}
* @type {Record<string, Record<string, RouteHandler>>}
*/
const handlers = {
token: {
@@ -36,9 +27,7 @@ const handlers = {
};

/**
* @param {Context} ctx
* @param {import("@cloudflare/workers-types/experimental").Request} req
* @returns {Promise<Response>}
* @type {RouteHandler}
*/
export default async function handler(ctx, req) {
const {
2 changes: 1 addition & 1 deletion src/routes/auth/rotate.js
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ import { errorResponse } from '../../utils/http.js';
import { updateToken } from './update.js';

/**
* @param {Context} ctx
* @type {RouteHandler}
*/
export default async function rotate(ctx) {
const { data } = ctx;
2 changes: 1 addition & 1 deletion src/routes/auth/update.js
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ export async function updateToken(ctx, token = generateToken()) {
}

/**
* @param {Context} ctx
* @type {RouteHandler}
*/
export default async function update(ctx) {
const { data } = ctx;
6 changes: 2 additions & 4 deletions src/routes/catalog/StorageClient.js
Original file line number Diff line number Diff line change
@@ -115,7 +115,7 @@ export default class StorageClient {
}

// Attempt to save the product
const putResponse = await env.CATALOG_BUCKET.put(key, body, {
await env.CATALOG_BUCKET.put(key, body, {
httpMetadata: { contentType: 'application/json' },
customMetadata,
});
@@ -136,7 +136,6 @@ export default class StorageClient {
*/
const result = {
sku,
status: putResponse.status,
message: 'Product saved successfully.',
...adminResponse.paths,
};
@@ -203,7 +202,7 @@ export default class StorageClient {
};
}
const { customMetadata } = productHead;
const deleteProductResponse = await env.CATALOG_BUCKET.delete(productKey);
await env.CATALOG_BUCKET.delete(productKey);

const { urlKey } = customMetadata;
if (urlKey) {
@@ -217,7 +216,6 @@ export default class StorageClient {
*/
const result = {
sku,
status: deleteProductResponse?.status,
message: 'Product deleted successfully.',
...adminResponse.paths,
};
4 changes: 1 addition & 3 deletions src/routes/catalog/fetch.js
Original file line number Diff line number Diff line change
@@ -13,9 +13,7 @@
import StorageClient from './StorageClient.js';

/**
* Handles a GET request for a product.
* @param {Context} ctx - The context object containing request information and utilities.
* @returns {Promise<Response>} - A promise that resolves to the product response.
* @type {RouteHandler}
*/
export default async function fetch(ctx) {
const { sku } = ctx.config;
17 changes: 2 additions & 15 deletions src/routes/catalog/handler.js
Original file line number Diff line number Diff line change
@@ -17,17 +17,7 @@ import update from './update.js';
import remove from './remove.js';

/**
* @type {Record<
* string,
* Record<
* string,
* (
* ctx: Context,
* req: import("@cloudflare/workers-types/experimental").Request
* ) => Promise<Response>
* >
* >
* }
* @type {Record<string, Record<string, RouteHandler>>}
*/
const handlers = {
lookup: {
@@ -47,10 +37,7 @@ const handlers = {
};

/**
* Handles productbus requests.
* @param {Context} ctx - The context object containing request information and utilities.
* @param {import("@cloudflare/workers-types/experimental").Request} request - The request object.
* @returns {Promise<Response>} - A promise that resolves to the catalog response.
* @type {RouteHandler}
*/
export default async function handler(ctx, request) {
const {
4 changes: 1 addition & 3 deletions src/routes/catalog/lookup.js
Original file line number Diff line number Diff line change
@@ -13,9 +13,7 @@
import StorageClient from './StorageClient.js';

/**
* Handles a product lookup request.
* @param {Context} ctx - The context object.
* @returns {Promise<Response>} - A promise that resolves to the product response.
* @type {RouteHandler}
*/
export default async function lookup(ctx) {
const {
4 changes: 1 addition & 3 deletions src/routes/catalog/remove.js
Original file line number Diff line number Diff line change
@@ -15,9 +15,7 @@ import { errorResponse, errorWithResponse } from '../../utils/http.js';
import StorageClient from './StorageClient.js';

/**
* Handles a DELETE request for a product.
* @param {Context} ctx - The context object containing request information and utilities.
* @returns {Promise<Response>} - A promise that resolves to the product response.
* @type {RouteHandler}
*/
export default async function remove(ctx) {
const { log, config } = ctx;
5 changes: 2 additions & 3 deletions src/routes/catalog/update.js
Original file line number Diff line number Diff line change
@@ -15,10 +15,9 @@ import { errorResponse } from '../../utils/http.js';
import StorageClient from './StorageClient.js';
import { assertAuthorization } from '../../utils/auth.js';
import { extractAndReplaceImages } from '../../utils/media.js';

/**
* Handles a PUT request to update a product.
* @param {Context} ctx - The context object containing request information and utilities.
* @returns {Promise<Response>} - A promise that resolves to the product response.
* @type {RouteHandler}
*/
export default async function update(ctx) {
const { config, log, data } = ctx;
3 changes: 1 addition & 2 deletions src/routes/config/handler.js
Original file line number Diff line number Diff line change
@@ -17,8 +17,7 @@ import { updateToken } from '../auth/update.js';
import ConfigSchema from '../../schemas/Config.js';

/**
* @param {Context} ctx
* @returns {Promise<Response>}
* @type {RouteHandler}
*/
export default async function configHandler(ctx) {
const { method } = ctx.info;
3 changes: 1 addition & 2 deletions src/routes/content/adobe-commerce/index.js
Original file line number Diff line number Diff line change
@@ -212,8 +212,7 @@ function lookupProductSKU(urlkey, config) {
}

/**
* @param {Context} ctx
* @returns {Promise<Response>}
* @type {RouteHandler}
*/
export default async function handler(ctx) {
const { config } = ctx;
4 changes: 4 additions & 0 deletions src/routes/content/adobe-commerce/queries/cs-product.js
Original file line number Diff line number Diff line change
@@ -18,6 +18,10 @@ import {
forceImagesHTTPS,
} from '../util.js';

/**
* @typedef {import('../types.d.ts').Product} Product
*/

function extractMinMaxPrice(data) {
let minPrice = data.priceRange?.minimum ?? data.price;
let maxPrice = data.priceRange?.maximum ?? data.price;
2 changes: 2 additions & 0 deletions src/routes/content/adobe-commerce/queries/cs-variants.js
Original file line number Diff line number Diff line change
@@ -18,6 +18,8 @@ import {
forceImagesHTTPS,
} from '../util.js';

/**
* @typedef {import('../types.d.ts').Variant} Variant
/**
* @param {Config} config
* @param {any} variants
10 changes: 10 additions & 0 deletions src/routes/content/adobe-commerce/templates/html/HTMLTemplate.js
Original file line number Diff line number Diff line change
@@ -15,6 +15,16 @@
import { findProductImage } from '../../util.js';
import jsonTemplateFromContext from '../json/index.js';

/**
* @typedef {import('../../types.d.ts').Product} Product
* @typedef {import('../../types.d.ts').Variant} Variant
* @typedef {import('../../types.d.ts').Image} Image
* @typedef {import('../../types.d.ts').Attribute} Attribute
* @typedef {import('../../types.d.ts').OptionValue} OptionValue
* @typedef {import('../../types.d.ts').Prices} Prices
* @typedef {import('../../types.d.ts').ProductOption} ProductOption
*/

export class HTMLTemplate {
/**
* Create a meta tag with a name attribute
5 changes: 5 additions & 0 deletions src/routes/content/adobe-commerce/templates/html/index.js
Original file line number Diff line number Diff line change
@@ -13,6 +13,11 @@
import { HTMLTemplate } from './HTMLTemplate.js';
import OVERRIDES from './overrides/index.js';

/**
* @typedef {import('../../types.d.ts').Product} Product
* @typedef {import('../../types.d.ts').Variant} Variant
*/

/**
* @param {Context} ctx
* @param {Product} product
Original file line number Diff line number Diff line change
@@ -12,6 +12,11 @@

import { HTMLTemplate } from '../HTMLTemplate.js';

/**
* @typedef {import('../../../types.d.ts').Product} Product
* @typedef {import('../../../types.d.ts').Variant} Variant
*/

export default class extends HTMLTemplate {
/**
* @param {Context} ctx
Original file line number Diff line number Diff line change
@@ -15,6 +15,11 @@
import { pruneUndefined } from '../../../../../utils/product.js';
import { findProductImage } from '../../util.js';

/**
* @typedef {import('../../types.d.ts').Product} Product
* @typedef {import('../../types.d.ts').Variant} Variant
*/

export class JSONTemplate {
/** @type {Context} */
ctx = undefined;
5 changes: 5 additions & 0 deletions src/routes/content/adobe-commerce/templates/json/index.js
Original file line number Diff line number Diff line change
@@ -13,6 +13,11 @@
import { JSONTemplate } from './JSONTemplate.js';
import OVERRIDES from './overrides/index.js';

/**
* @typedef {import('../../types.d.ts').Product} Product
* @typedef {import('../../types.d.ts').Variant} Variant
*/

/**
* @param {Context} ctx
* @param {Product} product
Original file line number Diff line number Diff line change
@@ -12,6 +12,11 @@

import { JSONTemplate } from '../JSONTemplate.js';

/**
* @typedef {import('../../../types.d.ts').Product} Product
* @typedef {import('../../../types.d.ts').Variant} Variant
*/

export default class extends JSONTemplate {
/**
* @param {Variant} [variant]
Original file line number Diff line number Diff line change
@@ -12,6 +12,11 @@

import { JSONTemplate } from '../JSONTemplate.js';

/**
* @typedef {import('../../../types.d.ts').Product} Product
* @typedef {import('../../../types.d.ts').Variant} Variant
*/

export default class extends JSONTemplate {
// eslint-disable-next-line class-methods-use-this
renderBrand() {
Original file line number Diff line number Diff line change
@@ -12,6 +12,11 @@

import { JSONTemplate } from '../JSONTemplate.js';

/**
* @typedef {import('../../../types.d.ts').Product} Product
* @typedef {import('../../../types.d.ts').Variant} Variant
*/

export default class extends JSONTemplate {
// eslint-disable-next-line class-methods-use-this
renderBrand() {
125 changes: 125 additions & 0 deletions src/routes/content/adobe-commerce/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
export interface Product {
name: string;
sku: string;
addToCartAllowed: boolean;
inStock: boolean | null;
shortDescription?: string;
metaDescription?: string;
metaKeyword?: string;
metaTitle?: string;
description?: string;
images: Image[];
prices: Prices;
attributes: Attribute[];
options: ProductOption[];
url?: string;
urlKey?: string;
externalId?: string;
variants?: Variant[]; // variants exist on products in helix commerce but not on magento
specialToDate?: string;
rating?: Rating;
links?: Link[];

// Coming only from Catalog Service at the time of writing:
lastModifiedAt?: string;

// not handled currently:
externalParentId?: string;
variantSku?: string;
optionUIDs?: string[];

// internal use:
attributeMap: Record<string, string>;
}

export interface Variant {
sku: string;
name: string;
description?: string;
url: string;
inStock: boolean;
images: Image[];
prices: Pick<Prices, 'regular' | 'final'>;
selections: string[];
attributes: Attribute[];
externalId: string;
specialToDate?: string;
gtin?: string;
rating?: Rating;

// internal use:
attributeMap: Record<string, string>;
}

interface Rating {
// number of ratings
count?: number;
// number of reviews
reviews?: number;
// rating value
value: number | string;
// range of ratings, highest
best?: number | string;
// range of ratings, lowest
worst?: number | string;
}

interface Link {
types: string[];
sku: string;
urlKey: string;
prices: Prices;
}

interface Image {
url: string;
label: string;
roles: string[];
}

interface Price {
amount?: number;
currency?: string;
maximumAmount?: number;
minimumAmount?: number;
variant?: 'default' | 'strikethrough';
}

interface Prices {
regular: Price;
final: Price;
visible: boolean;
}

export interface ProductOption {
id: string;
type: 'text' | 'image' | 'color' | 'dropdown';
typename:
| 'ProductViewOptionValueProduct'
| 'ProductViewOptionValueSwatch'
| 'ProductViewOptionValueConfiguration';
label: string;
required: boolean;
multiple: boolean;
items: OptionValue[];
}

interface OptionValue {
id: string;
label: string;
inStock: boolean;
value: string;
selected: boolean;
type: string;
product?: {
name: string;
sku: string;
prices?: Prices;
};
}

interface Attribute {
name: string;
label: string;
value: string;
}
6 changes: 6 additions & 0 deletions src/routes/content/adobe-commerce/util.js
Original file line number Diff line number Diff line change
@@ -12,6 +12,12 @@

import { pruneUndefined } from '../../../utils/product.js';

/**
* @typedef {import('./types.d.ts').Product} Product
* @typedef {import('./types.d.ts').Variant} Variant
* @typedef {import('./types.d.ts').Rating} Rating
*/

/**
* This function combines an array of strings with interpolated
* parameters to create a GraphQL query string.
11 changes: 5 additions & 6 deletions src/routes/content/handler.js
Original file line number Diff line number Diff line change
@@ -18,10 +18,9 @@ import media from './media.js';
const ALLOWED_METHODS = ['GET'];

/**
* @param {Context} ctx
* @returns {Promise<Response>}
* @type {RouteHandler}
*/
export default async function contentHandler(ctx) {
export default async function contentHandler(ctx, req) {
const {
log,
config,
@@ -33,7 +32,7 @@ export default async function contentHandler(ctx) {
}

if (['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp'].includes(info.extension)) {
return media(ctx);
return media(ctx, req);
}

if (!config.pageType) {
@@ -42,8 +41,8 @@ export default async function contentHandler(ctx) {
log.debug('config: ', JSON.stringify(config, null, 2));

if (config.catalogSource === 'adobe-commerce') {
return adobeCommerce(ctx);
return adobeCommerce(ctx, req);
}

return helixCommerce(ctx);
return helixCommerce(ctx, req);
}
3 changes: 1 addition & 2 deletions src/routes/content/helix-commerce.js
Original file line number Diff line number Diff line change
@@ -145,8 +145,7 @@ ${indent(product.images?.map(pictureTemplate).join('\n'), 10)}
</html>`;

/**
* @param {Context} ctx
* @returns {Promise<Response>}
* @type {RouteHandler}
*/
export default async function handler(ctx) {
const { config: { params } } = ctx;
2 changes: 1 addition & 1 deletion src/routes/content/media.js
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
import { errorResponse } from '../../utils/http.js';

/**
* @param {Context} ctx
* @type {RouteHandler}
*/
export default async function handler(ctx) {
const {
8 changes: 1 addition & 7 deletions src/routes/index.js
Original file line number Diff line number Diff line change
@@ -16,13 +16,7 @@ import config from './config/handler.js';
import auth from './auth/handler.js';

/**
* @type {Record<
* string,
* (
* ctx: Context,
* request: import("@cloudflare/workers-types/experimental").Request
* ) => Promise<Response>
* >}
* @type {Record<string, RouteHandler>}
*/
export default {
content,
128 changes: 2 additions & 126 deletions src/types.d.ts
Original file line number Diff line number Diff line change
@@ -272,132 +272,6 @@ declare global {
executionContext: ExecutionContext;
}

export interface Product {
name: string;
sku: string;
addToCartAllowed: boolean;
inStock: boolean | null;
shortDescription?: string;
metaDescription?: string;
metaKeyword?: string;
metaTitle?: string;
description?: string;
images: Image[];
prices: Prices;
attributes: Attribute[];
options: ProductOption[];
url?: string;
urlKey?: string;
externalId?: string;
variants?: Variant[]; // variants exist on products in helix commerce but not on magento
specialToDate?: string;
rating?: Rating;
links?: Link[];

// Coming only from Catalog Service at the time of writing:
lastModifiedAt?: string;

// not handled currently:
externalParentId?: string;
variantSku?: string;
optionUIDs?: string[];

// internal use:
attributeMap: Record<string, string>;
}

export interface Variant {
sku: string;
name: string;
description?: string;
url: string;
inStock: boolean;
images: Image[];
prices: Pick<Prices, 'regular' | 'final'>;
selections: string[];
attributes: Attribute[];
externalId: string;
specialToDate?: string;
gtin?: string;
rating?: Rating;

// internal use:
attributeMap: Record<string, string>;
}

interface Rating {
// number of ratings
count?: number;
// number of reviews
reviews?: number;
// rating value
value: number | string;
// range of ratings, highest
best?: number | string;
// range of ratings, lowest
worst?: number | string;
}

interface Link {
types: string[];
sku: string;
urlKey: string;
prices: Prices;
}

interface Image {
url: string;
label: string;
roles: string[];
}

interface Price {
amount?: number;
currency?: string;
maximumAmount?: number;
minimumAmount?: number;
variant?: 'default' | 'strikethrough';
}

interface Prices {
regular: Price;
final: Price;
visible: boolean;
}

export interface ProductOption {
id: string;
type: 'text' | 'image' | 'color' | 'dropdown';
typename:
| 'ProductViewOptionValueProduct'
| 'ProductViewOptionValueSwatch'
| 'ProductViewOptionValueConfiguration';
label: string;
required: boolean;
multiple: boolean;
items: OptionValue[];
}

interface OptionValue {
id: string;
label: string;
inStock: boolean;
value: string;
selected: boolean;
type: string;
product?: {
name: string;
sku: string;
prices?: Prices;
};
}

interface Attribute {
name: string;
label: string;
value: string;
}

interface BatchResult {
sku: string;
status: number;
@@ -414,6 +288,8 @@ declare global {
status: number;
message?: string;
}

export type RouteHandler = (ctx: Context, request: import("@cloudflare/workers-types").Request) => Promise<Response>;
}

export { };
4 changes: 2 additions & 2 deletions src/utils/admin.js
Original file line number Diff line number Diff line change
@@ -10,8 +10,6 @@
* governing permissions and limitations under the License.
*/

/* eslint-disable no-await-in-loop */

import { getPreviewPublishPaths } from './product.js';

/**
@@ -125,7 +123,9 @@ export async function callPreviewPublish(config, method, sku, urlKey) {

// Conditional sequencing or parallel execution based on the method
const operations = method === 'POST'
// eslint-disable-next-line no-await-in-loop
? [await callAdminWithOp('preview'), await callAdminWithOp('live')]
// eslint-disable-next-line no-await-in-loop
: await Promise.all(['preview', 'live'].map(callAdminWithOp));

operations.forEach(({ op, status, message }) => {
14 changes: 0 additions & 14 deletions test/routes/catalog/StorageClient.test.js
Original file line number Diff line number Diff line change
@@ -595,7 +595,6 @@ describe('StorageClient Class Tests', () => {
assert.deepStrictEqual(results, [
{
sku: 'sku1',
status: 200,
message: 'Product saved successfully.',
'/products/product-1/sku1': {
preview: {
@@ -608,7 +607,6 @@ describe('StorageClient Class Tests', () => {
},
{
sku: 'sku2',
status: 200,
message: 'Product saved successfully.',
'/products/product-2/sku2': {
preview: {
@@ -688,7 +686,6 @@ describe('StorageClient Class Tests', () => {
assert.deepStrictEqual(results, [
{
sku: 'sku1',
status: 200,
message: 'Product saved successfully.',
'/products/sku1': {
preview: {
@@ -701,7 +698,6 @@ describe('StorageClient Class Tests', () => {
},
{
sku: 'sku2',
status: 200,
message: 'Product saved successfully.',
'/products/sku2': {
preview: {
@@ -798,7 +794,6 @@ describe('StorageClient Class Tests', () => {
assert.deepStrictEqual(results, [
{
sku: 'sku1',
status: 200,
message: 'Product saved successfully.',
'/products/product-1/sku1': {
preview: {
@@ -976,7 +971,6 @@ describe('StorageClient Class Tests', () => {
assert.deepStrictEqual(results, [
{
sku: 'sku1',
status: 200,
message: 'Product saved successfully.',
'/products/product-1/sku1': {
preview: {
@@ -989,7 +983,6 @@ describe('StorageClient Class Tests', () => {
},
{
sku: 'sku2',
status: 200,
message: 'Product saved successfully.',
'/products/product-2/sku2': {
preview: {
@@ -1158,7 +1151,6 @@ describe('StorageClient Class Tests', () => {
assert.deepStrictEqual(results, [
{
sku: 'sku1',
status: 200,
message: 'Product saved successfully.',
'/products/product-1/sku1': {
preview: {
@@ -1171,7 +1163,6 @@ describe('StorageClient Class Tests', () => {
},
{
sku: 'sku2',
status: 200,
message: 'Product saved successfully.',
'/products/sku2': {
preview: {
@@ -1184,7 +1175,6 @@ describe('StorageClient Class Tests', () => {
},
{
sku: 'sku3',
status: 200,
message: 'Product saved successfully.',
'/products/product-3/sku3': {
preview: {
@@ -1560,7 +1550,6 @@ describe('StorageClient Class Tests', () => {
assert.deepStrictEqual(results, [
{
sku: 'sku1',
status: 200,
message: 'Product deleted successfully.',
'/products/product-1/sku1': {
preview: {
@@ -1573,7 +1562,6 @@ describe('StorageClient Class Tests', () => {
},
{
sku: 'sku2',
status: 200,
message: 'Product deleted successfully.',
'/products/product-2/sku2': {
preview: {
@@ -1650,7 +1638,6 @@ describe('StorageClient Class Tests', () => {
assert.deepStrictEqual(results, [
{
sku: 'sku1',
status: 200,
message: 'Product deleted successfully.',
'/products/sku1': {
preview: {
@@ -1663,7 +1650,6 @@ describe('StorageClient Class Tests', () => {
},
{
sku: 'sku2',
status: 200,
message: 'Product deleted successfully.',
'/products/sku2': {
preview: {