npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

shopping-assistant-headless-sdk

v1.0.0

Published

Headless Shopping Assistant SDK with event-driven TypeScript APIs

Downloads

2

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-sdk

Quick 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 cart
  • POST /api/cart/update - Update cart item
  • POST /api/cart/remove - Remove cart item
  • POST /api/cart/clear - Clear cart
  • GET /api/cart - Get cart contents
  • POST /api/chat/stream - Stream chat responses
  • GET /api/chat/clearContext - Clear conversation context
  • GET /api/get-catalog - Get product catalog
  • GET /api/get-itemDetail - Get product details

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. 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