@huskel/sdk 0.2.2 → 0.2.3
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.
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
"use strict";
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -536,3 +537,4 @@ function Sparkle({ productName, limit = 5, onResult, className }) {
|
|
|
536
537
|
useIngest,
|
|
537
538
|
useSearch
|
|
538
539
|
});
|
|
540
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/api.ts","../src/client.ts","../src/hooks/useHuskel.ts","../src/hooks/useSearch.ts","../src/components/HuskelProvider.tsx","../src/hooks/useIngest.ts","../src/components/SearchBar.tsx","../src/components/Sparkle.tsx"],"sourcesContent":["export { initHuskel, getHuskelClient, HuskelClient } from './client';\r\nexport { HuskelAPI } from './api';\r\nexport { useHuskel } from './hooks/useHuskel';\r\nexport { useSearch } from './hooks/useSearch';\r\nexport { useIngest } from './hooks/useIngest';\r\nexport { SearchBar } from './components/SearchBar';\r\nexport { Sparkle } from './components/Sparkle';\r\nexport { HuskelProvider } from './components/HuskelProvider';\r\nexport type {\r\n Product,\r\n RawProductInput,\r\n HuskelConfig,\r\n SearchRequest,\r\n SearchResult,\r\n SearchResponse,\r\n IngestResponse,\r\n HuskelError,\r\n} from './types';\r\n","import { Product, SearchResponse, IngestResponse, HuskelError } from './types';\r\n\r\nconst MAX_RETRIES = 3;\r\nconst RETRY_DELAYS = [500, 1000, 2000]; // ms\r\n\r\nfunction log(level: 'info' | 'warn' | 'error', msg: string, data?: unknown) {\r\n const prefix = '[Huskel]';\r\n if (level === 'error') console.error(prefix, msg, data ?? '');\r\n else if (level === 'warn') console.warn(prefix, msg, data ?? '');\r\n else console.log(prefix, msg, data ?? '');\r\n}\r\n\r\nasync function sleep(ms: number) {\r\n return new Promise(r => setTimeout(r, ms));\r\n}\r\n\r\nexport class HuskelAPI {\r\n constructor(\r\n private apiUrl: string,\r\n private siteId: string,\r\n private apiToken: string\r\n ) {}\r\n\r\n private async post<T>(path: string, body: unknown, attempt = 0): Promise<T> {\r\n const url = `${this.apiUrl}${path}`;\r\n\r\n try {\r\n const res = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'X-Huskel-Token': this.apiToken,\r\n 'X-Huskel-Site': this.siteId,\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n const err: HuskelError = { status: res.status, message: text };\r\n\r\n // Don't retry 4xx — developer errors\r\n if (res.status >= 400 && res.status < 500) {\r\n log('error', `${path} failed [${res.status}]`, text);\r\n throw err;\r\n }\r\n\r\n // Retry 5xx\r\n if (attempt < MAX_RETRIES - 1) {\r\n log('warn', `${path} [${res.status}] retrying (${attempt + 1}/${MAX_RETRIES})...`);\r\n await sleep(RETRY_DELAYS[attempt]);\r\n return this.post(path, body, attempt + 1);\r\n }\r\n\r\n log('error', `${path} failed after ${MAX_RETRIES} attempts`, err);\r\n throw err;\r\n }\r\n\r\n return res.json();\r\n } catch (e) {\r\n // Network error (offline, DNS, etc.)\r\n if ((e as HuskelError).status === undefined) {\r\n if (attempt < MAX_RETRIES - 1) {\r\n log('warn', `${path} network error, retrying (${attempt + 1}/${MAX_RETRIES})...`);\r\n await sleep(RETRY_DELAYS[attempt]);\r\n return this.post(path, body, attempt + 1);\r\n }\r\n log('error', `${path} unreachable after ${MAX_RETRIES} attempts`);\r\n }\r\n throw e;\r\n }\r\n }\r\n\r\n async ingest(product: Product): Promise<IngestResponse> {\r\n log('info', 'ingesting product', product.name);\r\n return this.post('/ingest', { siteId: this.siteId, product });\r\n }\r\n\r\n async ingestBatch(products: Product[]): Promise<IngestResponse> {\r\n log('info', `ingesting batch of ${products.length} products`);\r\n return this.post('/ingest/batch', { siteId: this.siteId, products });\r\n }\r\n\r\n async search(query: string, limit = 10): Promise<SearchResponse> {\r\n log('info', 'search query', query);\r\n return this.post('/search', { query, siteId: this.siteId, limit });\r\n }\r\n}\r\n","import { HuskelConfig, Product, RawProductInput } from './types';\r\nimport { HuskelAPI } from './api';\r\n\r\nfunction getEnvVar(key: string): string | undefined {\r\n if (typeof globalThis !== 'undefined') {\r\n const g = globalThis as any;\r\n if (g.process && g.process.env) {\r\n return g.process.env[key];\r\n }\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction mapRawProduct(input: RawProductInput): Product | null {\r\n const name = input.name || input.title || input.productName || '';\r\n \r\n let price = '';\r\n let priceNumeric: number | undefined = undefined;\r\n\r\n if (input.price !== undefined) {\r\n if (typeof input.price === 'number') {\r\n priceNumeric = input.price;\r\n price = String(input.price);\r\n } else {\r\n price = input.price;\r\n const num = parseFloat(input.price.replace(/[^0-9.]/g, ''));\r\n priceNumeric = isNaN(num) ? undefined : num;\r\n }\r\n }\r\n if (input.priceNumeric !== undefined) {\r\n priceNumeric = input.priceNumeric;\r\n }\r\n\r\n let url = input.url || '';\r\n if (!url && typeof window !== 'undefined') {\r\n url = window.location.href;\r\n }\r\n\r\n let slug = input.slug || input.id || input.productId || '';\r\n if (!slug && url) {\r\n slug = url.split('/').filter(Boolean).pop() || '';\r\n }\r\n if (!slug && name) {\r\n slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');\r\n }\r\n\r\n let images: string[] = [];\r\n if (input.images) {\r\n images = input.images;\r\n } else if (input.image) {\r\n images = [input.image];\r\n } else if (input.thumbnail) {\r\n images = [input.thumbnail];\r\n }\r\n\r\n if (!name) {\r\n console.warn('[Huskel] Validation warning: Product name/title is missing. Skipping:', input);\r\n return null;\r\n }\r\n if (!price) {\r\n console.warn('[Huskel] Validation warning: Product price is missing. Skipping:', input);\r\n return null;\r\n }\r\n if (!url) {\r\n console.warn('[Huskel] Validation warning: Product URL is missing. Skipping:', input);\r\n return null;\r\n }\r\n\r\n return {\r\n name,\r\n price,\r\n url,\r\n brand: input.brand,\r\n description: input.description,\r\n originalPrice: input.originalPrice,\r\n discount: input.discount,\r\n currency: input.currency ?? 'KES',\r\n stock: input.stock,\r\n availability: input.availability,\r\n rating: input.rating,\r\n reviewCount: input.reviewCount,\r\n category: input.category,\r\n subCategory: input.subCategory,\r\n tags: input.tags,\r\n images: images.length > 0 ? images : undefined,\r\n specs: input.specs,\r\n priceNumeric,\r\n slug,\r\n };\r\n}\r\n\r\nexport class HuskelClient {\r\n readonly api: HuskelAPI;\r\n private ingestQueue: Product[] = [];\r\n private ingestTimer: ReturnType<typeof setTimeout> | null = null;\r\n private ingestedUrls = new Set<string>();\r\n private onlineHandler: (() => void) | null = null;\r\n\r\n constructor(config: HuskelConfig) {\r\n const siteId = config.siteId || getEnvVar('NEXT_PUBLIC_HUSKEL_SITE_ID') || '';\r\n const apiUrl = config.apiUrl || getEnvVar('NEXT_PUBLIC_HUSKEL_API_URL') || '';\r\n const apiToken = config.apiToken || getEnvVar('NEXT_PUBLIC_HUSKEL_API_TOKEN') || '';\r\n\r\n // Runtime validation — fail loudly so misconfiguration is never silent\r\n if (!siteId) console.error('[Huskel] Missing siteId. Set it via <HuskelProvider siteId=\"...\"> or NEXT_PUBLIC_HUSKEL_SITE_ID.');\r\n if (!apiUrl) console.error('[Huskel] Missing apiUrl. Set it via <HuskelProvider apiUrl=\"...\"> or NEXT_PUBLIC_HUSKEL_API_URL.');\r\n if (!apiToken) console.error('[Huskel] Missing apiToken. Set it via <HuskelProvider apiToken=\"...\"> or NEXT_PUBLIC_HUSKEL_API_TOKEN.');\r\n\r\n this.api = new HuskelAPI(apiUrl, siteId, apiToken);\r\n instance = this;\r\n\r\n if (typeof window !== 'undefined') {\r\n this.onlineHandler = () => {\r\n console.log('[Huskel] Connectivity restored, flushing queued ingestions.');\r\n this.flushQueue();\r\n };\r\n window.addEventListener('online', this.onlineHandler);\r\n }\r\n }\r\n\r\n destroy() {\r\n if (typeof window !== 'undefined' && this.onlineHandler) {\r\n window.removeEventListener('online', this.onlineHandler);\r\n this.onlineHandler = null;\r\n }\r\n if (this.ingestTimer) {\r\n clearTimeout(this.ingestTimer);\r\n this.ingestTimer = null;\r\n }\r\n if (instance === this) instance = null;\r\n }\r\n\r\n async queueIngest(rawProduct: RawProductInput): Promise<void> {\r\n const product = mapRawProduct(rawProduct);\r\n if (!product) return;\r\n\r\n if (this.ingestedUrls.has(product.url)) {\r\n return;\r\n }\r\n this.ingestedUrls.add(product.url);\r\n\r\n this.ingestQueue.push(product);\r\n this.scheduleFlush();\r\n }\r\n\r\n async queueIngestBatch(rawProducts: RawProductInput[]): Promise<void> {\r\n rawProducts.forEach(p => {\r\n const product = mapRawProduct(p);\r\n if (!product) return;\r\n\r\n if (this.ingestedUrls.has(product.url)) {\r\n return;\r\n }\r\n this.ingestedUrls.add(product.url);\r\n this.ingestQueue.push(product);\r\n });\r\n\r\n if (this.ingestQueue.length > 0) {\r\n this.scheduleFlush();\r\n }\r\n }\r\n\r\n private scheduleFlush() {\r\n if (this.ingestTimer) return;\r\n this.ingestTimer = setTimeout(() => {\r\n this.flushQueue();\r\n }, 300);\r\n }\r\n\r\n private async flushQueue() {\r\n this.ingestTimer = null;\r\n if (this.ingestQueue.length === 0) return;\r\n\r\n if (typeof navigator !== 'undefined' && !navigator.onLine) {\r\n console.warn('[Huskel] Browser offline. Postponing ingestion.');\r\n return;\r\n }\r\n\r\n const batch = [...this.ingestQueue];\r\n this.ingestQueue = [];\r\n\r\n try {\r\n await this.api.ingestBatch(batch);\r\n } catch (e: any) {\r\n if (e.status && e.status >= 400 && e.status < 500) {\r\n console.error('[Huskel] Ingestion discarded due to client error:', e.message);\r\n return;\r\n }\r\n\r\n // Re-queue and schedule another flush so items are not stuck forever\r\n console.warn('[Huskel] Ingestion failed. Re-queuing to retry.', e);\r\n this.ingestQueue = [...batch, ...this.ingestQueue];\r\n this.scheduleFlush();\r\n }\r\n }\r\n}\r\n\r\nlet instance: HuskelClient | null = null;\r\n\r\nexport function initHuskel(config: HuskelConfig): HuskelClient {\r\n instance = new HuskelClient(config);\r\n return instance;\r\n}\r\n\r\nexport function getHuskelClient(): HuskelClient {\r\n if (!instance) {\r\n const siteId = getEnvVar('NEXT_PUBLIC_HUSKEL_SITE_ID');\r\n const apiUrl = getEnvVar('NEXT_PUBLIC_HUSKEL_API_URL');\r\n const apiToken = getEnvVar('NEXT_PUBLIC_HUSKEL_API_TOKEN');\r\n\r\n if (siteId && apiUrl && apiToken) {\r\n instance = new HuskelClient({ siteId, apiUrl, apiToken });\r\n } else {\r\n throw new Error('[Huskel] Call initHuskel() or set NEXT_PUBLIC_HUSKEL_* environment variables before using the client.');\r\n }\r\n }\r\n return instance;\r\n}\r\n","import { useRef } from 'react';\r\nimport { HuskelConfig } from '../types';\r\nimport { HuskelClient, initHuskel } from '../client';\r\n\r\n/**\r\n * @deprecated Use <HuskelProvider> instead to avoid SSR issues.\r\n */\r\nexport function useHuskel(config: HuskelConfig): HuskelClient {\r\n const clientRef = useRef<HuskelClient | null>(null);\r\n\r\n if (!clientRef.current) {\r\n console.warn('[Huskel] useHuskel() is deprecated. Please wrap your application in <HuskelProvider> instead.');\r\n clientRef.current = initHuskel(config);\r\n }\r\n\r\n return clientRef.current;\r\n}\r\n","import { useState, useCallback, useRef } from 'react';\r\nimport { SearchResult } from '../types';\r\nimport { useHuskelContext } from '../components/HuskelProvider';\r\n\r\ninterface UseSearchReturn {\r\n results: SearchResult[];\r\n loading: boolean;\r\n error: string | null;\r\n search: (query: string, limit?: number) => Promise<void>;\r\n clear: () => void;\r\n}\r\n\r\nexport function useSearch(): UseSearchReturn {\r\n const client = useHuskelContext();\r\n const [results, setResults] = useState<SearchResult[]>([]);\r\n const [loading, setLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const abortRef = useRef<AbortController | null>(null);\r\n\r\n const search = useCallback(async (query: string, limit = 10) => {\r\n if (!query.trim()) { setResults([]); return; }\r\n abortRef.current?.abort();\r\n abortRef.current = new AbortController();\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n const res = await client.api.search(query, limit);\r\n setResults(res.results ?? []);\r\n } catch (e: unknown) {\r\n setError((e as Error).message ?? 'Search failed');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [client]);\r\n\r\n const clear = useCallback(() => { setResults([]); setError(null); }, []);\r\n\r\n return { results, loading, error, search, clear };\r\n}\r\n","'use client';\r\n\r\nimport React, { createContext, useContext, useEffect, useRef } from 'react';\r\nimport { HuskelClient, getHuskelClient } from '../client';\r\nimport { HuskelConfig } from '../types';\r\n\r\nexport const HuskelContext = createContext<HuskelClient | null>(null);\r\n\r\ninterface HuskelProviderProps extends HuskelConfig {\r\n children: React.ReactNode;\r\n}\r\n\r\nexport function HuskelProvider({ siteId, apiUrl, apiToken, children }: HuskelProviderProps) {\r\n const clientRef = useRef<HuskelClient | null>(null);\r\n\r\n if (!clientRef.current) {\r\n clientRef.current = new HuskelClient({ siteId, apiUrl, apiToken });\r\n }\r\n\r\n // Clean up the online listener and timers when the provider unmounts\r\n // (prevents leaks during hot module reload and React StrictMode double-mount)\r\n useEffect(() => {\r\n return () => {\r\n clientRef.current?.destroy();\r\n };\r\n }, []);\r\n\r\n return (\r\n <HuskelContext.Provider value={clientRef.current}>\r\n {children}\r\n </HuskelContext.Provider>\r\n );\r\n}\r\n\r\nexport function useHuskelContext(): HuskelClient {\r\n const context = useContext(HuskelContext);\r\n if (!context) {\r\n return getHuskelClient();\r\n }\r\n return context;\r\n}\r\n\r\n","import { useCallback, useState } from 'react';\r\nimport { RawProductInput } from '../types';\r\nimport { useHuskelContext } from '../components/HuskelProvider';\r\n\r\ninterface UseIngestReturn {\r\n ingest: (product: RawProductInput) => Promise<void>;\r\n ingestBatch: (products: RawProductInput[]) => Promise<void>;\r\n loading: boolean;\r\n error: string | null;\r\n}\r\n\r\nexport function useIngest(): UseIngestReturn {\r\n const client = useHuskelContext();\r\n const [loading, setLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const ingest = useCallback(async (product: RawProductInput) => {\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n await client.queueIngest(product);\r\n } catch (e: unknown) {\r\n setError((e as Error).message ?? 'Ingest failed');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [client]);\r\n\r\n const ingestBatch = useCallback(async (products: RawProductInput[]) => {\r\n if (!products.length) return;\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n await client.queueIngestBatch(products);\r\n } catch (e: unknown) {\r\n setError((e as Error).message ?? 'Batch ingest failed');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [client]);\r\n\r\n return { ingest, ingestBatch, loading, error };\r\n}\r\n","import React, { useState, useEffect, useRef } from 'react';\r\nimport { useSearch } from '../hooks/useSearch';\r\nimport { SearchResult } from '../types';\r\n\r\ninterface SearchBarProps {\r\n placeholder?: string;\r\n limit?: number;\r\n debounceMs?: number;\r\n onSelect?: (result: SearchResult) => void;\r\n className?: string;\r\n inputClassName?: string;\r\n dropdownClassName?: string;\r\n renderResult?: (result: SearchResult) => React.ReactNode;\r\n}\r\n\r\nconst S = `\r\n .hsk-wrap{position:relative;width:100%;font-family:inherit}\r\n .hsk-input{width:100%;padding:10px 16px;font-size:15px;border:1.5px solid #e2e2e2;border-radius:8px;outline:none;box-sizing:border-box;background:#fff;transition:border-color .2s}\r\n .hsk-input:focus{border-color:#f47c3c}\r\n .hsk-drop{position:absolute;top:calc(100% + 6px);left:0;right:0;background:#fff;border:1px solid #e2e2e2;border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.1);z-index:9999;max-height:360px;overflow-y:auto}\r\n .hsk-item{display:flex;align-items:center;gap:12px;padding:10px 14px;cursor:pointer;transition:background .15s}\r\n .hsk-item:hover{background:#faf5f1}\r\n .hsk-item img{width:40px;height:40px;object-fit:cover;border-radius:4px}\r\n .hsk-item-name{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\r\n .hsk-item-price{font-size:13px;color:#f47c3c;margin-top:2px}\r\n .hsk-msg{padding:16px;text-align:center;font-size:14px;color:#888}\r\n`;\r\n\r\nexport function SearchBar({\r\n placeholder = 'Search for what you want — how you want',\r\n limit = 10,\r\n debounceMs = 300,\r\n onSelect,\r\n className,\r\n inputClassName,\r\n dropdownClassName,\r\n renderResult,\r\n}: SearchBarProps) {\r\n const [query, setQuery] = useState('');\r\n const [open, setOpen] = useState(false);\r\n const { results, loading, search, clear } = useSearch();\r\n const timer = useRef<ReturnType<typeof setTimeout>>();\r\n const wrap = useRef<HTMLDivElement>(null);\r\n\r\n useEffect(() => {\r\n clearTimeout(timer.current);\r\n if (!query.trim()) { clear(); setOpen(false); return; }\r\n timer.current = setTimeout(() => { search(query, limit); setOpen(true); }, debounceMs);\r\n return () => clearTimeout(timer.current);\r\n }, [query, search, clear, limit, debounceMs]);\r\n\r\n useEffect(() => {\r\n const handler = (e: MouseEvent) => {\r\n if (wrap.current && !wrap.current.contains(e.target as Node)) setOpen(false);\r\n };\r\n document.addEventListener('mousedown', handler);\r\n return () => document.removeEventListener('mousedown', handler);\r\n }, []);\r\n\r\n const handleSelect = (r: SearchResult) => {\r\n setOpen(false);\r\n setQuery(r.product.name);\r\n onSelect?.(r);\r\n };\r\n\r\n return (\r\n <>\r\n <style>{S}</style>\r\n <div className={`hsk-wrap ${className ?? ''}`} ref={wrap}>\r\n <input\r\n className={`hsk-input ${inputClassName ?? ''}`}\r\n type=\"text\"\r\n value={query}\r\n placeholder={placeholder}\r\n onChange={e => setQuery(e.target.value)}\r\n onFocus={() => results.length && setOpen(true)}\r\n />\r\n {open && (\r\n <div className={`hsk-drop ${dropdownClassName ?? ''}`}>\r\n {loading && <div className=\"hsk-msg\">Searching…</div>}\r\n {!loading && results.length === 0 && <div className=\"hsk-msg\">No results for \"{query}\"</div>}\r\n {results.map(r =>\r\n renderResult ? (\r\n <div key={r.id} onClick={() => handleSelect(r)}>{renderResult(r)}</div>\r\n ) : (\r\n <div key={r.id} className=\"hsk-item\" onClick={() => handleSelect(r)}>\r\n {r.product.images?.[0] && <img src={r.product.images[0]} alt={r.product.name} />}\r\n <div>\r\n <div className=\"hsk-item-name\">{r.product.name}</div>\r\n <div className=\"hsk-item-price\">{r.product.currency ?? 'KES'} {r.product.price}</div>\r\n </div>\r\n </div>\r\n )\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n </>\r\n );\r\n}\r\n","import React, { useState } from 'react';\r\nimport { useHuskelContext } from './HuskelProvider';\r\nimport { SearchResult } from '../types';\r\n\r\ninterface SparkleProps {\r\n productName: string;\r\n limit?: number;\r\n onResult?: (results: SearchResult[]) => void;\r\n className?: string;\r\n}\r\n\r\nconst S = `\r\n .hsk-sparkle{display:inline-flex;align-items:center;gap:5px;padding:4px 10px;font-size:12px;font-weight:600;background:#f47c3c;color:#fff;border:none;border-radius:20px;cursor:pointer;transition:opacity .2s,transform .15s}\r\n .hsk-sparkle:hover{opacity:.88;transform:scale(1.04)}\r\n .hsk-sparkle:disabled{opacity:.5;cursor:not-allowed}\r\n`;\r\n\r\nexport function Sparkle({ productName, limit = 5, onResult, className }: SparkleProps) {\r\n const client = useHuskelContext();\r\n const [loading, setLoading] = useState(false);\r\n\r\n const handleClick = async () => {\r\n setLoading(true);\r\n try {\r\n const res = await client.api.search(productName, limit);\r\n onResult?.(res.results);\r\n } catch (e) {\r\n console.error('[Huskel Sparkle]', e);\r\n } finally {\r\n setLoading(false);\r\n }\r\n };\r\n\r\n return (\r\n <>\r\n <style>{S}</style>\r\n <button className={`hsk-sparkle ${className ?? ''}`} onClick={handleClick} disabled={loading}>\r\n ✦ {loading ? 'Finding…' : 'Similar'}\r\n </button>\r\n </>\r\n );\r\n}\r\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","S"]}
|
package/dist/index.mjs
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/api.ts","../src/client.ts","../src/hooks/useHuskel.ts","../src/hooks/useSearch.ts","../src/components/HuskelProvider.tsx","../src/hooks/useIngest.ts","../src/components/SearchBar.tsx","../src/components/Sparkle.tsx"],"sourcesContent":["import { Product, SearchResponse, IngestResponse, HuskelError } from './types';\r\n\r\nconst MAX_RETRIES = 3;\r\nconst RETRY_DELAYS = [500, 1000, 2000]; // ms\r\n\r\nfunction log(level: 'info' | 'warn' | 'error', msg: string, data?: unknown) {\r\n const prefix = '[Huskel]';\r\n if (level === 'error') console.error(prefix, msg, data ?? '');\r\n else if (level === 'warn') console.warn(prefix, msg, data ?? '');\r\n else console.log(prefix, msg, data ?? '');\r\n}\r\n\r\nasync function sleep(ms: number) {\r\n return new Promise(r => setTimeout(r, ms));\r\n}\r\n\r\nexport class HuskelAPI {\r\n constructor(\r\n private apiUrl: string,\r\n private siteId: string,\r\n private apiToken: string\r\n ) {}\r\n\r\n private async post<T>(path: string, body: unknown, attempt = 0): Promise<T> {\r\n const url = `${this.apiUrl}${path}`;\r\n\r\n try {\r\n const res = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'X-Huskel-Token': this.apiToken,\r\n 'X-Huskel-Site': this.siteId,\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n const err: HuskelError = { status: res.status, message: text };\r\n\r\n // Don't retry 4xx — developer errors\r\n if (res.status >= 400 && res.status < 500) {\r\n log('error', `${path} failed [${res.status}]`, text);\r\n throw err;\r\n }\r\n\r\n // Retry 5xx\r\n if (attempt < MAX_RETRIES - 1) {\r\n log('warn', `${path} [${res.status}] retrying (${attempt + 1}/${MAX_RETRIES})...`);\r\n await sleep(RETRY_DELAYS[attempt]);\r\n return this.post(path, body, attempt + 1);\r\n }\r\n\r\n log('error', `${path} failed after ${MAX_RETRIES} attempts`, err);\r\n throw err;\r\n }\r\n\r\n return res.json();\r\n } catch (e) {\r\n // Network error (offline, DNS, etc.)\r\n if ((e as HuskelError).status === undefined) {\r\n if (attempt < MAX_RETRIES - 1) {\r\n log('warn', `${path} network error, retrying (${attempt + 1}/${MAX_RETRIES})...`);\r\n await sleep(RETRY_DELAYS[attempt]);\r\n return this.post(path, body, attempt + 1);\r\n }\r\n log('error', `${path} unreachable after ${MAX_RETRIES} attempts`);\r\n }\r\n throw e;\r\n }\r\n }\r\n\r\n async ingest(product: Product): Promise<IngestResponse> {\r\n log('info', 'ingesting product', product.name);\r\n return this.post('/ingest', { siteId: this.siteId, product });\r\n }\r\n\r\n async ingestBatch(products: Product[]): Promise<IngestResponse> {\r\n log('info', `ingesting batch of ${products.length} products`);\r\n return this.post('/ingest/batch', { siteId: this.siteId, products });\r\n }\r\n\r\n async search(query: string, limit = 10): Promise<SearchResponse> {\r\n log('info', 'search query', query);\r\n return this.post('/search', { query, siteId: this.siteId, limit });\r\n }\r\n}\r\n","import { HuskelConfig, Product, RawProductInput } from './types';\r\nimport { HuskelAPI } from './api';\r\n\r\nfunction getEnvVar(key: string): string | undefined {\r\n if (typeof globalThis !== 'undefined') {\r\n const g = globalThis as any;\r\n if (g.process && g.process.env) {\r\n return g.process.env[key];\r\n }\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction mapRawProduct(input: RawProductInput): Product | null {\r\n const name = input.name || input.title || input.productName || '';\r\n \r\n let price = '';\r\n let priceNumeric: number | undefined = undefined;\r\n\r\n if (input.price !== undefined) {\r\n if (typeof input.price === 'number') {\r\n priceNumeric = input.price;\r\n price = String(input.price);\r\n } else {\r\n price = input.price;\r\n const num = parseFloat(input.price.replace(/[^0-9.]/g, ''));\r\n priceNumeric = isNaN(num) ? undefined : num;\r\n }\r\n }\r\n if (input.priceNumeric !== undefined) {\r\n priceNumeric = input.priceNumeric;\r\n }\r\n\r\n let url = input.url || '';\r\n if (!url && typeof window !== 'undefined') {\r\n url = window.location.href;\r\n }\r\n\r\n let slug = input.slug || input.id || input.productId || '';\r\n if (!slug && url) {\r\n slug = url.split('/').filter(Boolean).pop() || '';\r\n }\r\n if (!slug && name) {\r\n slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');\r\n }\r\n\r\n let images: string[] = [];\r\n if (input.images) {\r\n images = input.images;\r\n } else if (input.image) {\r\n images = [input.image];\r\n } else if (input.thumbnail) {\r\n images = [input.thumbnail];\r\n }\r\n\r\n if (!name) {\r\n console.warn('[Huskel] Validation warning: Product name/title is missing. Skipping:', input);\r\n return null;\r\n }\r\n if (!price) {\r\n console.warn('[Huskel] Validation warning: Product price is missing. Skipping:', input);\r\n return null;\r\n }\r\n if (!url) {\r\n console.warn('[Huskel] Validation warning: Product URL is missing. Skipping:', input);\r\n return null;\r\n }\r\n\r\n return {\r\n name,\r\n price,\r\n url,\r\n brand: input.brand,\r\n description: input.description,\r\n originalPrice: input.originalPrice,\r\n discount: input.discount,\r\n currency: input.currency ?? 'KES',\r\n stock: input.stock,\r\n availability: input.availability,\r\n rating: input.rating,\r\n reviewCount: input.reviewCount,\r\n category: input.category,\r\n subCategory: input.subCategory,\r\n tags: input.tags,\r\n images: images.length > 0 ? images : undefined,\r\n specs: input.specs,\r\n priceNumeric,\r\n slug,\r\n };\r\n}\r\n\r\nexport class HuskelClient {\r\n readonly api: HuskelAPI;\r\n private ingestQueue: Product[] = [];\r\n private ingestTimer: ReturnType<typeof setTimeout> | null = null;\r\n private ingestedUrls = new Set<string>();\r\n private onlineHandler: (() => void) | null = null;\r\n\r\n constructor(config: HuskelConfig) {\r\n const siteId = config.siteId || getEnvVar('NEXT_PUBLIC_HUSKEL_SITE_ID') || '';\r\n const apiUrl = config.apiUrl || getEnvVar('NEXT_PUBLIC_HUSKEL_API_URL') || '';\r\n const apiToken = config.apiToken || getEnvVar('NEXT_PUBLIC_HUSKEL_API_TOKEN') || '';\r\n\r\n // Runtime validation — fail loudly so misconfiguration is never silent\r\n if (!siteId) console.error('[Huskel] Missing siteId. Set it via <HuskelProvider siteId=\"...\"> or NEXT_PUBLIC_HUSKEL_SITE_ID.');\r\n if (!apiUrl) console.error('[Huskel] Missing apiUrl. Set it via <HuskelProvider apiUrl=\"...\"> or NEXT_PUBLIC_HUSKEL_API_URL.');\r\n if (!apiToken) console.error('[Huskel] Missing apiToken. Set it via <HuskelProvider apiToken=\"...\"> or NEXT_PUBLIC_HUSKEL_API_TOKEN.');\r\n\r\n this.api = new HuskelAPI(apiUrl, siteId, apiToken);\r\n instance = this;\r\n\r\n if (typeof window !== 'undefined') {\r\n this.onlineHandler = () => {\r\n console.log('[Huskel] Connectivity restored, flushing queued ingestions.');\r\n this.flushQueue();\r\n };\r\n window.addEventListener('online', this.onlineHandler);\r\n }\r\n }\r\n\r\n destroy() {\r\n if (typeof window !== 'undefined' && this.onlineHandler) {\r\n window.removeEventListener('online', this.onlineHandler);\r\n this.onlineHandler = null;\r\n }\r\n if (this.ingestTimer) {\r\n clearTimeout(this.ingestTimer);\r\n this.ingestTimer = null;\r\n }\r\n if (instance === this) instance = null;\r\n }\r\n\r\n async queueIngest(rawProduct: RawProductInput): Promise<void> {\r\n const product = mapRawProduct(rawProduct);\r\n if (!product) return;\r\n\r\n if (this.ingestedUrls.has(product.url)) {\r\n return;\r\n }\r\n this.ingestedUrls.add(product.url);\r\n\r\n this.ingestQueue.push(product);\r\n this.scheduleFlush();\r\n }\r\n\r\n async queueIngestBatch(rawProducts: RawProductInput[]): Promise<void> {\r\n rawProducts.forEach(p => {\r\n const product = mapRawProduct(p);\r\n if (!product) return;\r\n\r\n if (this.ingestedUrls.has(product.url)) {\r\n return;\r\n }\r\n this.ingestedUrls.add(product.url);\r\n this.ingestQueue.push(product);\r\n });\r\n\r\n if (this.ingestQueue.length > 0) {\r\n this.scheduleFlush();\r\n }\r\n }\r\n\r\n private scheduleFlush() {\r\n if (this.ingestTimer) return;\r\n this.ingestTimer = setTimeout(() => {\r\n this.flushQueue();\r\n }, 300);\r\n }\r\n\r\n private async flushQueue() {\r\n this.ingestTimer = null;\r\n if (this.ingestQueue.length === 0) return;\r\n\r\n if (typeof navigator !== 'undefined' && !navigator.onLine) {\r\n console.warn('[Huskel] Browser offline. Postponing ingestion.');\r\n return;\r\n }\r\n\r\n const batch = [...this.ingestQueue];\r\n this.ingestQueue = [];\r\n\r\n try {\r\n await this.api.ingestBatch(batch);\r\n } catch (e: any) {\r\n if (e.status && e.status >= 400 && e.status < 500) {\r\n console.error('[Huskel] Ingestion discarded due to client error:', e.message);\r\n return;\r\n }\r\n\r\n // Re-queue and schedule another flush so items are not stuck forever\r\n console.warn('[Huskel] Ingestion failed. Re-queuing to retry.', e);\r\n this.ingestQueue = [...batch, ...this.ingestQueue];\r\n this.scheduleFlush();\r\n }\r\n }\r\n}\r\n\r\nlet instance: HuskelClient | null = null;\r\n\r\nexport function initHuskel(config: HuskelConfig): HuskelClient {\r\n instance = new HuskelClient(config);\r\n return instance;\r\n}\r\n\r\nexport function getHuskelClient(): HuskelClient {\r\n if (!instance) {\r\n const siteId = getEnvVar('NEXT_PUBLIC_HUSKEL_SITE_ID');\r\n const apiUrl = getEnvVar('NEXT_PUBLIC_HUSKEL_API_URL');\r\n const apiToken = getEnvVar('NEXT_PUBLIC_HUSKEL_API_TOKEN');\r\n\r\n if (siteId && apiUrl && apiToken) {\r\n instance = new HuskelClient({ siteId, apiUrl, apiToken });\r\n } else {\r\n throw new Error('[Huskel] Call initHuskel() or set NEXT_PUBLIC_HUSKEL_* environment variables before using the client.');\r\n }\r\n }\r\n return instance;\r\n}\r\n","import { useRef } from 'react';\r\nimport { HuskelConfig } from '../types';\r\nimport { HuskelClient, initHuskel } from '../client';\r\n\r\n/**\r\n * @deprecated Use <HuskelProvider> instead to avoid SSR issues.\r\n */\r\nexport function useHuskel(config: HuskelConfig): HuskelClient {\r\n const clientRef = useRef<HuskelClient | null>(null);\r\n\r\n if (!clientRef.current) {\r\n console.warn('[Huskel] useHuskel() is deprecated. Please wrap your application in <HuskelProvider> instead.');\r\n clientRef.current = initHuskel(config);\r\n }\r\n\r\n return clientRef.current;\r\n}\r\n","import { useState, useCallback, useRef } from 'react';\r\nimport { SearchResult } from '../types';\r\nimport { useHuskelContext } from '../components/HuskelProvider';\r\n\r\ninterface UseSearchReturn {\r\n results: SearchResult[];\r\n loading: boolean;\r\n error: string | null;\r\n search: (query: string, limit?: number) => Promise<void>;\r\n clear: () => void;\r\n}\r\n\r\nexport function useSearch(): UseSearchReturn {\r\n const client = useHuskelContext();\r\n const [results, setResults] = useState<SearchResult[]>([]);\r\n const [loading, setLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const abortRef = useRef<AbortController | null>(null);\r\n\r\n const search = useCallback(async (query: string, limit = 10) => {\r\n if (!query.trim()) { setResults([]); return; }\r\n abortRef.current?.abort();\r\n abortRef.current = new AbortController();\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n const res = await client.api.search(query, limit);\r\n setResults(res.results ?? []);\r\n } catch (e: unknown) {\r\n setError((e as Error).message ?? 'Search failed');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [client]);\r\n\r\n const clear = useCallback(() => { setResults([]); setError(null); }, []);\r\n\r\n return { results, loading, error, search, clear };\r\n}\r\n","'use client';\r\n\r\nimport React, { createContext, useContext, useEffect, useRef } from 'react';\r\nimport { HuskelClient, getHuskelClient } from '../client';\r\nimport { HuskelConfig } from '../types';\r\n\r\nexport const HuskelContext = createContext<HuskelClient | null>(null);\r\n\r\ninterface HuskelProviderProps extends HuskelConfig {\r\n children: React.ReactNode;\r\n}\r\n\r\nexport function HuskelProvider({ siteId, apiUrl, apiToken, children }: HuskelProviderProps) {\r\n const clientRef = useRef<HuskelClient | null>(null);\r\n\r\n if (!clientRef.current) {\r\n clientRef.current = new HuskelClient({ siteId, apiUrl, apiToken });\r\n }\r\n\r\n // Clean up the online listener and timers when the provider unmounts\r\n // (prevents leaks during hot module reload and React StrictMode double-mount)\r\n useEffect(() => {\r\n return () => {\r\n clientRef.current?.destroy();\r\n };\r\n }, []);\r\n\r\n return (\r\n <HuskelContext.Provider value={clientRef.current}>\r\n {children}\r\n </HuskelContext.Provider>\r\n );\r\n}\r\n\r\nexport function useHuskelContext(): HuskelClient {\r\n const context = useContext(HuskelContext);\r\n if (!context) {\r\n return getHuskelClient();\r\n }\r\n return context;\r\n}\r\n\r\n","import { useCallback, useState } from 'react';\r\nimport { RawProductInput } from '../types';\r\nimport { useHuskelContext } from '../components/HuskelProvider';\r\n\r\ninterface UseIngestReturn {\r\n ingest: (product: RawProductInput) => Promise<void>;\r\n ingestBatch: (products: RawProductInput[]) => Promise<void>;\r\n loading: boolean;\r\n error: string | null;\r\n}\r\n\r\nexport function useIngest(): UseIngestReturn {\r\n const client = useHuskelContext();\r\n const [loading, setLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const ingest = useCallback(async (product: RawProductInput) => {\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n await client.queueIngest(product);\r\n } catch (e: unknown) {\r\n setError((e as Error).message ?? 'Ingest failed');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [client]);\r\n\r\n const ingestBatch = useCallback(async (products: RawProductInput[]) => {\r\n if (!products.length) return;\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n await client.queueIngestBatch(products);\r\n } catch (e: unknown) {\r\n setError((e as Error).message ?? 'Batch ingest failed');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [client]);\r\n\r\n return { ingest, ingestBatch, loading, error };\r\n}\r\n","import React, { useState, useEffect, useRef } from 'react';\r\nimport { useSearch } from '../hooks/useSearch';\r\nimport { SearchResult } from '../types';\r\n\r\ninterface SearchBarProps {\r\n placeholder?: string;\r\n limit?: number;\r\n debounceMs?: number;\r\n onSelect?: (result: SearchResult) => void;\r\n className?: string;\r\n inputClassName?: string;\r\n dropdownClassName?: string;\r\n renderResult?: (result: SearchResult) => React.ReactNode;\r\n}\r\n\r\nconst S = `\r\n .hsk-wrap{position:relative;width:100%;font-family:inherit}\r\n .hsk-input{width:100%;padding:10px 16px;font-size:15px;border:1.5px solid #e2e2e2;border-radius:8px;outline:none;box-sizing:border-box;background:#fff;transition:border-color .2s}\r\n .hsk-input:focus{border-color:#f47c3c}\r\n .hsk-drop{position:absolute;top:calc(100% + 6px);left:0;right:0;background:#fff;border:1px solid #e2e2e2;border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.1);z-index:9999;max-height:360px;overflow-y:auto}\r\n .hsk-item{display:flex;align-items:center;gap:12px;padding:10px 14px;cursor:pointer;transition:background .15s}\r\n .hsk-item:hover{background:#faf5f1}\r\n .hsk-item img{width:40px;height:40px;object-fit:cover;border-radius:4px}\r\n .hsk-item-name{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\r\n .hsk-item-price{font-size:13px;color:#f47c3c;margin-top:2px}\r\n .hsk-msg{padding:16px;text-align:center;font-size:14px;color:#888}\r\n`;\r\n\r\nexport function SearchBar({\r\n placeholder = 'Search for what you want — how you want',\r\n limit = 10,\r\n debounceMs = 300,\r\n onSelect,\r\n className,\r\n inputClassName,\r\n dropdownClassName,\r\n renderResult,\r\n}: SearchBarProps) {\r\n const [query, setQuery] = useState('');\r\n const [open, setOpen] = useState(false);\r\n const { results, loading, search, clear } = useSearch();\r\n const timer = useRef<ReturnType<typeof setTimeout>>();\r\n const wrap = useRef<HTMLDivElement>(null);\r\n\r\n useEffect(() => {\r\n clearTimeout(timer.current);\r\n if (!query.trim()) { clear(); setOpen(false); return; }\r\n timer.current = setTimeout(() => { search(query, limit); setOpen(true); }, debounceMs);\r\n return () => clearTimeout(timer.current);\r\n }, [query, search, clear, limit, debounceMs]);\r\n\r\n useEffect(() => {\r\n const handler = (e: MouseEvent) => {\r\n if (wrap.current && !wrap.current.contains(e.target as Node)) setOpen(false);\r\n };\r\n document.addEventListener('mousedown', handler);\r\n return () => document.removeEventListener('mousedown', handler);\r\n }, []);\r\n\r\n const handleSelect = (r: SearchResult) => {\r\n setOpen(false);\r\n setQuery(r.product.name);\r\n onSelect?.(r);\r\n };\r\n\r\n return (\r\n <>\r\n <style>{S}</style>\r\n <div className={`hsk-wrap ${className ?? ''}`} ref={wrap}>\r\n <input\r\n className={`hsk-input ${inputClassName ?? ''}`}\r\n type=\"text\"\r\n value={query}\r\n placeholder={placeholder}\r\n onChange={e => setQuery(e.target.value)}\r\n onFocus={() => results.length && setOpen(true)}\r\n />\r\n {open && (\r\n <div className={`hsk-drop ${dropdownClassName ?? ''}`}>\r\n {loading && <div className=\"hsk-msg\">Searching…</div>}\r\n {!loading && results.length === 0 && <div className=\"hsk-msg\">No results for \"{query}\"</div>}\r\n {results.map(r =>\r\n renderResult ? (\r\n <div key={r.id} onClick={() => handleSelect(r)}>{renderResult(r)}</div>\r\n ) : (\r\n <div key={r.id} className=\"hsk-item\" onClick={() => handleSelect(r)}>\r\n {r.product.images?.[0] && <img src={r.product.images[0]} alt={r.product.name} />}\r\n <div>\r\n <div className=\"hsk-item-name\">{r.product.name}</div>\r\n <div className=\"hsk-item-price\">{r.product.currency ?? 'KES'} {r.product.price}</div>\r\n </div>\r\n </div>\r\n )\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n </>\r\n );\r\n}\r\n","import React, { useState } from 'react';\r\nimport { useHuskelContext } from './HuskelProvider';\r\nimport { SearchResult } from '../types';\r\n\r\ninterface SparkleProps {\r\n productName: string;\r\n limit?: number;\r\n onResult?: (results: SearchResult[]) => void;\r\n className?: string;\r\n}\r\n\r\nconst S = `\r\n .hsk-sparkle{display:inline-flex;align-items:center;gap:5px;padding:4px 10px;font-size:12px;font-weight:600;background:#f47c3c;color:#fff;border:none;border-radius:20px;cursor:pointer;transition:opacity .2s,transform .15s}\r\n .hsk-sparkle:hover{opacity:.88;transform:scale(1.04)}\r\n .hsk-sparkle:disabled{opacity:.5;cursor:not-allowed}\r\n`;\r\n\r\nexport function Sparkle({ productName, limit = 5, onResult, className }: SparkleProps) {\r\n const client = useHuskelContext();\r\n const [loading, setLoading] = useState(false);\r\n\r\n const handleClick = async () => {\r\n setLoading(true);\r\n try {\r\n const res = await client.api.search(productName, limit);\r\n onResult?.(res.results);\r\n } catch (e) {\r\n console.error('[Huskel Sparkle]', e);\r\n } finally {\r\n setLoading(false);\r\n }\r\n };\r\n\r\n return (\r\n <>\r\n <style>{S}</style>\r\n <button className={`hsk-sparkle ${className ?? ''}`} onClick={handleClick} disabled={loading}>\r\n ✦ {loading ? 'Finding…' : 'Similar'}\r\n </button>\r\n </>\r\n );\r\n}\r\n"],"mappings":"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","names":["useRef","useRef","useRef","useRef","useCallback","useState","useState","useCallback","useState","useEffect","useRef","jsx","useState","useRef","useEffect","useState","Fragment","jsx","jsxs","S","useState"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@huskel/sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Huskel AI-powered search SDK for SPAs",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"typescript": "^5.0.0"
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
|
-
"build": "tsup
|
|
30
|
-
"dev": "tsup
|
|
29
|
+
"build": "tsup",
|
|
30
|
+
"dev": "tsup --watch"
|
|
31
31
|
}
|
|
32
32
|
}
|