shop-client 3.8.2 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +93 -1
  3. package/dist/checkout.mjs +1 -7
  4. package/dist/chunk-6GPWNCDO.mjs +130 -0
  5. package/dist/chunk-EJO5U4BT.mjs +2 -0
  6. package/dist/chunk-FFKWCNLU.mjs +1 -0
  7. package/dist/chunk-KYLPIEU3.mjs +2 -0
  8. package/dist/chunk-MB2INNNP.mjs +1 -0
  9. package/dist/chunk-MI7754VX.mjs +2 -0
  10. package/dist/chunk-SZQPMLZG.mjs +1 -0
  11. package/dist/collections.d.ts +1 -1
  12. package/dist/collections.mjs +1 -9
  13. package/dist/enrich-OZHBXKK6.mjs +1 -0
  14. package/dist/index.d.ts +24 -6
  15. package/dist/index.mjs +2 -702
  16. package/dist/products.d.ts +1 -1
  17. package/dist/products.mjs +1 -9
  18. package/dist/{store-CJVUz2Yb.d.mts → store-iQARl6J3.d.ts} +3 -3
  19. package/dist/store.d.ts +1 -1
  20. package/dist/store.mjs +1 -9
  21. package/dist/utils/rate-limit.d.ts +5 -0
  22. package/dist/utils/rate-limit.mjs +1 -11
  23. package/package.json +8 -10
  24. package/dist/checkout.d.mts +0 -31
  25. package/dist/checkout.js +0 -115
  26. package/dist/checkout.js.map +0 -1
  27. package/dist/checkout.mjs.map +0 -1
  28. package/dist/chunk-2KBOKOAD.mjs +0 -177
  29. package/dist/chunk-2KBOKOAD.mjs.map +0 -1
  30. package/dist/chunk-BWKBRM2Z.mjs +0 -136
  31. package/dist/chunk-BWKBRM2Z.mjs.map +0 -1
  32. package/dist/chunk-O4BPIIQ6.mjs +0 -503
  33. package/dist/chunk-O4BPIIQ6.mjs.map +0 -1
  34. package/dist/chunk-QCTICSBE.mjs +0 -398
  35. package/dist/chunk-QCTICSBE.mjs.map +0 -1
  36. package/dist/chunk-QL5OUZGP.mjs +0 -91
  37. package/dist/chunk-QL5OUZGP.mjs.map +0 -1
  38. package/dist/chunk-WTK5HUFI.mjs +0 -1287
  39. package/dist/chunk-WTK5HUFI.mjs.map +0 -1
  40. package/dist/collections.d.mts +0 -64
  41. package/dist/collections.js +0 -540
  42. package/dist/collections.js.map +0 -1
  43. package/dist/collections.mjs.map +0 -1
  44. package/dist/index.d.mts +0 -233
  45. package/dist/index.js +0 -3241
  46. package/dist/index.js.map +0 -1
  47. package/dist/index.mjs.map +0 -1
  48. package/dist/products.d.mts +0 -63
  49. package/dist/products.js +0 -1206
  50. package/dist/products.js.map +0 -1
  51. package/dist/products.mjs.map +0 -1
  52. package/dist/store-CJVUz2Yb.d.ts +0 -608
  53. package/dist/store.d.mts +0 -1
  54. package/dist/store.js +0 -698
  55. package/dist/store.js.map +0 -1
  56. package/dist/store.mjs.map +0 -1
  57. package/dist/utils/rate-limit.d.mts +0 -25
  58. package/dist/utils/rate-limit.js +0 -203
  59. package/dist/utils/rate-limit.js.map +0 -1
  60. package/dist/utils/rate-limit.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ai/determine-store-type.ts","../src/dto/collections.dto.ts","../src/dto/products.mapped.ts","../src/index.ts"],"sourcesContent":["import type { StoreInfo } from \"../store\";\nimport type { StoreTypeBreakdown } from \"../types\";\nimport { determineStoreType as determineStoreTypeViaLLM } from \"./enrich\";\n\ntype Args = {\n getInfo: () => Promise<StoreInfo>;\n baseUrl: string;\n findProduct: (handle: string) => Promise<unknown>;\n apiKey?: string;\n model?: string;\n maxShowcaseProducts?: number;\n maxShowcaseCollections?: number;\n};\n\n/**\n * Lightweight wrapper for determining store type by delegating to utils/enrich.\n * It first fetches StoreInfo via getInfo, then passes showcase samples\n * directly to the enrichment function.\n */\nexport async function determineStoreTypeForStore(\n args: Args\n): Promise<StoreTypeBreakdown> {\n const info = await args.getInfo();\n\n const maxProducts = Math.max(0, Math.min(50, args.maxShowcaseProducts ?? 10));\n const maxCollections = Math.max(\n 0,\n Math.min(50, args.maxShowcaseCollections ?? 10)\n );\n\n const take = <T>(arr: T[], n: number): T[] => arr.slice(0, Math.max(0, n));\n\n const productsSample = Array.isArray(info.showcase.products)\n ? take(info.showcase.products, maxProducts)\n : [];\n const collectionsSample = Array.isArray(info.showcase.collections)\n ? take(info.showcase.collections, maxCollections)\n : [];\n\n const breakdown = await determineStoreTypeViaLLM(\n {\n title: info.title || info.name,\n description: info.description ?? null,\n showcase: {\n products: productsSample,\n collections: collectionsSample,\n },\n },\n { apiKey: args.apiKey, model: args.model }\n );\n\n return breakdown as StoreTypeBreakdown;\n}\n","import type { Collection, ShopifyCollection } from \"../types\";\n\nexport function collectionsDto(\n collections: ShopifyCollection[] | null\n): Collection[] | null {\n if (!collections || collections.length === 0) return null;\n\n return collections.map((collection) => ({\n id: collection.id.toString(),\n title: collection.title,\n handle: collection.handle,\n description: collection.description,\n image: collection.image\n ? {\n id: collection.image.id,\n createdAt: collection.image.created_at,\n src: collection.image.src,\n alt: collection.image.alt,\n }\n : undefined,\n productsCount: collection.products_count,\n publishedAt: collection.published_at,\n updatedAt: collection.updated_at,\n }));\n}\n","import type { Product, ShopifyProduct, ShopifySingleProduct } from \"../types\";\nimport {\n buildVariantOptionsMap,\n genProductSlug,\n normalizeKey,\n safeParseDate,\n} from \"../utils/func\";\n\ntype Ctx = {\n storeDomain: string;\n storeSlug: string;\n currency: string;\n normalizeImageUrl: (url: string | null | undefined) => string;\n formatPrice: (amountInCents: number) => string;\n};\n\nfunction mapVariants(\n product: ShopifyProduct | ShopifySingleProduct\n): NonNullable<Product[\"variants\"]> {\n const variants = (product as ShopifyProduct).variants ?? [];\n return variants.map((variant: any) => ({\n id: variant.id.toString(),\n platformId: variant.id.toString(),\n name: variant.name,\n title: variant.title,\n option1: variant.option1 || null,\n option2: variant.option2 || null,\n option3: variant.option3 || null,\n options: [variant.option1, variant.option2, variant.option3].filter(\n Boolean\n ) as string[],\n sku: variant.sku || null,\n requiresShipping: variant.requires_shipping,\n taxable: variant.taxable,\n featuredImage: variant.featured_image\n ? {\n id: variant.featured_image.id,\n src: variant.featured_image.src,\n width: variant.featured_image.width,\n height: variant.featured_image.height,\n position: variant.featured_image.position,\n productId: variant.featured_image.product_id,\n aspectRatio: variant.featured_image.aspect_ratio || 0,\n variantIds: variant.featured_image.variant_ids || [],\n createdAt: variant.featured_image.created_at,\n updatedAt: variant.featured_image.updated_at,\n alt: variant.featured_image.alt,\n }\n : null,\n available: Boolean(variant.available),\n price:\n typeof variant.price === \"string\"\n ? Number.parseFloat(variant.price) * 100\n : variant.price,\n weightInGrams: variant.weightInGrams ?? variant.grams,\n compareAtPrice: variant.compare_at_price\n ? typeof variant.compare_at_price === \"string\"\n ? Number.parseFloat(variant.compare_at_price) * 100\n : variant.compare_at_price\n : 0,\n position: variant.position,\n productId: variant.product_id,\n createdAt: variant.created_at,\n updatedAt: variant.updated_at,\n }));\n}\n\nexport function mapProductsDto(\n products: ShopifyProduct[] | null,\n ctx: Ctx\n): Product[] | null {\n if (!products || products.length === 0) return null;\n\n return products.map((product) => {\n const optionNames = product.options.map((o) => o.name);\n const variantOptionsMap = buildVariantOptionsMap(\n optionNames,\n product.variants\n );\n const mappedVariants = mapVariants(product);\n\n const priceValues = mappedVariants\n .map((v) => v.price)\n .filter((p) => typeof p === \"number\" && !Number.isNaN(p));\n const compareAtValues = mappedVariants\n .map((v) => v.compareAtPrice || 0)\n .filter((p) => typeof p === \"number\" && !Number.isNaN(p));\n\n const priceMin = priceValues.length ? Math.min(...priceValues) : 0;\n const priceMax = priceValues.length ? Math.max(...priceValues) : 0;\n const priceVaries = mappedVariants.length > 1 && priceMin !== priceMax;\n\n const compareAtMin = compareAtValues.length\n ? Math.min(...compareAtValues)\n : 0;\n const compareAtMax = compareAtValues.length\n ? Math.max(...compareAtValues)\n : 0;\n const compareAtVaries =\n mappedVariants.length > 1 && compareAtMin !== compareAtMax;\n\n return {\n slug: genProductSlug({\n handle: product.handle,\n storeDomain: ctx.storeDomain,\n }),\n handle: product.handle,\n platformId: product.id.toString(),\n title: product.title,\n available: mappedVariants.some((v) => v.available),\n price: priceMin,\n priceMin: priceMin,\n priceMax: priceMax,\n priceVaries,\n compareAtPrice: compareAtMin,\n compareAtPriceMin: compareAtMin,\n compareAtPriceMax: compareAtMax,\n compareAtPriceVaries: compareAtVaries,\n discount: 0,\n currency: ctx.currency,\n localizedPricing: {\n currency: ctx.currency,\n priceFormatted: ctx.formatPrice(priceMin),\n priceMinFormatted: ctx.formatPrice(priceMin),\n priceMaxFormatted: ctx.formatPrice(priceMax),\n compareAtPriceFormatted: ctx.formatPrice(compareAtMin),\n },\n options: product.options.map((option) => ({\n key: normalizeKey(option.name),\n data: option.values,\n name: option.name,\n position: option.position,\n values: option.values,\n })),\n variantOptionsMap,\n bodyHtml: product.body_html || null,\n active: true,\n productType: product.product_type || null,\n tags: Array.isArray(product.tags) ? product.tags : [],\n vendor: product.vendor,\n featuredImage: product.images?.[0]?.src\n ? ctx.normalizeImageUrl(product.images[0].src)\n : null,\n isProxyFeaturedImage: false,\n createdAt: safeParseDate(product.created_at),\n updatedAt: safeParseDate(product.updated_at),\n variants: mappedVariants,\n images: product.images.map((image) => ({\n id: image.id,\n productId: image.product_id,\n alt: null,\n position: image.position,\n src: ctx.normalizeImageUrl(image.src),\n width: image.width,\n height: image.height,\n mediaType: \"image\" as const,\n variantIds: image.variant_ids || [],\n createdAt: image.created_at,\n updatedAt: image.updated_at,\n })),\n publishedAt: safeParseDate(product.published_at) ?? null,\n seo: null,\n metaTags: null,\n displayScore: undefined,\n deletedAt: null,\n storeSlug: ctx.storeSlug,\n storeDomain: ctx.storeDomain,\n url: `${ctx.storeDomain}/products/${product.handle}`,\n } as Product;\n });\n}\n\nexport function mapProductDto(\n product: ShopifySingleProduct,\n ctx: Ctx\n): Product {\n const optionNames = product.options.map((o) => o.name);\n const variantOptionsMap = buildVariantOptionsMap(\n optionNames,\n product.variants\n );\n\n const mapped: Product = {\n slug: genProductSlug({\n handle: product.handle,\n storeDomain: ctx.storeDomain,\n }),\n handle: product.handle,\n platformId: product.id.toString(),\n title: product.title,\n available: product.available,\n price: product.price,\n priceMin: product.price_min,\n priceMax: product.price_max,\n priceVaries: product.price_varies,\n compareAtPrice: product.compare_at_price || 0,\n compareAtPriceMin: product.compare_at_price_min,\n compareAtPriceMax: product.compare_at_price_max,\n compareAtPriceVaries: product.compare_at_price_varies,\n discount: 0,\n currency: ctx.currency,\n localizedPricing: {\n currency: ctx.currency,\n priceFormatted: ctx.formatPrice(product.price),\n priceMinFormatted: ctx.formatPrice(product.price_min),\n priceMaxFormatted: ctx.formatPrice(product.price_max),\n compareAtPriceFormatted: ctx.formatPrice(product.compare_at_price || 0),\n },\n options: product.options.map((option) => ({\n key: normalizeKey(option.name),\n data: option.values,\n name: option.name,\n position: option.position,\n values: option.values,\n })),\n variantOptionsMap,\n bodyHtml: product.description || null,\n active: true,\n productType: product.type || null,\n tags: Array.isArray(product.tags)\n ? product.tags\n : typeof product.tags === \"string\"\n ? [product.tags]\n : [],\n vendor: product.vendor,\n featuredImage: ctx.normalizeImageUrl(product.featured_image),\n isProxyFeaturedImage: false,\n createdAt: safeParseDate(product.created_at),\n updatedAt: safeParseDate(product.updated_at),\n variants: mapVariants(product),\n images: Array.isArray(product.images)\n ? product.images.map((imageSrc, index) => ({\n id: index + 1,\n productId: product.id,\n alt: null,\n position: index + 1,\n src: ctx.normalizeImageUrl(imageSrc),\n width: 0,\n height: 0,\n mediaType: \"image\" as const,\n variantIds: [],\n createdAt: product.created_at,\n updatedAt: product.updated_at,\n }))\n : [],\n publishedAt: safeParseDate(product.published_at) ?? null,\n seo: null,\n metaTags: null,\n displayScore: undefined,\n deletedAt: null,\n storeSlug: ctx.storeSlug,\n storeDomain: ctx.storeDomain,\n url: product.url || `${ctx.storeDomain}/products/${product.handle}`,\n };\n\n return mapped;\n}\n","import { determineStoreTypeForStore } from \"./ai/determine-store-type\";\nimport type { CheckoutOperations } from \"./checkout\";\nimport { createCheckoutOperations } from \"./checkout\";\nimport { getInfoForStore } from \"./client/get-info\";\nimport type { CollectionOperations } from \"./collections\";\nimport { createCollectionOperations } from \"./collections\";\nimport { collectionsDto as dtoCollections } from \"./dto/collections.dto\";\nimport { mapProductDto, mapProductsDto } from \"./dto/products.mapped\";\nimport type { ProductOperations } from \"./products\";\nimport { createProductOperations } from \"./products\";\nimport type { StoreInfo, StoreOperations } from \"./store\";\nimport { createStoreOperations } from \"./store\";\nimport type {\n Collection,\n Product,\n ShopifyCollection,\n ShopifyProduct,\n ShopifySingleProduct,\n StoreTypeBreakdown,\n} from \"./types\";\nimport { generateStoreSlug } from \"./utils/func\";\nimport { rateLimitedFetch } from \"./utils/rate-limit\";\n\n/**\n * A comprehensive Shopify store client for fetching products, collections, and store information.\n *\n * @example\n * ```typescript\n * import { ShopClient } from 'shop-search';\n *\n * const shop = new ShopClient('https://exampleshop.com');\n *\n * // Fetch all products\n * const products = await shop.products.all();\n *\n * // Get store information\n * const storeInfo = await shop.getInfo();\n * ```\n */\nexport class ShopClient {\n private storeDomain: string;\n private baseUrl: string;\n private storeSlug: string;\n private validationCache: Map<string, boolean> = new Map(); // Simple cache for validation results\n private cacheExpiry: number = 5 * 60 * 1000; // 5 minutes cache expiry\n private cacheTimestamps: Map<string, number> = new Map();\n private normalizeImageUrlCache: Map<string, string> = new Map();\n private storeCurrency?: string;\n\n // Public operations interfaces\n public products: ProductOperations;\n public collections: CollectionOperations;\n public checkout: CheckoutOperations;\n public storeOperations: StoreOperations;\n\n /**\n * Creates a new ShopClient instance for interacting with a Shopify store.\n *\n * @param urlPath - The Shopify store URL (e.g., 'https://exampleshop.com' or 'exampleshop.com')\n *\n * @throws {Error} When the URL is invalid or contains malicious patterns\n *\n * @example\n * ```typescript\n * // With full URL\n * const shop = new ShopClient('https://exampleshop.com');\n *\n * // Without protocol (automatically adds https://)\n * const shop = new ShopClient('exampleshop.com');\n *\n * // Works with any Shopify store domain\n * const shop1 = new ShopClient('https://example.myshopify.com');\n * const shop2 = new ShopClient('https://boutique.fashion');\n * ```\n */\n constructor(urlPath: string) {\n // Validate input URL\n if (!urlPath || typeof urlPath !== \"string\") {\n throw new Error(\"Store URL is required and must be a string\");\n }\n\n // Sanitize and validate URL\n let normalizedUrl = urlPath.trim();\n if (\n !normalizedUrl.startsWith(\"http://\") &&\n !normalizedUrl.startsWith(\"https://\")\n ) {\n normalizedUrl = `https://${normalizedUrl}`;\n }\n\n let storeUrl: URL;\n try {\n storeUrl = new URL(normalizedUrl);\n } catch (_error) {\n throw new Error(\"Invalid store URL format\");\n }\n\n // Validate domain format (basic check for Shopify domains)\n const hostname = storeUrl.hostname;\n if (!hostname || hostname.length < 3) {\n throw new Error(\"Invalid domain name\");\n }\n\n // Check for potentially malicious patterns\n if (\n hostname.includes(\"..\") ||\n hostname.includes(\"//\") ||\n hostname.includes(\"@\")\n ) {\n throw new Error(\"Invalid characters in domain name\");\n }\n\n // Validate domain structure - must contain at least one dot for TLD\n if (\n !hostname.includes(\".\") ||\n hostname.startsWith(\".\") ||\n hostname.endsWith(\".\")\n ) {\n throw new Error(\n \"Invalid domain format - must be a valid domain with TLD\"\n );\n }\n\n // Check for valid domain pattern (basic regex)\n const domainPattern =\n /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;\n if (!domainPattern.test(hostname)) {\n throw new Error(\"Invalid domain format\");\n }\n\n this.storeDomain = `https://${hostname}`;\n let fetchUrl = `https://${hostname}${storeUrl.pathname}`;\n if (!fetchUrl.endsWith(\"/\")) {\n fetchUrl = `${fetchUrl}/`;\n }\n this.baseUrl = fetchUrl;\n\n // Pre-calculate store slug once\n this.storeSlug = generateStoreSlug(this.storeDomain);\n\n // Initialize operations\n this.storeOperations = createStoreOperations({\n baseUrl: this.baseUrl,\n storeDomain: this.storeDomain,\n validateProductExists: this.validateProductExists.bind(this),\n validateCollectionExists: this.validateCollectionExists.bind(this),\n validateLinksInBatches: this.validateLinksInBatches.bind(this),\n handleFetchError: this.handleFetchError.bind(this),\n });\n\n this.products = createProductOperations(\n this.baseUrl,\n this.storeDomain,\n this.fetchProducts.bind(this),\n this.productsDto.bind(this),\n this.productDto.bind(this),\n () => this.getInfo(),\n (handle: string) => this.products.find(handle)\n );\n\n this.collections = createCollectionOperations(\n this.baseUrl,\n this.storeDomain,\n this.fetchCollections.bind(this),\n this.collectionsDto.bind(this),\n this.fetchPaginatedProductsFromCollection.bind(this),\n () => this.getInfo(),\n (handle: string) => this.collections.find(handle)\n );\n\n this.checkout = createCheckoutOperations(this.baseUrl);\n }\n\n /**\n * Optimized image URL normalization with caching\n */\n private normalizeImageUrl(url?: string | null): string {\n if (!url) {\n return \"\";\n }\n\n if (this.normalizeImageUrlCache.has(url)) {\n return this.normalizeImageUrlCache.get(url)!;\n }\n\n const normalized = url.startsWith(\"//\") ? `https:${url}` : url;\n this.normalizeImageUrlCache.set(url, normalized);\n return normalized;\n }\n\n /**\n * Format a price amount (in cents) using the store currency.\n */\n private formatPrice(amountInCents: number): string {\n const currency = this.storeCurrency ?? \"USD\";\n try {\n return new Intl.NumberFormat(undefined, {\n style: \"currency\",\n currency,\n }).format((amountInCents || 0) / 100);\n } catch {\n const val = (amountInCents || 0) / 100;\n return `${val} ${currency}`;\n }\n }\n\n /**\n * Transform Shopify products to our Product format\n */\n productsDto(products: ShopifyProduct[]): Product[] | null {\n return mapProductsDto(products, {\n storeDomain: this.storeDomain,\n storeSlug: this.storeSlug,\n currency: this.storeCurrency ?? \"USD\",\n normalizeImageUrl: (url) => this.normalizeImageUrl(url),\n formatPrice: (amount) => this.formatPrice(amount),\n });\n }\n\n productDto(product: ShopifySingleProduct): Product {\n return mapProductDto(product, {\n storeDomain: this.storeDomain,\n storeSlug: this.storeSlug,\n currency: this.storeCurrency ?? \"USD\",\n normalizeImageUrl: (url) => this.normalizeImageUrl(url),\n formatPrice: (amount) => this.formatPrice(amount),\n });\n }\n\n collectionsDto(collections: ShopifyCollection[]): Collection[] {\n return dtoCollections(collections) ?? [];\n }\n\n /**\n * Enhanced error handling with context\n */\n private handleFetchError(\n error: unknown,\n context: string,\n url: string\n ): never {\n let errorMessage = `Error ${context}`;\n let statusCode: number | undefined;\n\n if (error instanceof Error) {\n errorMessage += `: ${error.message}`;\n\n // Check if it's a fetch error with response\n if (\"status\" in error) {\n statusCode = error.status as number;\n }\n } else if (typeof error === \"string\") {\n errorMessage += `: ${error}`;\n } else {\n errorMessage += \": Unknown error occurred\";\n }\n\n // Add URL context for debugging\n errorMessage += ` (URL: ${url})`;\n\n // Add status code if available\n if (statusCode) {\n errorMessage += ` (Status: ${statusCode})`;\n }\n\n // Create enhanced error with additional properties\n const enhancedError = new Error(errorMessage);\n (enhancedError as any).context = context;\n (enhancedError as any).url = url;\n (enhancedError as any).statusCode = statusCode;\n (enhancedError as any).originalError = error;\n\n throw enhancedError;\n }\n\n /**\n * Fetch products with pagination\n */\n private async fetchProducts(\n page: number,\n limit: number\n ): Promise<Product[] | null> {\n try {\n const url = `${this.baseUrl}products.json?page=${page}&limit=${limit}`;\n const response = await rateLimitedFetch(url);\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const data: { products: ShopifyProduct[] } = await response.json();\n return this.productsDto(data.products);\n } catch (error) {\n this.handleFetchError(\n error,\n \"fetching products\",\n `${this.baseUrl}products.json`\n );\n }\n }\n\n /**\n * Fetch collections with pagination\n */\n private async fetchCollections(page: number, limit: number) {\n try {\n const url = `${this.baseUrl}collections.json?page=${page}&limit=${limit}`;\n const response = await rateLimitedFetch(url);\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const data = await response.json();\n return this.collectionsDto(data.collections);\n } catch (error) {\n this.handleFetchError(\n error,\n \"fetching collections\",\n `${this.baseUrl}collections.json`\n );\n }\n }\n\n /**\n * Fetch paginated products from a specific collection\n */\n private async fetchPaginatedProductsFromCollection(\n collectionHandle: string,\n options: { page?: number; limit?: number } = {}\n ) {\n try {\n const { page = 1, limit = 250 } = options;\n // Resolve canonical collection handle via HTML redirect if handle has changed\n let finalHandle = collectionHandle;\n try {\n const htmlResp = await rateLimitedFetch(\n `${this.baseUrl}collections/${encodeURIComponent(collectionHandle)}`\n );\n if (htmlResp.ok) {\n const finalUrl = htmlResp.url;\n if (finalUrl) {\n const pathname = new URL(finalUrl).pathname.replace(/\\/$/, \"\");\n const parts = pathname.split(\"/\").filter(Boolean);\n const idx = parts.indexOf(\"collections\");\n const maybeHandle = idx >= 0 ? parts[idx + 1] : undefined;\n if (typeof maybeHandle === \"string\" && maybeHandle.length) {\n finalHandle = maybeHandle;\n }\n }\n }\n } catch {\n // Ignore redirect resolution errors and proceed with original handle\n }\n\n const url = `${this.baseUrl}collections/${finalHandle}/products.json?page=${page}&limit=${limit}`;\n const response = await rateLimitedFetch(url);\n\n if (!response.ok) {\n if (response.status === 404) {\n return null; // Collection not found\n }\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const data: { products: ShopifyProduct[] } = await response.json();\n return this.productsDto(data.products);\n } catch (error) {\n this.handleFetchError(\n error,\n \"fetching products from collection\",\n `${this.baseUrl}collections/${collectionHandle}/products.json`\n );\n }\n }\n\n /**\n * Validate if a product exists (with caching)\n */\n private async validateProductExists(handle: string): Promise<boolean> {\n const cacheKey = `product:${handle}`;\n\n if (this.isCacheValid(cacheKey)) {\n return this.validationCache.get(cacheKey) || false;\n }\n\n try {\n const url = `${this.baseUrl}products/${handle}.js`;\n const response = await rateLimitedFetch(url, { method: \"HEAD\" });\n const exists = response.ok;\n\n this.setCacheValue(cacheKey, exists);\n return exists;\n } catch (_error) {\n this.setCacheValue(cacheKey, false);\n return false;\n }\n }\n\n /**\n * Validate if a collection exists (with caching)\n */\n private async validateCollectionExists(handle: string): Promise<boolean> {\n const cacheKey = `collection:${handle}`;\n\n if (this.isCacheValid(cacheKey)) {\n return this.validationCache.get(cacheKey) || false;\n }\n\n try {\n const url = `${this.baseUrl}collections/${handle}.json`;\n const response = await rateLimitedFetch(url, { method: \"HEAD\" });\n const exists = response.ok;\n\n this.setCacheValue(cacheKey, exists);\n return exists;\n } catch (_error) {\n this.setCacheValue(cacheKey, false);\n return false;\n }\n }\n\n /**\n * Check if cache entry is still valid\n */\n private isCacheValid(key: string): boolean {\n const timestamp = this.cacheTimestamps.get(key);\n if (!timestamp) return false;\n\n return Date.now() - timestamp < this.cacheExpiry;\n }\n\n /**\n * Set cache value with timestamp\n */\n private setCacheValue(key: string, value: boolean): void {\n this.validationCache.set(key, value);\n this.cacheTimestamps.set(key, Date.now());\n }\n\n /**\n * Validate links in batches to avoid overwhelming the server\n */\n private async validateLinksInBatches<T>(\n items: T[],\n validator: (item: T) => Promise<boolean>,\n batchSize = 10\n ): Promise<T[]> {\n const validItems: T[] = [];\n\n for (let i = 0; i < items.length; i += batchSize) {\n const batch = items.slice(i, i + batchSize);\n const validationPromises = batch.map(async (item) => {\n const isValid = await validator(item);\n return isValid ? item : null;\n });\n\n const results = await Promise.all(validationPromises);\n const validBatchItems = results.filter(\n (item): item is NonNullable<typeof item> => item !== null\n );\n validItems.push(...validBatchItems);\n\n // Add small delay between batches to be respectful\n if (i + batchSize < items.length) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n }\n\n return validItems;\n }\n\n /**\n * Fetches comprehensive store information including metadata, social links, and showcase content.\n *\n * @returns {Promise<StoreInfo>} Store information object containing:\n * - `name` - Store name from meta tags or domain\n * - `domain` - Store domain URL\n * - `slug` - Generated store slug\n * - `title` - Store title from meta tags\n * - `description` - Store description from meta tags\n * - `logoUrl` - Store logo URL from Open Graph or CDN\n * - `socialLinks` - Object with social media links (facebook, twitter, instagram, etc.)\n * - `contactLinks` - Object with contact information (tel, email, contactPage)\n * - `headerLinks` - Array of navigation links from header\n * - `showcase` - Object with featured products and collections from homepage\n * - `jsonLdData` - Structured data from JSON-LD scripts\n * - `techProvider` - Shopify-specific information (walletId, subDomain)\n * - `country` - Country detection results with ISO 3166-1 alpha-2 codes (e.g., \"US\", \"GB\")\n *\n * @throws {Error} When the store URL is unreachable or returns an error\n *\n * @example\n * ```typescript\n * const shop = new ShopClient('https://exampleshop.com');\n * const storeInfo = await shop.getInfo();\n *\n * console.log(storeInfo.name); // \"Example Store\"\n * console.log(storeInfo.socialLinks.instagram); // \"https://instagram.com/example\"\n * console.log(storeInfo.showcase.products); // [\"product-handle-1\", \"product-handle-2\"]\n * console.log(storeInfo.country); // \"US\"\n * ```\n */\n async getInfo(): Promise<StoreInfo> {\n try {\n const { info, currencyCode } = await getInfoForStore({\n baseUrl: this.baseUrl,\n storeDomain: this.storeDomain,\n validateProductExists: (handle) => this.validateProductExists(handle),\n validateCollectionExists: (handle) =>\n this.validateCollectionExists(handle),\n validateLinksInBatches: (items, validator, batchSize) =>\n this.validateLinksInBatches(items, validator, batchSize),\n });\n if (typeof currencyCode === \"string\") {\n this.storeCurrency = currencyCode;\n }\n return info;\n } catch (error) {\n this.handleFetchError(error, \"fetching store info\", this.baseUrl);\n }\n }\n\n /**\n * Determine the store's primary vertical and target audience.\n * Uses `getInfo()` internally; no input required.\n */\n async determineStoreType(options?: {\n apiKey?: string;\n model?: string;\n maxShowcaseProducts?: number;\n maxShowcaseCollections?: number;\n }): Promise<StoreTypeBreakdown> {\n try {\n const breakdown = await determineStoreTypeForStore({\n baseUrl: this.baseUrl,\n getInfo: () => this.getInfo(),\n findProduct: (handle: string) => this.products.find(handle),\n apiKey: options?.apiKey,\n model: options?.model,\n maxShowcaseProducts: options?.maxShowcaseProducts,\n maxShowcaseCollections: options?.maxShowcaseCollections,\n });\n return breakdown;\n } catch (error: unknown) {\n throw this.handleFetchError(error, \"determineStoreType\", this.baseUrl);\n }\n }\n}\n\nexport { classifyProduct, generateSEOContent } from \"./ai/enrich\";\nexport type { CheckoutOperations } from \"./checkout\";\nexport type { CollectionOperations } from \"./collections\";\n// Export operation interfaces\nexport type { ProductOperations } from \"./products\";\nexport type { StoreInfo, StoreOperations } from \"./store\";\n// Export all types for external use\n// Classification utility\nexport type * from \"./types\";\nexport { detectShopifyCountry } from \"./utils/detect-country\";\n// Export utility functions\nexport {\n calculateDiscount,\n extractDomainWithoutSuffix,\n generateStoreSlug,\n genProductSlug,\n safeParseDate,\n sanitizeDomain,\n} from \"./utils/func\";\nexport { configureRateLimit } from \"./utils/rate-limit\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmBA,eAAsB,2BACpB,MAC6B;AArB/B;AAsBE,QAAM,OAAO,MAAM,KAAK,QAAQ;AAEhC,QAAM,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,KAAI,UAAK,wBAAL,YAA4B,EAAE,CAAC;AAC5E,QAAM,iBAAiB,KAAK;AAAA,IAC1B;AAAA,IACA,KAAK,IAAI,KAAI,UAAK,2BAAL,YAA+B,EAAE;AAAA,EAChD;AAEA,QAAM,OAAO,CAAI,KAAU,MAAmB,IAAI,MAAM,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;AAEzE,QAAM,iBAAiB,MAAM,QAAQ,KAAK,SAAS,QAAQ,IACvD,KAAK,KAAK,SAAS,UAAU,WAAW,IACxC,CAAC;AACL,QAAM,oBAAoB,MAAM,QAAQ,KAAK,SAAS,WAAW,IAC7D,KAAK,KAAK,SAAS,aAAa,cAAc,IAC9C,CAAC;AAEL,QAAM,YAAY,MAAM;AAAA,IACtB;AAAA,MACE,OAAO,KAAK,SAAS,KAAK;AAAA,MAC1B,cAAa,UAAK,gBAAL,YAAoB;AAAA,MACjC,UAAU;AAAA,QACR,UAAU;AAAA,QACV,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,EAAE,QAAQ,KAAK,QAAQ,OAAO,KAAK,MAAM;AAAA,EAC3C;AAEA,SAAO;AACT;;;AClDO,SAAS,eACd,aACqB;AACrB,MAAI,CAAC,eAAe,YAAY,WAAW,EAAG,QAAO;AAErD,SAAO,YAAY,IAAI,CAAC,gBAAgB;AAAA,IACtC,IAAI,WAAW,GAAG,SAAS;AAAA,IAC3B,OAAO,WAAW;AAAA,IAClB,QAAQ,WAAW;AAAA,IACnB,aAAa,WAAW;AAAA,IACxB,OAAO,WAAW,QACd;AAAA,MACE,IAAI,WAAW,MAAM;AAAA,MACrB,WAAW,WAAW,MAAM;AAAA,MAC5B,KAAK,WAAW,MAAM;AAAA,MACtB,KAAK,WAAW,MAAM;AAAA,IACxB,IACA;AAAA,IACJ,eAAe,WAAW;AAAA,IAC1B,aAAa,WAAW;AAAA,IACxB,WAAW,WAAW;AAAA,EACxB,EAAE;AACJ;;;ACRA,SAAS,YACP,SACkC;AAlBpC;AAmBE,QAAM,YAAY,aAA2B,aAA3B,YAAuC,CAAC;AAC1D,SAAO,SAAS,IAAI,CAAC,YAAc;AApBrC,QAAAA;AAoByC;AAAA,MACrC,IAAI,QAAQ,GAAG,SAAS;AAAA,MACxB,YAAY,QAAQ,GAAG,SAAS;AAAA,MAChC,MAAM,QAAQ;AAAA,MACd,OAAO,QAAQ;AAAA,MACf,SAAS,QAAQ,WAAW;AAAA,MAC5B,SAAS,QAAQ,WAAW;AAAA,MAC5B,SAAS,QAAQ,WAAW;AAAA,MAC5B,SAAS,CAAC,QAAQ,SAAS,QAAQ,SAAS,QAAQ,OAAO,EAAE;AAAA,QAC3D;AAAA,MACF;AAAA,MACA,KAAK,QAAQ,OAAO;AAAA,MACpB,kBAAkB,QAAQ;AAAA,MAC1B,SAAS,QAAQ;AAAA,MACjB,eAAe,QAAQ,iBACnB;AAAA,QACE,IAAI,QAAQ,eAAe;AAAA,QAC3B,KAAK,QAAQ,eAAe;AAAA,QAC5B,OAAO,QAAQ,eAAe;AAAA,QAC9B,QAAQ,QAAQ,eAAe;AAAA,QAC/B,UAAU,QAAQ,eAAe;AAAA,QACjC,WAAW,QAAQ,eAAe;AAAA,QAClC,aAAa,QAAQ,eAAe,gBAAgB;AAAA,QACpD,YAAY,QAAQ,eAAe,eAAe,CAAC;AAAA,QACnD,WAAW,QAAQ,eAAe;AAAA,QAClC,WAAW,QAAQ,eAAe;AAAA,QAClC,KAAK,QAAQ,eAAe;AAAA,MAC9B,IACA;AAAA,MACJ,WAAW,QAAQ,QAAQ,SAAS;AAAA,MACpC,OACE,OAAO,QAAQ,UAAU,WACrB,OAAO,WAAW,QAAQ,KAAK,IAAI,MACnC,QAAQ;AAAA,MACd,gBAAeA,MAAA,QAAQ,kBAAR,OAAAA,MAAyB,QAAQ;AAAA,MAChD,gBAAgB,QAAQ,mBACpB,OAAO,QAAQ,qBAAqB,WAClC,OAAO,WAAW,QAAQ,gBAAgB,IAAI,MAC9C,QAAQ,mBACV;AAAA,MACJ,UAAU,QAAQ;AAAA,MAClB,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ;AAAA,IACrB;AAAA,GAAE;AACJ;AAEO,SAAS,eACd,UACA,KACkB;AAClB,MAAI,CAAC,YAAY,SAAS,WAAW,EAAG,QAAO;AAE/C,SAAO,SAAS,IAAI,CAAC,YAAY;AAzEnC;AA0EI,UAAM,cAAc,QAAQ,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI;AACrD,UAAM,oBAAoB;AAAA,MACxB;AAAA,MACA,QAAQ;AAAA,IACV;AACA,UAAM,iBAAiB,YAAY,OAAO;AAE1C,UAAM,cAAc,eACjB,IAAI,CAAC,MAAM,EAAE,KAAK,EAClB,OAAO,CAAC,MAAM,OAAO,MAAM,YAAY,CAAC,OAAO,MAAM,CAAC,CAAC;AAC1D,UAAM,kBAAkB,eACrB,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAChC,OAAO,CAAC,MAAM,OAAO,MAAM,YAAY,CAAC,OAAO,MAAM,CAAC,CAAC;AAE1D,UAAM,WAAW,YAAY,SAAS,KAAK,IAAI,GAAG,WAAW,IAAI;AACjE,UAAM,WAAW,YAAY,SAAS,KAAK,IAAI,GAAG,WAAW,IAAI;AACjE,UAAM,cAAc,eAAe,SAAS,KAAK,aAAa;AAE9D,UAAM,eAAe,gBAAgB,SACjC,KAAK,IAAI,GAAG,eAAe,IAC3B;AACJ,UAAM,eAAe,gBAAgB,SACjC,KAAK,IAAI,GAAG,eAAe,IAC3B;AACJ,UAAM,kBACJ,eAAe,SAAS,KAAK,iBAAiB;AAEhD,WAAO;AAAA,MACL,MAAM,eAAe;AAAA,QACnB,QAAQ,QAAQ;AAAA,QAChB,aAAa,IAAI;AAAA,MACnB,CAAC;AAAA,MACD,QAAQ,QAAQ;AAAA,MAChB,YAAY,QAAQ,GAAG,SAAS;AAAA,MAChC,OAAO,QAAQ;AAAA,MACf,WAAW,eAAe,KAAK,CAAC,MAAM,EAAE,SAAS;AAAA,MACjD,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,MAChB,mBAAmB;AAAA,MACnB,mBAAmB;AAAA,MACnB,sBAAsB;AAAA,MACtB,UAAU;AAAA,MACV,UAAU,IAAI;AAAA,MACd,kBAAkB;AAAA,QAChB,UAAU,IAAI;AAAA,QACd,gBAAgB,IAAI,YAAY,QAAQ;AAAA,QACxC,mBAAmB,IAAI,YAAY,QAAQ;AAAA,QAC3C,mBAAmB,IAAI,YAAY,QAAQ;AAAA,QAC3C,yBAAyB,IAAI,YAAY,YAAY;AAAA,MACvD;AAAA,MACA,SAAS,QAAQ,QAAQ,IAAI,CAAC,YAAY;AAAA,QACxC,KAAK,aAAa,OAAO,IAAI;AAAA,QAC7B,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,QACb,UAAU,OAAO;AAAA,QACjB,QAAQ,OAAO;AAAA,MACjB,EAAE;AAAA,MACF;AAAA,MACA,UAAU,QAAQ,aAAa;AAAA,MAC/B,QAAQ;AAAA,MACR,aAAa,QAAQ,gBAAgB;AAAA,MACrC,MAAM,MAAM,QAAQ,QAAQ,IAAI,IAAI,QAAQ,OAAO,CAAC;AAAA,MACpD,QAAQ,QAAQ;AAAA,MAChB,iBAAe,mBAAQ,WAAR,mBAAiB,OAAjB,mBAAqB,OAChC,IAAI,kBAAkB,QAAQ,OAAO,CAAC,EAAE,GAAG,IAC3C;AAAA,MACJ,sBAAsB;AAAA,MACtB,WAAW,cAAc,QAAQ,UAAU;AAAA,MAC3C,WAAW,cAAc,QAAQ,UAAU;AAAA,MAC3C,UAAU;AAAA,MACV,QAAQ,QAAQ,OAAO,IAAI,CAAC,WAAW;AAAA,QACrC,IAAI,MAAM;AAAA,QACV,WAAW,MAAM;AAAA,QACjB,KAAK;AAAA,QACL,UAAU,MAAM;AAAA,QAChB,KAAK,IAAI,kBAAkB,MAAM,GAAG;AAAA,QACpC,OAAO,MAAM;AAAA,QACb,QAAQ,MAAM;AAAA,QACd,WAAW;AAAA,QACX,YAAY,MAAM,eAAe,CAAC;AAAA,QAClC,WAAW,MAAM;AAAA,QACjB,WAAW,MAAM;AAAA,MACnB,EAAE;AAAA,MACF,cAAa,mBAAc,QAAQ,YAAY,MAAlC,YAAuC;AAAA,MACpD,KAAK;AAAA,MACL,UAAU;AAAA,MACV,cAAc;AAAA,MACd,WAAW;AAAA,MACX,WAAW,IAAI;AAAA,MACf,aAAa,IAAI;AAAA,MACjB,KAAK,GAAG,IAAI,WAAW,aAAa,QAAQ,MAAM;AAAA,IACpD;AAAA,EACF,CAAC;AACH;AAEO,SAAS,cACd,SACA,KACS;AA/KX;AAgLE,QAAM,cAAc,QAAQ,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI;AACrD,QAAM,oBAAoB;AAAA,IACxB;AAAA,IACA,QAAQ;AAAA,EACV;AAEA,QAAM,SAAkB;AAAA,IACtB,MAAM,eAAe;AAAA,MACnB,QAAQ,QAAQ;AAAA,MAChB,aAAa,IAAI;AAAA,IACnB,CAAC;AAAA,IACD,QAAQ,QAAQ;AAAA,IAChB,YAAY,QAAQ,GAAG,SAAS;AAAA,IAChC,OAAO,QAAQ;AAAA,IACf,WAAW,QAAQ;AAAA,IACnB,OAAO,QAAQ;AAAA,IACf,UAAU,QAAQ;AAAA,IAClB,UAAU,QAAQ;AAAA,IAClB,aAAa,QAAQ;AAAA,IACrB,gBAAgB,QAAQ,oBAAoB;AAAA,IAC5C,mBAAmB,QAAQ;AAAA,IAC3B,mBAAmB,QAAQ;AAAA,IAC3B,sBAAsB,QAAQ;AAAA,IAC9B,UAAU;AAAA,IACV,UAAU,IAAI;AAAA,IACd,kBAAkB;AAAA,MAChB,UAAU,IAAI;AAAA,MACd,gBAAgB,IAAI,YAAY,QAAQ,KAAK;AAAA,MAC7C,mBAAmB,IAAI,YAAY,QAAQ,SAAS;AAAA,MACpD,mBAAmB,IAAI,YAAY,QAAQ,SAAS;AAAA,MACpD,yBAAyB,IAAI,YAAY,QAAQ,oBAAoB,CAAC;AAAA,IACxE;AAAA,IACA,SAAS,QAAQ,QAAQ,IAAI,CAAC,YAAY;AAAA,MACxC,KAAK,aAAa,OAAO,IAAI;AAAA,MAC7B,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,UAAU,OAAO;AAAA,MACjB,QAAQ,OAAO;AAAA,IACjB,EAAE;AAAA,IACF;AAAA,IACA,UAAU,QAAQ,eAAe;AAAA,IACjC,QAAQ;AAAA,IACR,aAAa,QAAQ,QAAQ;AAAA,IAC7B,MAAM,MAAM,QAAQ,QAAQ,IAAI,IAC5B,QAAQ,OACR,OAAO,QAAQ,SAAS,WACtB,CAAC,QAAQ,IAAI,IACb,CAAC;AAAA,IACP,QAAQ,QAAQ;AAAA,IAChB,eAAe,IAAI,kBAAkB,QAAQ,cAAc;AAAA,IAC3D,sBAAsB;AAAA,IACtB,WAAW,cAAc,QAAQ,UAAU;AAAA,IAC3C,WAAW,cAAc,QAAQ,UAAU;AAAA,IAC3C,UAAU,YAAY,OAAO;AAAA,IAC7B,QAAQ,MAAM,QAAQ,QAAQ,MAAM,IAChC,QAAQ,OAAO,IAAI,CAAC,UAAU,WAAW;AAAA,MACvC,IAAI,QAAQ;AAAA,MACZ,WAAW,QAAQ;AAAA,MACnB,KAAK;AAAA,MACL,UAAU,QAAQ;AAAA,MAClB,KAAK,IAAI,kBAAkB,QAAQ;AAAA,MACnC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,YAAY,CAAC;AAAA,MACb,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ;AAAA,IACrB,EAAE,IACF,CAAC;AAAA,IACL,cAAa,mBAAc,QAAQ,YAAY,MAAlC,YAAuC;AAAA,IACpD,KAAK;AAAA,IACL,UAAU;AAAA,IACV,cAAc;AAAA,IACd,WAAW;AAAA,IACX,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,KAAK,QAAQ,OAAO,GAAG,IAAI,WAAW,aAAa,QAAQ,MAAM;AAAA,EACnE;AAEA,SAAO;AACT;;;ACzNO,IAAM,aAAN,MAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoCtB,YAAY,SAAiB;AAhC7B,SAAQ,kBAAwC,oBAAI,IAAI;AACxD;AAAA,SAAQ,cAAsB,IAAI,KAAK;AACvC;AAAA,SAAQ,kBAAuC,oBAAI,IAAI;AACvD,SAAQ,yBAA8C,oBAAI,IAAI;AA+B5D,QAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAGA,QAAI,gBAAgB,QAAQ,KAAK;AACjC,QACE,CAAC,cAAc,WAAW,SAAS,KACnC,CAAC,cAAc,WAAW,UAAU,GACpC;AACA,sBAAgB,WAAW,aAAa;AAAA,IAC1C;AAEA,QAAI;AACJ,QAAI;AACF,iBAAW,IAAI,IAAI,aAAa;AAAA,IAClC,SAAS,QAAQ;AACf,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AAGA,UAAM,WAAW,SAAS;AAC1B,QAAI,CAAC,YAAY,SAAS,SAAS,GAAG;AACpC,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACvC;AAGA,QACE,SAAS,SAAS,IAAI,KACtB,SAAS,SAAS,IAAI,KACtB,SAAS,SAAS,GAAG,GACrB;AACA,YAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AAGA,QACE,CAAC,SAAS,SAAS,GAAG,KACtB,SAAS,WAAW,GAAG,KACvB,SAAS,SAAS,GAAG,GACrB;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAGA,UAAM,gBACJ;AACF,QAAI,CAAC,cAAc,KAAK,QAAQ,GAAG;AACjC,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AAEA,SAAK,cAAc,WAAW,QAAQ;AACtC,QAAI,WAAW,WAAW,QAAQ,GAAG,SAAS,QAAQ;AACtD,QAAI,CAAC,SAAS,SAAS,GAAG,GAAG;AAC3B,iBAAW,GAAG,QAAQ;AAAA,IACxB;AACA,SAAK,UAAU;AAGf,SAAK,YAAY,kBAAkB,KAAK,WAAW;AAGnD,SAAK,kBAAkB,sBAAsB;AAAA,MAC3C,SAAS,KAAK;AAAA,MACd,aAAa,KAAK;AAAA,MAClB,uBAAuB,KAAK,sBAAsB,KAAK,IAAI;AAAA,MAC3D,0BAA0B,KAAK,yBAAyB,KAAK,IAAI;AAAA,MACjE,wBAAwB,KAAK,uBAAuB,KAAK,IAAI;AAAA,MAC7D,kBAAkB,KAAK,iBAAiB,KAAK,IAAI;AAAA,IACnD,CAAC;AAED,SAAK,WAAW;AAAA,MACd,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,cAAc,KAAK,IAAI;AAAA,MAC5B,KAAK,YAAY,KAAK,IAAI;AAAA,MAC1B,KAAK,WAAW,KAAK,IAAI;AAAA,MACzB,MAAM,KAAK,QAAQ;AAAA,MACnB,CAAC,WAAmB,KAAK,SAAS,KAAK,MAAM;AAAA,IAC/C;AAEA,SAAK,cAAc;AAAA,MACjB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,iBAAiB,KAAK,IAAI;AAAA,MAC/B,KAAK,eAAe,KAAK,IAAI;AAAA,MAC7B,KAAK,qCAAqC,KAAK,IAAI;AAAA,MACnD,MAAM,KAAK,QAAQ;AAAA,MACnB,CAAC,WAAmB,KAAK,YAAY,KAAK,MAAM;AAAA,IAClD;AAEA,SAAK,WAAW,yBAAyB,KAAK,OAAO;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,KAA6B;AACrD,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,uBAAuB,IAAI,GAAG,GAAG;AACxC,aAAO,KAAK,uBAAuB,IAAI,GAAG;AAAA,IAC5C;AAEA,UAAM,aAAa,IAAI,WAAW,IAAI,IAAI,SAAS,GAAG,KAAK;AAC3D,SAAK,uBAAuB,IAAI,KAAK,UAAU;AAC/C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,eAA+B;AAjMrD;AAkMI,UAAM,YAAW,UAAK,kBAAL,YAAsB;AACvC,QAAI;AACF,aAAO,IAAI,KAAK,aAAa,QAAW;AAAA,QACtC,OAAO;AAAA,QACP;AAAA,MACF,CAAC,EAAE,QAAQ,iBAAiB,KAAK,GAAG;AAAA,IACtC,QAAQ;AACN,YAAM,OAAO,iBAAiB,KAAK;AACnC,aAAO,GAAG,GAAG,IAAI,QAAQ;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,UAA8C;AAjN5D;AAkNI,WAAO,eAAe,UAAU;AAAA,MAC9B,aAAa,KAAK;AAAA,MAClB,WAAW,KAAK;AAAA,MAChB,WAAU,UAAK,kBAAL,YAAsB;AAAA,MAChC,mBAAmB,CAAC,QAAQ,KAAK,kBAAkB,GAAG;AAAA,MACtD,aAAa,CAAC,WAAW,KAAK,YAAY,MAAM;AAAA,IAClD,CAAC;AAAA,EACH;AAAA,EAEA,WAAW,SAAwC;AA3NrD;AA4NI,WAAO,cAAc,SAAS;AAAA,MAC5B,aAAa,KAAK;AAAA,MAClB,WAAW,KAAK;AAAA,MAChB,WAAU,UAAK,kBAAL,YAAsB;AAAA,MAChC,mBAAmB,CAAC,QAAQ,KAAK,kBAAkB,GAAG;AAAA,MACtD,aAAa,CAAC,WAAW,KAAK,YAAY,MAAM;AAAA,IAClD,CAAC;AAAA,EACH;AAAA,EAEA,eAAe,aAAgD;AArOjE;AAsOI,YAAO,oBAAe,WAAW,MAA1B,YAA+B,CAAC;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKQ,iBACN,OACA,SACA,KACO;AACP,QAAI,eAAe,SAAS,OAAO;AACnC,QAAI;AAEJ,QAAI,iBAAiB,OAAO;AAC1B,sBAAgB,KAAK,MAAM,OAAO;AAGlC,UAAI,YAAY,OAAO;AACrB,qBAAa,MAAM;AAAA,MACrB;AAAA,IACF,WAAW,OAAO,UAAU,UAAU;AACpC,sBAAgB,KAAK,KAAK;AAAA,IAC5B,OAAO;AACL,sBAAgB;AAAA,IAClB;AAGA,oBAAgB,UAAU,GAAG;AAG7B,QAAI,YAAY;AACd,sBAAgB,aAAa,UAAU;AAAA,IACzC;AAGA,UAAM,gBAAgB,IAAI,MAAM,YAAY;AAC5C,IAAC,cAAsB,UAAU;AACjC,IAAC,cAAsB,MAAM;AAC7B,IAAC,cAAsB,aAAa;AACpC,IAAC,cAAsB,gBAAgB;AAEvC,UAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,cACZ,MACA,OAC2B;AAC3B,QAAI;AACF,YAAM,MAAM,GAAG,KAAK,OAAO,sBAAsB,IAAI,UAAU,KAAK;AACpE,YAAM,WAAW,MAAM,iBAAiB,GAAG;AAE3C,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,MACnE;AAEA,YAAM,OAAuC,MAAM,SAAS,KAAK;AACjE,aAAO,KAAK,YAAY,KAAK,QAAQ;AAAA,IACvC,SAAS,OAAO;AACd,WAAK;AAAA,QACH;AAAA,QACA;AAAA,QACA,GAAG,KAAK,OAAO;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBAAiB,MAAc,OAAe;AAC1D,QAAI;AACF,YAAM,MAAM,GAAG,KAAK,OAAO,yBAAyB,IAAI,UAAU,KAAK;AACvE,YAAM,WAAW,MAAM,iBAAiB,GAAG;AAE3C,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,MACnE;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,aAAO,KAAK,eAAe,KAAK,WAAW;AAAA,IAC7C,SAAS,OAAO;AACd,WAAK;AAAA,QACH;AAAA,QACA;AAAA,QACA,GAAG,KAAK,OAAO;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,qCACZ,kBACA,UAA6C,CAAC,GAC9C;AACA,QAAI;AACF,YAAM,EAAE,OAAO,GAAG,QAAQ,IAAI,IAAI;AAElC,UAAI,cAAc;AAClB,UAAI;AACF,cAAM,WAAW,MAAM;AAAA,UACrB,GAAG,KAAK,OAAO,eAAe,mBAAmB,gBAAgB,CAAC;AAAA,QACpE;AACA,YAAI,SAAS,IAAI;AACf,gBAAM,WAAW,SAAS;AAC1B,cAAI,UAAU;AACZ,kBAAM,WAAW,IAAI,IAAI,QAAQ,EAAE,SAAS,QAAQ,OAAO,EAAE;AAC7D,kBAAM,QAAQ,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AAChD,kBAAM,MAAM,MAAM,QAAQ,aAAa;AACvC,kBAAM,cAAc,OAAO,IAAI,MAAM,MAAM,CAAC,IAAI;AAChD,gBAAI,OAAO,gBAAgB,YAAY,YAAY,QAAQ;AACzD,4BAAc;AAAA,YAChB;AAAA,UACF;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAEA,YAAM,MAAM,GAAG,KAAK,OAAO,eAAe,WAAW,uBAAuB,IAAI,UAAU,KAAK;AAC/F,YAAM,WAAW,MAAM,iBAAiB,GAAG;AAE3C,UAAI,CAAC,SAAS,IAAI;AAChB,YAAI,SAAS,WAAW,KAAK;AAC3B,iBAAO;AAAA,QACT;AACA,cAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,MACnE;AAEA,YAAM,OAAuC,MAAM,SAAS,KAAK;AACjE,aAAO,KAAK,YAAY,KAAK,QAAQ;AAAA,IACvC,SAAS,OAAO;AACd,WAAK;AAAA,QACH;AAAA,QACA;AAAA,QACA,GAAG,KAAK,OAAO,eAAe,gBAAgB;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,sBAAsB,QAAkC;AACpE,UAAM,WAAW,WAAW,MAAM;AAElC,QAAI,KAAK,aAAa,QAAQ,GAAG;AAC/B,aAAO,KAAK,gBAAgB,IAAI,QAAQ,KAAK;AAAA,IAC/C;AAEA,QAAI;AACF,YAAM,MAAM,GAAG,KAAK,OAAO,YAAY,MAAM;AAC7C,YAAM,WAAW,MAAM,iBAAiB,KAAK,EAAE,QAAQ,OAAO,CAAC;AAC/D,YAAM,SAAS,SAAS;AAExB,WAAK,cAAc,UAAU,MAAM;AACnC,aAAO;AAAA,IACT,SAAS,QAAQ;AACf,WAAK,cAAc,UAAU,KAAK;AAClC,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,yBAAyB,QAAkC;AACvE,UAAM,WAAW,cAAc,MAAM;AAErC,QAAI,KAAK,aAAa,QAAQ,GAAG;AAC/B,aAAO,KAAK,gBAAgB,IAAI,QAAQ,KAAK;AAAA,IAC/C;AAEA,QAAI;AACF,YAAM,MAAM,GAAG,KAAK,OAAO,eAAe,MAAM;AAChD,YAAM,WAAW,MAAM,iBAAiB,KAAK,EAAE,QAAQ,OAAO,CAAC;AAC/D,YAAM,SAAS,SAAS;AAExB,WAAK,cAAc,UAAU,MAAM;AACnC,aAAO;AAAA,IACT,SAAS,QAAQ;AACf,WAAK,cAAc,UAAU,KAAK;AAClC,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,KAAsB;AACzC,UAAM,YAAY,KAAK,gBAAgB,IAAI,GAAG;AAC9C,QAAI,CAAC,UAAW,QAAO;AAEvB,WAAO,KAAK,IAAI,IAAI,YAAY,KAAK;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,KAAa,OAAsB;AACvD,SAAK,gBAAgB,IAAI,KAAK,KAAK;AACnC,SAAK,gBAAgB,IAAI,KAAK,KAAK,IAAI,CAAC;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,uBACZ,OACA,WACA,YAAY,IACE;AACd,UAAM,aAAkB,CAAC;AAEzB,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,WAAW;AAChD,YAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,SAAS;AAC1C,YAAM,qBAAqB,MAAM,IAAI,OAAO,SAAS;AACnD,cAAM,UAAU,MAAM,UAAU,IAAI;AACpC,eAAO,UAAU,OAAO;AAAA,MAC1B,CAAC;AAED,YAAM,UAAU,MAAM,QAAQ,IAAI,kBAAkB;AACpD,YAAM,kBAAkB,QAAQ;AAAA,QAC9B,CAAC,SAA2C,SAAS;AAAA,MACvD;AACA,iBAAW,KAAK,GAAG,eAAe;AAGlC,UAAI,IAAI,YAAY,MAAM,QAAQ;AAChC,cAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG,CAAC;AAAA,MACzD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiCA,MAAM,UAA8B;AAClC,QAAI;AACF,YAAM,EAAE,MAAM,aAAa,IAAI,MAAM,gBAAgB;AAAA,QACnD,SAAS,KAAK;AAAA,QACd,aAAa,KAAK;AAAA,QAClB,uBAAuB,CAAC,WAAW,KAAK,sBAAsB,MAAM;AAAA,QACpE,0BAA0B,CAAC,WACzB,KAAK,yBAAyB,MAAM;AAAA,QACtC,wBAAwB,CAAC,OAAO,WAAW,cACzC,KAAK,uBAAuB,OAAO,WAAW,SAAS;AAAA,MAC3D,CAAC;AACD,UAAI,OAAO,iBAAiB,UAAU;AACpC,aAAK,gBAAgB;AAAA,MACvB;AACA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,iBAAiB,OAAO,uBAAuB,KAAK,OAAO;AAAA,IAClE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,mBAAmB,SAKO;AAC9B,QAAI;AACF,YAAM,YAAY,MAAM,2BAA2B;AAAA,QACjD,SAAS,KAAK;AAAA,QACd,SAAS,MAAM,KAAK,QAAQ;AAAA,QAC5B,aAAa,CAAC,WAAmB,KAAK,SAAS,KAAK,MAAM;AAAA,QAC1D,QAAQ,mCAAS;AAAA,QACjB,OAAO,mCAAS;AAAA,QAChB,qBAAqB,mCAAS;AAAA,QAC9B,wBAAwB,mCAAS;AAAA,MACnC,CAAC;AACD,aAAO;AAAA,IACT,SAAS,OAAgB;AACvB,YAAM,KAAK,iBAAiB,OAAO,sBAAsB,KAAK,OAAO;AAAA,IACvE;AAAA,EACF;AACF;","names":["_a"]}
