shopping-assistant-headless-sdk
v1.0.0
Published
Headless Shopping Assistant SDK with event-driven TypeScript APIs
Downloads
2
Maintainers
Readme
Shopping Assistant Headless SDK
A modern, event-driven TypeScript SDK for integrating shopping assistant functionality into your applications. Built with inspiration from Stripe, OpenAI, and Gemini SDKs.
Features
- 🚀 Event-driven API - Real-time streaming responses and reactive updates
- 🔧 Headless Architecture - Pure business logic without UI components
- 📦 TypeScript First - Full type safety and excellent developer experience
- 🔄 Session Management - Automatic token refresh and session handling
- 🛒 Complete Shopping API - Cart, products, streaming search, and more
- 🎯 Framework Agnostic - Works with React, Vue, Angular, or vanilla JS
Installation
npm install @shopping-assistant/headless-sdkQuick Start
import { ShoppingAssistant } from '@shopping-assistant/headless-sdk';
// Initialize the assistant
const assistant = new ShoppingAssistant({
apiKey: '<YOUR_API_KEY>',
userId: '<USER_ID>',
environment: 'production', // optional
session: true // auto-manage session
});
// Wait for initialization
assistant.on('ready', () => {
console.log('Shopping Assistant is ready!');
});
// Stream a query
const stream = assistant.stream('Show me latest party wear dresses');
stream.on('data', (chunk) => {
console.log('Received:', chunk);
});
stream.on('complete', () => {
console.log('Stream completed');
});
stream.start();API Reference
Initialization
const assistant = new ShoppingAssistant({
apiKey: string; // Required: Your API key
userId: string; // Required: Unique user identifier
environment?: 'development' | 'production'; // Optional: Environment
session?: boolean; // Optional: Auto-manage session (default: true)
baseUrl?: string; // Optional: Custom API base URL
timeout?: number; // Optional: Request timeout in ms
});Event-Driven Streaming
// Create a stream
const stream = assistant.stream('party wear dresses');
// Listen to events
stream.on('data', (chunk: StreamData) => {
if (chunk.type === 'text_chunk') {
console.log('Text:', chunk.text);
} else if (chunk.type === 'resource') {
console.log('Resource:', chunk.resource);
}
});
stream.on('complete', () => {
console.log('Streaming completed');
});
stream.on('error', (error: Error) => {
console.error('Stream error:', error);
});
// Control streaming
stream.start();
stream.stop();Product APIs
// Get product catalog
const catalog = await assistant.getProductCatalog();
console.log('Products:', catalog.searchedProductList);
// Get product details
const product = await assistant.getProductDetails('product123');
console.log('Product:', product);
// Change product variations
const blueProduct = await assistant.changeColor('product123', 'blue');
const xlProduct = await assistant.changeSize('product123', 'XL');
// Search products
const searchResults = await assistant.searchProducts('summer dresses');
// Get recommendations
const recommended = await assistant.getRecommendedProducts();
const deals = await assistant.getTopDeals();Cart APIs
// Add to cart
await assistant.addToCart('product123', 2, {
color: 'blue',
size: 'M'
});
// Update quantity
await assistant.updateCart('product123', 3);
// Remove from cart
await assistant.removeCart('product123');
// Clear cart
await assistant.clearCart();
// Get cart
const cart = await assistant.getCart();
console.log('Cart items:', cart.items);
console.log('Total:', cart.summary.total);
// Utility methods
const itemCount = await assistant.getCartItemCount();
const total = await assistant.getCartTotal();
const hasItem = await assistant.hasCartItem('product123');Session Management
// Get current session
const session = assistant.getSession();
console.log('Session expires at:', new Date(session.expiresAt));
// Reset session
assistant.resetSession();
// Refresh session
const newSession = await assistant.refreshSession();Event Listeners
The SDK emits various events that you can listen to:
// Global events
assistant.on('ready', () => {
console.log('Assistant is ready');
});
assistant.on('error', (error: Error) => {
console.error('Global error:', error);
});
// Streaming events
assistant.on('streaming', (data: StreamData) => {
console.log('Streaming data:', data);
});
assistant.on('streamCompleted', () => {
console.log('Stream completed');
});
assistant.on('streamError', (error: Error) => {
console.error('Stream error:', error);
});
// Cart events
assistant.on('cartUpdated', (cart: Cart) => {
console.log('Cart updated:', cart);
});
// Product events
assistant.on('productUpdated', (product: ProductDetail) => {
console.log('Product updated:', product);
});
// Session events
assistant.on('sessionExpired', () => {
console.log('Session expired');
});
assistant.on('sessionRefreshed', (session: SessionData) => {
console.log('Session refreshed:', session);
});Advanced Usage
Custom API Client
import { ApiClient } from '@shopping-assistant/headless-sdk';
const apiClient = new ApiClient({
baseUrl: 'https://your-api.com',
timeout: 60000,
defaultHeaders: {
'Custom-Header': 'value'
}
});
// Use with managers directly
import { ProductManager } from '@shopping-assistant/headless-sdk';
const productManager = new ProductManager(apiClient);Error Handling
import {
ShoppingAssistantError,
NetworkError,
SessionError,
ValidationError
} from '@shopping-assistant/headless-sdk';
try {
await assistant.addToCart('invalid-product', -1);
} catch (error) {
if (error instanceof ValidationError) {
console.error('Validation error:', error.message);
} else if (error instanceof NetworkError) {
console.error('Network error:', error.statusCode, error.message);
} else if (error instanceof SessionError) {
console.error('Session error:', error.message);
} else if (error instanceof ShoppingAssistantError) {
console.error('SDK error:', error.code, error.message);
}
}TypeScript Types
The SDK provides comprehensive TypeScript types:
import type {
ShoppingAssistantConfig,
StreamData,
Product,
ProductDetail,
Cart,
CartItem,
SessionData,
ShoppingAssistantEvents
} from '@shopping-assistant/headless-sdk';Framework Integration Examples
React
import { useEffect, useState } from 'react';
import { ShoppingAssistant, StreamData } from '@shopping-assistant/headless-sdk';
function useShoppingAssistant(config) {
const [assistant, setAssistant] = useState<ShoppingAssistant | null>(null);
const [isReady, setIsReady] = useState(false);
useEffect(() => {
const sa = new ShoppingAssistant(config);
sa.on('ready', () => setIsReady(true));
sa.on('error', console.error);
setAssistant(sa);
return () => sa.destroy();
}, []);
return { assistant, isReady };
}
function ChatComponent() {
const { assistant, isReady } = useShoppingAssistant({
apiKey: 'your-key',
userId: 'user-123'
});
const [messages, setMessages] = useState<string[]>([]);
const handleQuery = (query: string) => {
if (!assistant || !isReady) return;
const stream = assistant.stream(query);
stream.on('data', (chunk: StreamData) => {
if (chunk.type === 'text_chunk') {
setMessages(prev => [...prev, chunk.text || '']);
}
});
stream.start();
};
return (
<div>
{messages.map((msg, i) => <p key={i}>{msg}</p>)}
<button onClick={() => handleQuery('Show me dresses')}>
Search Dresses
</button>
</div>
);
}Vue 3
import { ref, onMounted, onUnmounted } from 'vue';
import { ShoppingAssistant } from '@shopping-assistant/headless-sdk';
export function useShoppingAssistant(config) {
const assistant = ref<ShoppingAssistant | null>(null);
const isReady = ref(false);
const cart = ref(null);
onMounted(() => {
const sa = new ShoppingAssistant(config);
sa.on('ready', () => {
isReady.value = true;
});
sa.on('cartUpdated', (updatedCart) => {
cart.value = updatedCart;
});
assistant.value = sa;
});
onUnmounted(() => {
assistant.value?.destroy();
});
return {
assistant: readonly(assistant),
isReady: readonly(isReady),
cart: readonly(cart)
};
}Vanilla JavaScript
import { ShoppingAssistant } from '@shopping-assistant/headless-sdk';
class ShoppingApp {
constructor() {
this.assistant = new ShoppingAssistant({
apiKey: 'your-key',
userId: 'user-123'
});
this.setupEventListeners();
}
setupEventListeners() {
this.assistant.on('ready', () => {
console.log('Assistant ready');
this.loadProducts();
});
this.assistant.on('cartUpdated', (cart) => {
this.updateCartUI(cart);
});
}
async loadProducts() {
try {
const catalog = await this.assistant.getProductCatalog();
this.renderProducts(catalog.searchedProductList);
} catch (error) {
console.error('Failed to load products:', error);
}
}
async addToCart(productId, quantity = 1) {
try {
await this.assistant.addToCart(productId, quantity);
// Cart updated event will fire automatically
} catch (error) {
console.error('Failed to add to cart:', error);
}
}
renderProducts(products) {
// Your UI rendering logic
}
updateCartUI(cart) {
// Update cart display
document.getElementById('cart-count').textContent = cart.summary.itemCount;
document.getElementById('cart-total').textContent = `$${cart.summary.total}`;
}
}
// Initialize app
const app = new ShoppingApp();Environment Setup
Development
const assistant = new ShoppingAssistant({
apiKey: 'dev-api-key',
userId: 'dev-user',
environment: 'development',
baseUrl: 'http://localhost:8080'
});Production
const assistant = new ShoppingAssistant({
apiKey: process.env.SHOPPING_ASSISTANT_API_KEY,
userId: getCurrentUserId(),
environment: 'production',
baseUrl: 'https://api.shopping-assistant.com'
});Best Practices
1. Error Handling
Always implement proper error handling:
assistant.on('error', (error) => {
// Log error for debugging
console.error('Shopping Assistant Error:', error);
// Show user-friendly message
showNotification('Something went wrong. Please try again.');
// Optionally retry or fallback
if (error instanceof NetworkError) {
// Retry logic
}
});2. Session Management
Monitor session state:
assistant.on('sessionExpired', () => {
// Redirect to login or refresh session
window.location.href = '/login';
});
assistant.on('sessionRefreshed', (session) => {
console.log('Session refreshed, expires at:', new Date(session.expiresAt));
});3. Streaming Best Practices
const stream = assistant.stream(query);
let accumulatedText = '';
stream.on('data', (chunk) => {
if (chunk.type === 'text_chunk') {
if (chunk.is_complete) {
// Use the complete text
displayMessage(chunk.text);
accumulatedText = '';
} else {
// Accumulate partial text for smooth updates
accumulatedText += chunk.text;
displayPartialMessage(accumulatedText);
}
}
});
stream.on('error', (error) => {
console.error('Stream error:', error);
stream.stop(); // Clean up
});4. Memory Management
// Clean up when component unmounts
useEffect(() => {
return () => {
assistant.destroy();
};
}, []);API Endpoints
The SDK connects to these backend endpoints:
POST /api/cart/add- Add item to cartPOST /api/cart/update- Update cart itemPOST /api/cart/remove- Remove cart itemPOST /api/cart/clear- Clear cartGET /api/cart- Get cart contentsPOST /api/chat/stream- Stream chat responsesGET /api/chat/clearContext- Clear conversation contextGET /api/get-catalog- Get product catalogGET /api/get-itemDetail- Get product details
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT License - see the LICENSE file for details.
Support
- 📧 Email: [email protected]
- 📚 Documentation: https://docs.shopping-assistant.com
- 🐛 Issues: https://github.com/your-org/shopping-assistant-sdk/issues
