Storefront data access functions for querying products, variants, and search from the Supabase database.
All functions are located in src/services/products.service.ts. They query the products table with nested variant data and enforce is_active = true, status = 'active', and stock > 0 by default for storefront display.
interface GetProductsOptions { section?: Section; // 'vape' | '420' categoryId?: string | string[]; // single ID or array for multi-category limit?: number; // default 50 offset?: number; // default 0 (used with range pagination) filter?: 'featured' | 'new' | 'bestseller'; // maps to boolean flag columns}
When filter is provided, limit is applied via .limit() and offset is ignored. Without filter, .range(offset, offset + limit - 1) is used for cursor-style pagination.
export async function getDiscountedProducts( limit: number = 50): Promise<Product[]>
Returns products that have a compare_at_price greater than their price. Filters are applied server-side first, then refined locally with p.compare_at_price && p.compare_at_price > p.price.
export async function getProductsByIds( ids: string[]): Promise<Product[]>
Batch lookup by primary key array. Used for cart validation to check current stock and active status. Returns an empty array immediately if ids is empty.
Advanced multi-field search from src/services/search.service.ts. Searches name, short_description, description, sku, and array tags. Orders results by is_featured DESC, then name ASC. Default limit is 20.
export async function getSmartRecommendations( product: Product, limit: number = 4): Promise<Product[]>
Smart upsell engine. Looks up compatible category slugs from @/lib/upsell-logic, fetches matching category IDs, then returns in-stock bestseller products from those categories. Falls back to same-category products if no upsell rules exist.
export function mapProductVariations(data: Product[]): Product[];export function mapProductVariations(data: Product): Product;
Applied automatically by all service functions. Ensures specs defaults to {}, badges defaults to [], and each variant option includes an attribute_name string extracted from the nested join.