@@ -1,63 +0,0 @@
1
- import { y as CurrencyCode, c as Product, P as ProductClassification, S as SEOContent, b as ShopifyProduct, d as ShopifySingleProduct, g as StoreInfo } from './store-CJVUz2Yb.mjs';
2
-
3
- /**
4
- * Interface for product operations
5
- */
6
- interface ProductOperations {
7
- /**
8
- * Fetches all products from the store across all pages.
9
- */
10
- all(options?: {
11
- currency?: CurrencyCode;
12
- }): Promise<Product[] | null>;
13
- /**
14
- * Fetches products with pagination support.
15
- */
16
- paginated(options?: {
17
- page?: number;
18
- limit?: number;
19
- currency?: CurrencyCode;
20
- }): Promise<Product[] | null>;
21
- /**
22
- * Finds a specific product by its handle.
23
- */
24
- find(productHandle: string, options?: {
25
- currency?: CurrencyCode;
26
- }): Promise<Product | null>;
27
- /**
28
- * Finds a product by handle and enriches its content using LLM.
29
- * Requires an OpenAI API key via options.apiKey or process.env.OPENAI_API_KEY.
30
- */
31
- enriched(productHandle: string, options?: {
32
- apiKey?: string;
33
- useGfm?: boolean;
34
- inputType?: "markdown" | "html";
35
- model?: string;
36
- outputFormat?: "markdown" | "json";
37
- }): Promise<Product | null>;
38
- classify(productHandle: string, options?: {
39
- apiKey?: string;
40
- model?: string;
41
- }): Promise<ProductClassification | null>;
42
- /**
43
- * Generate SEO and marketing content for a product.
44
- */
45
- generateSEOContent(productHandle: string, options?: {
46
- apiKey?: string;
47
- model?: string;
48
- }): Promise<SEOContent | null>;
49
- /**
50
- * Fetches products that are showcased/featured on the store's homepage.
51
- */
52
- showcased(): Promise<Product[]>;
53
- /**
54
- * Creates a filter map of variant options and their distinct values from all products.
55
- */
56
- filter(): Promise<Record<string, string[]> | null>;
57
- }
58
- /**
59
- * Creates product operations for a store instance
60
- */
61
- declare function createProductOperations(baseUrl: string, storeDomain: string, fetchProducts: (page: number, limit: number) => Promise<Product[] | null>, productsDto: (products: ShopifyProduct[]) => Product[] | null, productDto: (product: ShopifySingleProduct) => Product, getStoreInfo: () => Promise<StoreInfo>, findProduct: (handle: string) => Promise<Product | null>): ProductOperations;
62
-
63
- export { type ProductOperations, createProductOperations };