Creates a new instance of the supplier base class. Initializes the supplier with query parameters, request limits, and abort controller. Sets up logging and default product values.
The search term to query products for
The maximum number of results to return (default: 5)
Optional
controller: AbortControllerAbortController instance for managing request cancellation
// Create a supplier with default limit
const supplier = new MySupplier("sodium chloride", undefined, new AbortController());
// Create a supplier with custom limit
const supplier = new MySupplier("acetone", 10, new AbortController());
// Create a supplier and handle cancellation
const controller = new AbortController();
const supplier = new MySupplier("ethanol", 5, controller);
// Later, to cancel all pending requests:
controller.abort();
Initializes the cache for the supplier. This is called after construction to ensure supplierName is set.
Protected
setupPlaceholder for any setup that needs to be done before the query is made. Override this in subclasses if you need to perform setup (e.g., authentication, token fetching).
A promise that resolves when the setup is complete.
Protected
httpRetrieves HTTP headers from a URL using a HEAD request. Useful for checking content types, caching headers, and other metadata without downloading the full response.
The URL to fetch headers from
Promise resolving to the response headers or void if request fails
Protected
httpSends a POST request to the given URL with the given body and headers. Handles request setup, error handling, and response caching.
The request configuration options
Promise resolving to the Response object or void if request fails
// Basic POST request
const response = await supplier.httpPost({
path: '/api/v1/products',
body: { name: 'Test Chemical' }
});
// POST with custom headers
const response = await supplier.httpPost({
path: '/api/v1/products',
body: { name: 'Test Chemical' },
headers: {
'Authorization': 'Bearer token123',
'Content-Type': 'application/json'
}
});
Protected
httpSends a POST request and returns the response as a JSON object.
The parameters for the POST request.
The response from the POST request as a JSON object.
// Basic usage
const data = await supplier.httpPostJson({
path: '/api/v1/products',
body: { name: 'John' }
});
// With custom headers and error handling
try {
const data = await supplier.httpPostJson({
path: '/api/v1/products',
body: { name: 'John' },
headers: { 'Authorization': 'Bearer token123' }
});
if (data) {
console.log('Created:', data);
}
} catch (err) {
console.error('POST JSON failed:', err);
}
Protected
httpSends a POST request and returns the response as a HTML string.
The request configuration options
Promise resolving to the HTML response as a string or void if request fails
Protected
httpSends a GET request to the given URL with the specified options. Handles request setup, error handling, and response caching.
The request configuration options
Promise resolving to the Response object or void if request fails
// Basic GET request
const response = await supplier.httpGet({
path: '/products/search',
params: { query: 'sodium chloride' }
});
// GET with custom headers
const response = await supplier.httpGet({
path: '/products/search',
headers: { 'Accept': 'application/json' }
});
Protected
fuzzyFilters an array of data using fuzzy string matching to find items that closely match a query string. Uses the WRatio algorithm from fuzzball for string similarity comparison.
The search string to match against
Array of data objects to search through
Minimum similarity score (0-100) for a match to be included (default: 40)
Array of matching data objects with added fuzzy match metadata
// Example with simple string array
const products = [
{ title: "Sodium Chloride", price: 29.99 },
{ title: "Sodium Hydroxide", price: 39.99 },
{ title: "Potassium Chloride", price: 19.99 }
];
const matches = this.fuzzyFilter("sodium chloride", products);
// Returns: [
// {
// title: "Sodium Chloride",
// price: 29.99,
// ___fuzz: { score: 100, idx: 0 }
// },
// {
// title: "Sodium Hydroxide",
// price: 39.99,
// ___fuzz: { score: 85, idx: 1 }
// }
// ]
// Example with custom cutoff
const strictMatches = this.fuzzyFilter("sodium chloride", products, 90);
// Returns only exact matches with score >= 90
// Example with different data structure
const chemicals = [
{ name: "NaCl", formula: "Sodium Chloride" },
{ name: "NaOH", formula: "Sodium Hydroxide" }
];
// Override titleSelector to use formula field
this.titleSelector = (data) => data.formula;
const formulaMatches = this.fuzzyFilter("sodium chloride", chemicals);
Protected
httpMakes an HTTP GET request and returns the response as a string. Handles request configuration, error handling, and HTML parsing.
The request configuration options
Promise resolving to the HTML response as a string or void if request fails
// Basic GET request
const html = await this.httpGetHtml({
path: "/api/products",
params: { search: "sodium" }
});
// GET request with custom headers
const html = await this.httpGetHtml({
path: "/api/products",
headers: {
"Authorization": "Bearer token123",
"Accept": "text/html"
}
});
// GET request with custom host
const html = await this.httpGetHtml({
path: "/products",
host: "api.supplier.com",
params: { limit: 10 }
});
Protected
httpMakes an HTTP GET request and returns the response as parsed JSON. Handles request configuration, error handling, and JSON parsing.
The request configuration options
Promise resolving to the parsed JSON response or void if request fails
// Basic GET request
const data = await supplier.httpGetJson({ path: '/api/products', params: { search: 'sodium' } });
// GET request with custom headers
const data = await supplier.httpGetJson({
path: '/api/products',
headers: {
'Authorization': 'Bearer token123',
'Accept': 'application/json'
}
});
Protected
queryExecutes a product search query with caching support. First checks the cache for existing results, then falls back to the actual query if needed. The limit parameter is only used for the actual query and doesn't affect caching.
The search term to query products for
The maximum number of results to return (defaults to instance limit)
Promise resolving to array of product builders or void if search fails
Executes the supplier's search query and returns the results. This method will execute all results concurrently (to the limits set in the supplier class), and resolve to an array of product objects.
Promise resolving to an array of products
Protected
finishFinalizes a partial product by adding computed properties and validating the result. This method:
The ProductBuilder instance containing the partial product to finalize
Promise resolving to a complete Product object or void if validation fails
// Example with a valid partial product
const builder = new ProductBuilder<Product>(this.baseURL);
builder
.setBasicInfo("Sodium Chloride", "/products/nacl", "ChemSupplier")
.setPricing(29.99, "USD", "$")
.setQuantity(500, "g");
const finishedProduct = await this.finishProduct(builder);
if (finishedProduct) {
console.log("Finalized product:", {
title: finishedProduct.title,
price: finishedProduct.price,
quantity: finishedProduct.quantity,
uom: finishedProduct.uom,
usdPrice: finishedProduct.usdPrice,
baseQuantity: finishedProduct.baseQuantity
});
}
// Example with an invalid partial product
const invalidBuilder = new ProductBuilder<Product>(this.baseURL);
invalidBuilder.setBasicInfo("Sodium Chloride", "/products/nacl", "ChemSupplier");
// Missing required fields
const invalidProduct = await this.finishProduct(invalidBuilder);
if (!invalidProduct) {
console.log("Failed to finalize product - missing required fields");
}
Protected
hrefTakes in either a relative or absolute URL and returns an absolute URL. This is useful for when you aren't sure if the link (retrieved from parsed text, a setting, an element, an anchor value, etc) is absolute or not. Using relative links will result in http://chrome-extension://... being added to the link.
URL object or string
Optional
params: Maybe<RequestParams>The parameters to add to the URL.
Optional
host: stringThe host to use for overrides (eg: needing to call a different host for an API)
absolute URL
this.href('/some/path')
// https://supplier_base_url.com/some/path
this.href('https://supplier_base_url.com/some/path', null, 'another_host.com')
// https://another_host.com/some/path
this.href('/some/path', { a: 'b', c: 'd' }, 'another_host.com')
// http://another_host.com/some/path?a=b&c=d
this.href('https://supplier_base_url.com/some/path')
// https://supplier_base_url.com/some/path
this.href(new URL('https://supplier_base_url.com/some/path'))
// https://supplier_base_url.com/some/path
this.href('/some/path', { a: 'b', c: 'd' })
// https://supplier_base_url.com/some/path?a=b&c=d
this.href('https://supplier_base_url.com/some/path', new URLSearchParams({ a: 'b', c: 'd' }))
// https://supplier_base_url.com/some/path?a=b&c=d
Protected
getRetrieves product data with caching support. Similar to getProductData but allows for additional parameters to be included in the cache key.
The ProductBuilder instance to get data for
The function to use for fetching product data
Optional
params: Record<string, string>Optional parameters to include in the cache key
Promise resolving to the updated ProductBuilder or void if fetch fails
const builder = new ProductBuilder<Product>(this.baseURL);
builder.setBasicInfo("Acetone", "/products/acetone", "ChemSupplier");
// Use custom fetcher with additional params
const updatedBuilder = await supplier.getProductDataWithCache(
builder,
async (b) => {
// Custom fetching logic
return b;
},
{ version: "2.0" }
);
Protected
groupProtected
fetchInternal fetch method with request counting and decorator. Tracks request count and enforces hard limits on HTTP requests.
Arguments to pass to fetchDecorator (usually a Request or URL and options)
The response from the fetchDecorator
Protected
makeConstructs the query parameters for a product search request
Search term to look for
Object containing all required search parameters
Protected
queryExecutes a product search query and stores results Fetches products matching the current search query and updates internal results cache
Protected
initInitialize product builders from Carolina search response data. Transforms product listings into ProductBuilder instances, handling:
Array of product listings from search results
Array of ProductBuilder instances initialized with product data
const results = await this.queryProducts("sodium chloride");
if (results) {
const builders = this.initProductBuilders(results);
// Each builder contains parsed product data
for (const builder of builders) {
const product = await builder.build();
console.log(product.title, product.price, product.grade);
}
}
Protected
extractExtracts product search results from a response object Navigates through nested response structure to find product listings
Raw response object from search request
Array of validated search result items
Protected
extractExtracts the relevant product data from an ATG response object Navigates through the nested response structure to find product information
Raw ATG response object
Product data from response or null if invalid/not found
Schema data for breadcrumb navigation including JSON structure and data layer information
JSON string containing the structured breadcrumb schema data
Analytics data layer object specific to breadcrumb navigation
Standard result object containing core product information
Name of the product
Unique identifier for the product
Order-related data for the product display page
Specifications for the product
List of specifications
List of specification items
Detailed description of the product
Product data in string format
Analytics and tracking data container
Detailed product information for analytics
URL of the product's primary image
Unique identifier for the product
URL to the product's detail page
Type of page being displayed
Name of the product
Array of product price information
Container for data layer information
JSON object containing analytics data layer information
Canonical URL for the product page
Indicates if the product is a digital learning product
Display name shown for the product
Indicates if the product has been discontinued
Indicates if this is a product grouping
Brief description of the product
Type or category of the product
Details about product variants within the same family
Display name for the product family variant
Details about the organization
Protected
getTransforms a Carolina search result into the common Product type Makes additional API calls if needed to get complete product details
Carolina search result to transform
Promise resolving to a partial Product object or void if invalid
Look to see if the response header is 302 and if its sending us to https://www.carolina.com/CB_500, if so, stop sending requests to them for this search.
Protected
titleSelects the title of a product from the search response
Product object from search response
Protected
queryString to query for (Product name, CAS, etc). This is the search term that will be used to find products. Set during construction and used throughout the supplier's lifecycle.
Protected
baseThe base search parameters that are always included in search requests. These parameters are merged with any additional search parameters when making requests to the supplier's API.
Protected
controllerThe AbortController instance used to manage and cancel ongoing requests. This allows for cancellation of in-flight requests when needed, such as when a new search is started or the supplier is disposed.
Protected
limitThe maximum number of results to return for a search query. This is not a limit on HTTP requests, but rather the number of products that will be returned to the caller.
Protected
productsThe products that are currently being built by the supplier. This array holds ProductBuilder instances that are in the process of being transformed into complete Product objects.
Protected
requestCounter for HTTP requests made during the current query execution. This is used to track the number of requests and ensure we don't exceed the httpRequestHardLimit.
Protected
minMinimum number of milliseconds between two consecutive tasks
Protected
loggerProtected
productProtected
Static
Readonly
productProtected
cacheReadonly
supplierDisplay name of the supplier
Readonly
baseBase URL for all API requests
Readonly
shippingThe shipping scope of the supplier. This is used to determine the shipping scope of the supplier.
Readonly
countryThe country code of the supplier. This is used to determine the currency and other country-specific information.
Readonly
paymentThe payment methods accepted by the supplier. This is used to determine the payment methods accepted by the supplier.
Protected
queryCached search results from the last query
Protected
httpMaximum number of HTTP requests allowed per query
Protected
httpCounter for HTTP requests made during current query
Protected
maxNumber of requests to process in parallel
Protected
headersDefault headers sent with every request
Implementation of the Carolina Biological Supply Company supplier. Provides product search and data extraction functionality for Carolina.com.
Remarks
Carolina.com uses Oracle ATG Commerce as their ecommerce platform which has a predictable output format, though very bulky. But very parseable.
Product search uses the following endpoints:
/browse/product-search-results?tab=p&q=acid
/browse/product-search-results?tab=p&format=json&ajax=true&q=acid
/:category/:productName/:productId.pr
/:category/:productName/:productId.pr?format=json&ajax=true
API Documentation:
https://www.carolina.com/swagger-ui/
https://www.carolina.com/api/rest/openapi.json
https://www.carolina.com/api/rest/application.wadl
Common API Endpoints:
/api/rest/cb/product/product-quick-view/:id
/api/rest/cb/product/product-details/:id
/api/rest/cb/static/fetch-suggestions-for-global-search/:term
JSON Format: Append
&format=json&ajax=true
to any URL to get JSON response