npm package: @sherpahow/sherpa-sdk
Description: Sherpa JavaScript SDK for in-app help and product tours. Built with TypeScript, Lit web components, and Nano Stores.
Author: Sherpa
Latest version: 0.0.17

# Sherpa JavaScript SDK

A comprehensive JavaScript SDK for in-app help and product tours. Built with TypeScript, Lit web components, and Nano Stores for state management.

## Features

- 🎯 **Context-aware Tours**: Smart tours that adapt to user context and provide personalized recommendations
- 🔍 **Natural Language Search**: AI-powered search with floating interface for tours and knowledge base content
- 🎨 **Context Collection Modal**: Gather user context for personalized tour experiences
- 📚 **Draggable Docss**: In-app knowledge base documents in resizable, draggable windows
- 💡 **Interactive Tooltips**: Both informational and actionable tooltips with form auto-fill capabilities
- 📍 **Beacons**: Non-intrusive visual indicators to guide user attention
- 🎮 **Control Panel**: Tour navigation and progress tracking
- 📊 **Analytics**: Comprehensive event tracking and user behavior analytics
- 🔒 **Security**: CSP compliance, origin validation, and secure iframe sandboxing
- 🚀 **Performance**: Optimized element resolution, caching, and minimal DOM impact
- 📱 **SPA Support**: Navigation detection and tour state management for single-page applications
- 🔗 **Automatic Navigation**: Tours automatically navigate to the correct page using buildUrl configuration
- 🌐 **URL Parameter Support**: Start tours directly via URL parameters (?sherpa=tourId)
- 🧭 **Router Integration**: Seamless integration with React Router, Next.js Router, and custom routers for SPA navigation without page refreshes

## 🚀 Bundle Optimization & Code Splitting

The Sherpa SDK is optimized for minimal initial bundle size using dynamic imports and intelligent component grouping:

### Bundle Sizes

#### Standard Build (Single Bundle)

- **IIFE Format**: ~186 kB (~40 kB gzipped) - Ready for CDN
- **ES Module Format**: ~286 kB (~51 kB gzipped) - For modern bundlers

#### Code-Split Build (Optimized Component Grouping)

- **Main Bundle**: ~20 kB (~4.5 kB gzipped) - Core SDK with dynamic imports
- **Component Chunks** (loaded on-demand):
  - **Search Components**: ~128 kB (~22 kB gzipped) - Search interface and modal
  - **Tour Components**: ~45 kB (~9 kB gzipped) - Tooltip, Beacon, Control Panel
  - **Docs Components**: ~37 kB (~8 kB gzipped) - Knowledge Base document viewer
  - **Modals**: ~6 kB (~2 kB gzipped) - Context collection and other modals
  - **Tour Utilities**: ~46 kB (~9 kB gzipped) - Element resolver and recommendation applier

### Performance Benefits

1. **⚡ 90% Smaller Initial Load**: Only ~20 kB vs ~280 kB for the main bundle
2. **📦 Component-Based Loading**: Load only what users need, when they need it
3. **🎯 Better Caching**: Each component chunk cached separately
4. **🏃 Faster TTI**: Dramatically improved Time to Interactive
5. **🧠 Intelligent Prefetching**: Components load based on user interaction patterns

### Component Loading Strategy

#### Sequential Loading Priority

The SDK implements an intelligent sequential loading strategy:

1. **Search Components** load first when search is accessed - providing immediate search capability
2. **Docs Components** load in the background after search is ready - for smooth Docs viewing
3. **Tour Components** load when tours are started - ensuring seamless tour experiences
4. **Tour Controller** loads lazily only when tours are actually initiated

```mermaid
graph TD
    A[SDK Boot] --> B[Core Bundle Loaded ~21kB]
    B --> C[User Opens Search]
    C --> D[Search Components Load ~131kB]
    D --> E[Search Available Immediately]
    E --> F[Docs Components Load in Background ~38kB]
    F --> G[Docss Ready]

    B --> H[User Starts Tour]
    H --> I[Tour Controller Instantiated]
    I --> J[Tour Components Load ~46kB]
    J --> K[Tour Utilities Load ~47kB]
    K --> L[Tour Ready]

    style B fill:#e1f5fe
    style D fill:#f3e5f5
    style F fill:#fff3e0
    style J fill:#e8f5e8
```

#### Separation Benefits

- **Search Independence**: Search functionality is available immediately without waiting for Docs or tour components
- **Docs On-Demand**: Knowledge base documents load only when users need them, after search is ready
- **Tour Optimization**: All tour-related functionality loads together when tours start
- **Reduced Initial Bundle**: Core SDK remains minimal for fast page loads

### Build Commands

```bash
# Standard build (single bundle)
pnpm build

# Code-split build (multiple chunks)
pnpm build:split

# Build both variants
pnpm build:all
```

### Usage

#### For Modern Applications (Recommended)

Use the code-split ES module build for optimal performance:

```javascript
// The core SDK loads instantly
import { SherpaSDK } from './sherpa-sdk.0.0.1.esm.js';

const sherpa = new SherpaSDK();
await sherpa.boot({ applyCSSReset: true });

// Components load on-demand when tours start
await sherpa.startTour('tour-id', 'context');
```

#### For CDN/Legacy Support

Use the single bundle IIFE build:

```html
<script src="https://cdn.jsdelivr.net/npm/@sherpa/client@0.0.1/dist/sherpa-sdk.0.0.1.min.js"></script>
<script>
  const sherpa = new SherpaSDK();
  // All functionality available immediately
</script>
```

## Dynamic Import Architecture

The SDK uses dynamic imports with intelligent sequential loading to achieve optimal performance:

### Sequential Loading Strategy

The SDK prioritizes components based on user interaction patterns:

1. **Search Components First**: Load immediately when search is accessed, providing instant search capability without dependencies
2. **Docs Components Background**: Load asynchronously after search is ready, ensuring smooth Docs access
3. **Tour Components On-Demand**: Load together when tours start, providing seamless tour experiences
4. **Tour Utilities Lazy**: ElementResolver and RecommendationApplier load dynamically only when tours are initiated

### Component Independence

- **Search Standalone**: Search functionality works independently and loads first for immediate availability
- **Docs After Search**: Knowledge base components load after search is ready, optimizing the user flow
- **Tour Self-Contained**: All tour functionality (tooltip, beacon, control panel) loads together when needed
- **Tour Utilities Dynamic**: Element resolution and recommendation utilities load only when needed within tours
- **Modals Independent**: Context and other modals remain separate for specific use cases

### Loading Behavior

- **Priority-Based Loading**: Most commonly used components (search) load first
- **Background Preloading**: Docs components preload after search to reduce perceived latency
- **Just-in-Time Tour Loading**: Tour functionality only loads when users start tours
- **Dynamic Utility Loading**: ElementResolver and RecommendationApplier load on first tour interaction
- **Caching**: Once loaded, all components are cached for subsequent use
- **Error Handling**: Graceful fallbacks if dynamic loading fails
- **Network Optimization**: Reduces critical path loading while maintaining functionality

## CDN Deployment

The Sherpa SDK is available via jsDelivr CDN for easy integration. jsDelivr automatically serves packages published to npm.

### CDN Filename Options

The SDK provides two filename formats to optimize caching strategies:

#### Versioned Filenames (Recommended for Cache-Busting)

- **Format**: `sherpa-sdk.{version}.esm.min.js`
- **Example**: `sherpa-sdk.0.0.7.esm.min.js`
- **Benefits**: Automatic cache invalidation when versions change
- **Use Case**: Production deployments where you want guaranteed updates

#### Fixed Filenames (Convenience)

- **Format**: `sherpa-sdk.esm.min.js`
- **Benefits**: Simple, consistent URLs
- **Use Case**: Development or when you want to always use the latest version
- **Note**: May be cached by CDN/browsers; use cache purging when needed

### Quick CDN Integration

```html
<!DOCTYPE html>
<html>
  <head>
    <title>My App with Sherpa</title>
  </head>
  <body>
    <!-- Your app content -->

    <!-- Option 1: Versioned (Cache-busting, Recommended) -->
    <script
      type="module"
      src="https://cdn.jsdelivr.net/npm/@sherpahow/sherpa-sdk@0.0.7/dist/sherpa-sdk.0.0.7.esm.min.js"
      crossorigin="anonymous"
    ></script>

    <!-- Option 2: Fixed filename (Latest, may be cached) -->
    <script
      type="module"
      src="https://cdn.jsdelivr.net/npm/@sherpahow/sherpa-sdk@latest/dist/sherpa-sdk.esm.min.js"
      crossorigin="anonymous"
    ></script>

    <script type="module">
      // Import matches the script src above
      import { SherpaSDK } from 'https://cdn.jsdelivr.net/npm/@sherpahow/sherpa-sdk@0.0.7/dist/sherpa-sdk.0.0.7.esm.min.js';

      const sdk = new SherpaSDK();
      await sdk.boot({
        key: 'your-workspace-key',
        user: {
          id: 'user-123',
          name: 'John Doe',
          email: 'john@example.com',
        },
      });
    </script>
  </body>
</html>
```

✅ **That's it!** Sherpa is now ready with optimized loading. Components will load automatically as needed:

- **Main bundle**: ~20 kB (loads instantly)
- **Components load on-demand**: Search (~128 kB), Tour (~45 kB), Docs (~37 kB)

### Available CDN Platforms

- **jsDelivr**: `https://cdn.jsdelivr.net/npm/@sherpa/client@0.0.1/dist/`
- **unpkg**: `https://unpkg.com/@sherpa/client@0.0.1/dist/`
- **cdnjs**: Available after manual submission to cdnjs

### Build Formats & Sizes

**Published Version (Code-Split for Optimal Performance):**

- **Main Bundle**: ~20 kB (~4.5 kB gzipped) - Core SDK with dynamic imports
- **Component Chunks** (loaded on-demand):
  - **Search Components**: ~128 kB (~22 kB gzipped) - Search interface and modal
  - **Tour Components**: ~45 kB (~9 kB gzipped) - Tooltip, Beacon, Control Panel
  - **Docs Components**: ~37 kB (~8 kB gzipped) - Knowledge Base document viewer
  - **Modals**: ~6 kB (~2 kB gzipped) - Context collection and other modals
  - **Tour Utilities**: ~46 kB (~9 kB gzipped) - Element resolver and recommendation applier

**Alternative Builds:**

- **Single Bundle**: Available as `sherpa-sdk.0.0.1.min.js` (legacy/compatibility)

### Performance Benefits of Code Splitting

1. **⚡ 90% Smaller Initial Load**: Only ~20 kB vs ~280 kB for the main bundle
2. **📦 Component-Based Loading**: Load only what users need, when they need it
3. **🎯 Better Caching**: Each component chunk cached separately
4. **🏃 Faster TTI**: Dramatically improved Time to Interactive
5. **🧠 Intelligent Prefetching**: Components load based on user interaction patterns

### Integration Examples

#### ES Modules with Code Splitting (Recommended)

```html
<!-- Modern approach with optimal performance -->
<script type="module">
  import { SherpaSDK } from 'https://cdn.jsdelivr.net/npm/@sherpa/client@0.0.1/dist/sherpa-sdk.0.0.1.esm.js';

  const sdk = new SherpaSDK();
  await sdk.boot({
    key: 'your-workspace-key',
    user: {
      id: 'user-123',
      name: 'John Doe',
      email: 'john@example.com',
    },
  });
</script>
```

#### For Legacy Browsers (Single Bundle)

```html
<!-- For browsers that don't support ES modules -->
<script>
  (function () {
    const script = document.createElement('script');
    script.src = 'https://cdn.jsdelivr.net/npm/@sherpa/client@0.0.1/dist/sherpa-sdk.0.0.1.min.js';
    script.onload = function () {
      window.Sherpa('boot', {
        key: 'your-workspace-key',
        user: {
          id: 'user-123',
          name: 'John Doe',
          email: 'john@example.com',
        },
      });
    };
    document.head.appendChild(script);
  })();
</script>
```

#### Advanced Setup with Preloading

```html
<!-- Preload for better performance -->
<link rel="dns-prefetch" href="//cdn.jsdelivr.net" />
<link
  rel="modulepreload"
  href="https://cdn.jsdelivr.net/npm/@sherpa/client@0.0.1/dist/sherpa-sdk.0.0.1.esm.js"
/>

<!-- Load SDK -->
<script type="module">
  import { SherpaSDK } from 'https://cdn.jsdelivr.net/npm/@sherpa/client@0.0.1/dist/sherpa-sdk.0.0.1.esm.js';

  const sdk = new SherpaSDK();
  await sdk.boot({
    key: 'your-workspace-key',
    user: {
      id: 'user-123',
      name: 'John Doe',
      email: 'john@example.com',
    },
    debug: true,
  });
</script>
```

## Environment Configuration

### Backend API Configuration

For production deployments, you'll need to configure the backend API URL where your Sherpa backend is hosted. The SDK supports environment variables for this configuration.

#### Environment Variables

Create a `.env` file in your project root (copy from `env.example`):

```bash
# Backend API Configuration
VITE_BACKEND_URL=https://api.sherpa.example.com/api

# Development Settings
NODE_ENV=production
```

#### Vite Integration

For Vite-based projects, use the `VITE_` prefix:

```bash
# .env
VITE_BACKEND_URL=https://api.sherpa.example.com/api
```

The SDK will automatically detect and use this configuration.

#### Manual Configuration

You can also configure the backend URL programmatically:

```javascript
import { configureAPIClient } from '@sherpahow/sherpa-sdk';

// Configure for production
configureAPIClient({
  backendUrl: 'https://api.sherpa.example.com/api',
  serviceKey: 'your-service-key',
});
```

#### Environment Detection

The SDK automatically determines which API client to use:

- **Development** (`NODE_ENV=development`): Uses mock API client with sample data
- **Production** (`NODE_ENV=production`): Uses real API client with configured backend URL

#### API Client Options

```javascript
import { createAPIClient } from '@sherpahow/sherpa-sdk';

// Force production client with custom URL
const prodClient = createAPIClient({
  backendUrl: 'https://api.sherpa.example.com/api',
});
```

### Development vs Production

- **Development**: Mock client provides sample tours and data for development
- **Production**: Real client connects to your Sherpa backend for live data

## Search Functionality

### Overview

The Sherpa SDK includes a powerful search system that allows users to discover tours and knowledge base content using natural language queries. The search interface consists of:

1. **Floating Search Bar**: A persistent, unobtrusive search button that expands into a full search interface
2. **Search Modal**: A comprehensive search interface with recommendations and results
3. **Context Modal**: A personalization interface for collecting tour context before starting
4. **Docs Viewer**: Draggable, resizable windows for viewing knowledge base content

### Search Flow

```mermaid
graph TD
    A[Floating Search Bar] --> B[Click or Cmd+K]
    B --> C[Search Modal Opens]
    C --> D[Show Recommendations]
    C --> E[User Searches]
    E --> F[Display Results]
    F --> G[Tour Selected]
    F --> H[Docs Selected]
    G --> I[Context Modal Opens]
    I --> J[Basic Tour]
    I --> K[Custom Tour with Context]
    H --> L[Open Draggable Docs]
    L --> M[Multiple Documents Supported]
```

### Keyboard Shortcuts

- **`Cmd/Ctrl + K`**: Open search modal
- **`Esc`**: Close current modal or Docs
- **`Ctrl + Enter`**: Start custom tour with context (in context modal)

### Search API

#### Automatic Search Initialization

The search interface is available immediately after SDK initialization but is hidden by default to prevent blocking user interactions:

```javascript
window.Sherpa('boot', {
  key: 'your-workspace-key',
  // ... other options
});
// Search interface is available but hidden - call showSearch() to display it
```

#### Manual Search Control

```javascript
// Show search interface
window.Sherpa('showSearch');

// Hide search interface
window.Sherpa('hideSearch');
```

#### Search Events

Listen for search-related events:

```javascript
// Search shown
window.Sherpa('onShowSearch', () => {
  console.log('Search interface opened');
});

// Search hidden
window.Sherpa('onHideSearch', () => {
  console.log('Search interface closed');
});
```

## Knowledge Base Documents

### Overview

The SDK provides a powerful system for displaying knowledge base documents in draggable, resizable windows within your application. Documents can contain HTML content, external URLs, or custom content.

### Key Features

- **Draggable Interface**: Click and drag documents by their header
- **Resizable Windows**: Resize documents using the handle in the bottom-right corner
- **Window Management**: Smart positioning with cascade layout for multiple documents
- **Minimize/Restore**: Collapse documents to header-only view
- **Z-index Management**: Automatic focus management when clicking on documents
- **Loading States**: Visual feedback during document loading
- **Error Handling**: Graceful error states for failed loads
- **Iframe Sandboxing**: Secure iframe sandboxing for external content

### Docs API

#### Opening Documents

```javascript
// Open a document with HTML content
window.Sherpa('openDocs', {
  id: 'user-guide',
  title: 'User Guide',
  content: '<html><body><h1>User Guide</h1><p>Content here...</p></body></html>',
});

// Open a document with external URL
window.Sherpa('openDocs', {
  id: 'api-docs',
  title: 'API Documentation',
  url: 'https://api.example.com/docs',
});

// Open with custom positioning and sizing
window.Sherpa(
  'openDocs',
  {
    id: 'help-center',
    title: 'Help Center',
  },
  {
    position: { x: 200, y: 150 },
    size: { width: 800, height: 600 },
  },
);
```

#### Programmatic Control

```javascript
// Close a specific document
window.Sherpa('closeDocs', 'document-id');

// Close all open documents
window.Sherpa('closeAllDocs');

// Check if any documents are open
const hasOpenDocs = sdk.hasOpenDocs();
```

#### Document Object Structure

```typescript
interface Docs {
  id: string; // Unique identifier
  title: string; // Display title in header
  url?: string; // External URL to load
  content?: string; // HTML content to display
}
```

### Integration with Search

Docss automatically integrate with the search system:

```javascript
// Listen for Docs requests from search
document.addEventListener('docs-open', event => {
  const { docsId, title } = event.detail;

  // Fetch document content from your API
  fetch(`/api/docs/${docsId}`)
    .then(response => response.json())
    .then(doc => {
      window.Sherpa('openDocs', {
        id: docsId,
        title: title,
        content: doc.html_content,
      });
    });
});
```

### Customization

#### Styling and Theming

The Docs components use CSS custom properties for theming:

```css
:root {
  --sherpa-docs-surface: rgba(31, 41, 55, 0.98);
  --sherpa-docs-border: rgba(255, 255, 255, 0.2);
  --sherpa-docs-text: #ffffff;
  --sherpa-docs-text-muted: #d1d5db;
  --sherpa-docs-primary: #3b82f6;
  --sherpa-docs-danger: #ef4444;
  --sherpa-docs-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4);
}
```

#### Window Behavior

```javascript
// Docs management is now integrated into UIManager
// Access through the main SDK interface

// Get list of open documents
const hasOpenDocs = window.Sherpa('hasOpenDocs');

// Close specific document
window.Sherpa('closeDocs', 'document-id');

// Close all documents
window.Sherpa('closeAllDocs');

// Documents automatically handle focus management and z-index ordering
// when clicked or interacted with
```

### Accessibility

The Docs system includes comprehensive accessibility features:

- **Keyboard Navigation**: Full keyboard support for window controls
- **Focus Management**: Proper focus handling when opening/closing documents
- **Screen Reader Support**: ARIA labels and semantic markup
- **High Contrast**: Sufficient color contrast ratios
- **Reduced Motion**: Respects `prefers-reduced-motion` settings

### Security

Docss are displayed in sandboxed iframes with restricted permissions:

```html
<iframe sandbox="allow-same-origin allow-scripts allow-forms"></iframe>
```

This provides security while allowing necessary functionality for document interaction.

#### CSP and Cross-Origin Handling

The Docs system intelligently handles Content Security Policy (CSP) restrictions and cross-origin issues:

1. **Direct Loading**: First attempts to load external URLs directly in the iframe
2. **CSP Detection**: Automatically detects when direct loading is blocked by CSP or cross-origin restrictions
3. **Proxy Fallback**: Falls back to a proxy service (AllOrigins) when direct loading fails
4. **User Notification**: Shows a subtle notification when proxy mode is active

```javascript
// The system automatically handles CSP fallback:
window.Sherpa('openDocs', {
  id: 'external-docs',
  title: 'External Documentation',
  url: 'https://external-site.com/docs', // Will try direct first, then proxy if blocked
});
```

**Security Features:**

- Automatic CSP compliance detection
- Secure iframe sandboxing with minimal required permissions
- Proxy service only used when necessary (not by default)
- Timeout protection against slow-loading content
- Memory leak prevention with automatic blob URL cleanup

### Example Implementation

```html
<!DOCTYPE html>
<html>
  <head>
    <title>My App with Sherpa Docss</title>
  </head>
  <body>
    <div id="app">
      <!-- Your application content -->
      <button onclick="openHelpDoc()">Open Help Document</button>
    </div>

    <script>
      // Initialize SDK
      window.Sherpa('boot', {
        key: 'your-workspace-key',
        user: { id: 'user-123' },
      });

      function openHelpDoc() {
        window.Sherpa('openDocs', {
          id: 'help-main',
          title: 'Getting Started Guide',
          content: `
            <html>
              <head><title>Help</title></head>
              <body>
                <h1>Getting Started</h1>
                <p>Welcome to our application!</p>
                <p>Here's how to get started...</p>
              </body>
            </html>
          `,
        });
      }

      // Handle multiple document types
      function openMultipleHelp() {
        const docs = [
          { id: 'faq', title: 'FAQ', url: '/help/faq.html' },
          { id: 'guide', title: 'User Guide', url: '/help/guide.html' },
          { id: 'api', title: 'API Docs', url: 'https://api.example.com/docs' },
        ];

        docs.forEach((doc, index) => {
          setTimeout(() => {
            window.Sherpa('openDocs', doc);
          }, index * 200); // Stagger opening for better UX
        });
      }
    </script>
  </body>
</html>
```

### Demo

A complete demo showcasing all Docs features is available at `src/dev/search-demo.html`, including:

- Sample Docss with different content types
- Drag and resize interactions
- Multiple document management
- Integration with search functionality

### Customization

#### Search Recommendations

The search interface automatically shows personalized recommendations based on:

- Current page URL
- User information
- Previous tour history
- Available content

#### Tour Context Collection

When users select a tour from search results, they can provide additional context:

```javascript
// Example of tour context that users might provide:
{
  role: "신입 직원",
  department: "인사팀",
  situation: "연말정산 처리 시 자주 실수하는 부분을 중점적으로 알고 싶음",
  requirements: "대량 처리 시 주의사항도 함께 설명해주세요"
}
```

#### Knowledge Base Integration

Docss can be opened from search results. The SDK dispatches events that your application can handle:

```javascript
// Listen for Docs requests
document.addEventListener('docs-open', event => {
  const { docsId, title } = event.detail;
  // Handle Docs opening (e.g., create draggable iframe)
  openDocs(docsId, title);
});
```

#### Styling and Theming

The search components use CSS custom properties for theming:

```css
:root {
  --sherpa-primary: #3b82f6;
  --sherpa-primary-hover: #2563eb;
  --sherpa-success: #22c55e;
  --sherpa-surface: rgba(31, 41, 55, 0.9);
  --sherpa-text: #ffffff;
  --sherpa-text-muted: #d1d5db;
  --sherpa-border: rgba(255, 255, 255, 0.2);
  --sherpa-backdrop: rgba(0, 0, 0, 0.2);
  --sherpa-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4);
}
```

#### Accessibility

The search interface includes comprehensive accessibility features:

- **Keyboard Navigation**: Full keyboard support with logical tab order
- **Screen Reader Support**: Proper ARIA labels and announcements
- **Focus Management**: Automatic focus handling and restoration
- **Reduced Motion**: Respects `prefers-reduced-motion` settings
- **High Contrast**: Sufficient color contrast ratios

#### Example Implementation

```html
<!DOCTYPE html>
<html>
  <head>
    <title>My App with Sherpa Search</title>
  </head>
  <body>
    <div id="app">
      <!-- Your application content -->
    </div>

    <!-- Sherpa SDK Loader -->
    <script>
      // Sherpa loader script (see installation section)
    </script>

    <script>
      // Initialize SDK with search
      window.Sherpa('boot', {
        key: 'your-workspace-key',
        user: {
          id: 'user-123',
          name: 'John Doe',
          email: 'john@example.com',
        },
        debug: true,
      });

      // Optional: Listen for search events
      window.Sherpa('onShowSearch', () => {
        console.log('User opened search');
        // Track search usage
        analytics.track('search_opened');
      });

      // Optional: Handle Docs requests
      document.addEventListener('docs-open', event => {
        const { docsId, title } = event.detail;

        // Create draggable iframe or redirect to Docs
        window.open(`/docs/${docsId}`, '_blank');
      });
    </script>
  </body>
</html>
```

#### Demo

A complete demo is available at `src/dev/search-demo.html` which showcases:

- Natural language search queries
- Tour personalization flow
- Knowledge base integration
- Keyboard shortcuts
- Responsive design

## Installation

### Quick Start with jsDelivr CDN

The fastest way to get started is using our jsDelivr CDN with optimized code splitting:

```html
<!DOCTYPE html>
<html>
  <head>
    <title>My App with Sherpa</title>
  </head>
  <body>
    <!-- Your app content -->

    <!-- Sherpa SDK (Code-Split Version) -->
    <script
      type="module"
      src="https://cdn.jsdelivr.net/npm/@sherpa/client@0.0.1/dist/sherpa-sdk.0.0.1.esm.js"
      integrity="sha384-ugBM3nlFVMI/bXFC9mJXN/SGxQLlxqhv5S4qKeoqtEotKxYqi7jleYjHt91+EBLH"
      crossorigin="anonymous"
    ></script>
    <script type="module">
      import { SherpaSDK } from 'https://cdn.jsdelivr.net/npm/@sherpa/client@0.0.1/dist/sherpa-sdk.0.0.1.esm.js';

      const sdk = new SherpaSDK();
      await sdk.boot({
        key: 'your-workspace-key',
        user: {
          id: 'user-123',
          name: 'John Doe',
          email: 'john@example.com',
        },
      });
    </script>
  </body>
</html>
```

✅ **That's it!** Sherpa is now ready with optimized loading. Components will load automatically as needed:

- **Main bundle**: ~20 kB (loads instantly)
- **Components load on-demand**: Search (~128 kB), Tour (~45 kB), Docs (~37 kB)

### Script Tag (Recommended)

Add the Sherpa SDK to your website using the loader script:

```html
<script>
  (function () {
    var w = window;
    if (w.Sherpa) {
      return w.console.error('Sherpa script included twice.');
    }
    var ch = function () {
      ch.c?.(arguments);
    };
    ch.q = [];
    ch.c = function (args) {
      ch.q?.push(args);
    };
    ch.version = '1.0.0';
    w.Sherpa = ch;

    function l() {
      if (w.SherpaInitialized) {
        return;
      }
      w.SherpaInitialized = true;
      var s = document.createElement('script');
      s.type = 'text/javascript';
      s.async = true;
      s.crossOrigin = 'anonymous';
      s.integrity = 'sha384-[HASH]';
      s.src = 'https://cdn.sherpa.how/client.js';
      s.onerror = function () {
        console.error('Failed to load Sherpa SDK. Check CSP settings.');
      };
      var x = document.getElementsByTagName('script')[0];
      if (x && x.parentNode) {
        x.parentNode.insertBefore(s, x);
      } else {
        document.head.appendChild(s);
      }
    }

    if (document.readyState === 'complete') {
      l();
    } else {
      w.addEventListener('DOMContentLoaded', l);
      w.addEventListener('load', l);
    }
  })();
</script>
```

### NPM Package

```bash
npm install @sherpa/client
```

```javascript
import SherpaSDK from '@sherpa/client';

const sdk = new SherpaSDK();
await sdk.boot({
  key: 'your-workspace-key',
  user: {
    id: 'user-123',
    name: 'John Doe',
    email: 'john@example.com',
  },
});
```

## Quick Start

### 1. Initialize the SDK

```javascript
// Using the global Sherpa function (script tag method)
window.Sherpa('boot', {
  key: 'your-workspace-key',
  user: {
    id: 'user-123',
    name: 'John Doe',
    email: 'john@example.com',
  },
  locale: 'ko',
  debug: true,
});
```

### 2. Start a Tour

```javascript
window.Sherpa('startTour', 'tour-id', 'User wants to learn how to use the dashboard');
```

### 3. Track Events

```javascript
window.Sherpa('track', 'button_clicked', {
  button_id: 'save-profile',
  section: 'user-settings',
});
```

### 4. Open Docss

```javascript
window.Sherpa('openDocs', {
  id: 'user-guide',
  title: 'User Guide',
  content: '<h1>Getting Started</h1><p>Welcome to our platform!</p>',
});
```

## API Reference

### Core Methods

#### `boot(options, callback?)`

Initialize the SDK with configuration options.

```javascript
window.Sherpa(
  'boot',
  {
    key: 'workspace-key', // Required: Your workspace key
    user: {
      // Optional: User information
      id: 'user-123',
      name: 'John Doe',
      email: 'john@example.com',
    },
    locale: 'ko', // Optional: Locale setting
    debug: true, // Optional: Enable debug logging
  },
  error => {
    if (error) {
      console.error('Boot failed:', error);
    } else {
      console.log('SDK initialized successfully');
    }
  },
);
```

#### `startTour(tourId, context, metadata?)`

Start a tour with personalized context. The SDK automatically handles navigation if the current page doesn't match the tour's `buildUrl`.

```javascript
window.Sherpa('startTour', 'onboarding-tour', 'New user needs help setting up their profile', {
  source: 'welcome-modal',
  user_type: 'premium',
});
```

**Automatic Navigation:**

- If the current URL doesn't match the tour's `buildUrl`, the SDK will automatically navigate to the correct page
- Tour parameters are preserved across navigation using `sessionStorage`
- The tour starts automatically after the page loads

**URL Parameter Support:**
Tours can also be started directly via URL parameters:

```html
<!-- Start tour via URL parameter -->
https://yourapp.com/dashboard?sherpa=onboarding-tour

<!-- Start tour with custom context -->
https://yourapp.com/dashboard?sherpa=onboarding-tour:custom-context
```

#### `endTour()`

End the currently active tour.

```javascript
window.Sherpa('endTour');
```

#### `showSearch()` / `hideSearch()`

Control the floating search interface.

```javascript
window.Sherpa('showSearch');
window.Sherpa('hideSearch');
```

#### Docs Methods

Control knowledge base documents programmatically.

```javascript
// Open a Docs
window.Sherpa(
  'openDocs',
  {
    id: 'help-guide',
    title: 'Help Guide',
    content: '<html>...</html>', // or url: 'https://...'
  },
  {
    position: { x: 100, y: 100 }, // Optional positioning
    size: { width: 600, height: 500 }, // Optional sizing
  },
);

// Close specific document
window.Sherpa('closeDocs', 'document-id');

// Close all documents
window.Sherpa('closeAllDocs');
```

#### `track(eventName, properties?)`

Track custom analytics events.

```javascript
window.Sherpa('track', 'feature_used', {
  feature: 'export-data',
  format: 'csv',
  timestamp: Date.now(),
});
```

## Integration Requirements for Client Applications

### Router Integration for SPA Navigation

For Single Page Applications (SPAs), you can integrate Sherpa SDK with your router to enable seamless navigation without full page refreshes.

#### Automatic Router Detection (Recommended)

The SDK automatically detects and integrates with most popular routers without any configuration:

```typescript
// No setup needed - SDK auto-detects router
const tourController = TourController.getInstance();
await tourController.startTour('tour-id', 'context');
// Automatically uses SPA navigation if router is detected
```

For manual control, use the Universal Router Adapter:

```typescript
import { UniversalRouterAdapter, TourController } from '@sherpa/client';

const routerAdapter = new UniversalRouterAdapter();
const tourController = TourController.getInstance();
tourController.setRouterAdapter(routerAdapter);
```

#### React Router Integration (Manual)

```tsx
import React, { useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { TourController, ReactRouterAdapter } from '@sherpa/client';

function App() {
  const navigate = useNavigate();
  const location = useLocation();

  useEffect(() => {
    const routerAdapter = new ReactRouterAdapter(navigate, location);
    const tourController = TourController.getInstance();
    tourController.setRouterAdapter(routerAdapter);

    return () => {
      tourController.setRouterAdapter(null);
    };
  }, [navigate, location]);

  return <YourAppContent />;
}
```

#### Next.js Integration

```tsx
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { TourController, NextRouterAdapter } from '@sherpa/client';

export function SherpaProvider({ children }) {
  const router = useRouter();

  useEffect(() => {
    const routerAdapter = new NextRouterAdapter(router);
    const tourController = TourController.getInstance();
    tourController.setRouterAdapter(routerAdapter);

    return () => {
      tourController.setRouterAdapter(null);
    };
  }, [router]);

  return <>{children}</>;
}
```

### Automatic Tour Navigation

The Sherpa SDK automatically handles page navigation when a tour's `buildUrl` doesn't match the current URL. This feature works out-of-the-box with no additional client-side code required.

#### How It Works

1. **Tour Start**: When `startTour()` is called, the SDK compares the current URL with the tour's `buildUrl`
2. **Smart Navigation**: The SDK uses multiple navigation strategies with automatic fallbacks:
   - **SPA Navigation**: Uses router adapters for seamless navigation without page reloads
   - **Content Verification**: Verifies that actual HTML content has loaded, not just URL changes
   - **Automatic Fallback**: Falls back to full page navigation when SPA navigation fails
3. **Parameter Preservation**: Tour parameters are stored in `sessionStorage` during navigation
4. **Auto-Resume**: After page load, the SDK automatically detects and starts the pending tour

#### Client Application Requirements

**✅ No Additional Code Required**

The navigation feature works automatically with:

- **Single Page Applications (SPAs)**: React, Angular, Next.js, SvelteKit
- **Multi-Page Applications (MPAs)**: Traditional server-rendered applications
- **Hybrid Applications**: Mixed SPA/MPA architectures
- **Static Sites**: JAMstack and static site generators

**✅ Supported URL Formats**

The SDK handles both absolute and relative URLs in `buildUrl`:

```javascript
// Absolute URLs
"buildUrl": "https://yourapp.com/dashboard"

// Relative URLs
"buildUrl": "/dashboard"
"buildUrl": "/users/profile?tab=settings"
```

**✅ URL Parameter Integration**

Tours can be started directly via URL parameters without any additional setup:

```html
<!-- These work automatically -->
https://yourapp.com?sherpa=tour-id https://yourapp.com/page?sherpa=tour-id:context
```

#### Enhanced Navigation Features

**🔄 Multiple Navigation Strategies**

The SDK automatically tries multiple navigation approaches in order:

1. **Router Adapter Navigation**: Uses configured SPA router (React Router, etc.)
2. **Auto-Detected SPA Navigation**: Automatically detects and uses framework routers
3. **History API Navigation**: Uses browser History API for SPA-like navigation
4. **Full Page Navigation**: Traditional page reload as final fallback

**🔍 Content Verification**

The SDK doesn't just check URL changes - it verifies that actual content has loaded:

- **Content Hash Verification**: Compares page content before and after navigation
- **Title Change Detection**: Monitors document title changes
- **Framework-Specific Indicators**: Checks for framework-specific DOM elements
- **Loading State Detection**: Waits for loading indicators to disappear
- **Lazy Loading Support**: Handles content that loads asynchronously

**⚡ Intelligent Fallbacks**

When SPA navigation fails or content doesn't load properly:

- **Automatic Detection**: Detects when URL changes but content doesn't load
- **Graceful Fallback**: Automatically switches to full page navigation
- **Error Recovery**: Continues tour execution after successful fallback navigation
- **Logging**: Provides detailed console logs for debugging navigation issues

#### Advanced Configuration (Optional)

For advanced use cases, you can customize the navigation behavior:

```javascript
// Custom navigation handling (optional)
window.addEventListener('beforeunload', event => {
  // Custom logic before navigation
  if (sherpaNavigationInProgress) {
    // Allow navigation for Sherpa tours
    return;
  }
});
```

#### Security Considerations

- **Same-Origin Policy**: Navigation only works within the same origin for security
- **HTTPS**: Secure contexts are maintained during navigation
- **Session Storage**: Tour parameters are stored securely and expire after 5 minutes

#### Troubleshooting

**Tour doesn't start after navigation:**

- Check that the SDK is properly initialized on the target page
- Verify that `sessionStorage` is available and not blocked
- Ensure the target page loads the Sherpa SDK
- Check browser console for navigation verification logs

**Navigation doesn't occur:**

- Verify the `buildUrl` format in your tour configuration
- Check browser console for navigation errors and fallback messages
- Ensure the target URL is accessible and returns valid HTML
- For SPAs, verify that the router is properly configured

**SPA navigation fails:**

- Check console logs for "Navigation verification failed" messages
- Verify that your SPA router is properly handling the navigation
- Ensure content actually changes after navigation (not just URL)
- The SDK will automatically fall back to full page navigation

**Content doesn't load after navigation:**

- Check for loading indicators that might be preventing content detection
- Verify that the target page has meaningful content changes
- For lazy-loaded content, ensure it loads within the verification timeout
- Check for JavaScript errors that might prevent content rendering

## License

MIT License - see LICENSE file for details.

## Development

### Hot Reloading & CDN Server

The client SDK includes a development server that provides hot reloading and CDN-like serving of the dist folder:

#### Development Server Features

- **Hot Reloading**: Automatically rebuilds when source files change
- **CDN-like Serving**: Serves dist folder with proper CORS headers
- **Cache Control**: No-cache headers for development
- **File Listing**: JSON API to list available files

#### Starting the Development Server

```bash
# Start dev server with hot reloading and CDN serving
pnpm dev

# This runs:
# - Vite build in watch mode
# - Express server on port 4100 serving dist folder
```

#### Accessing the Development CDN

- **CDN Server**: `http://localhost:4100/`
- **SDK Files**: `http://localhost:4100/dist/[filename]`
- **List Files API**: `http://localhost:4100/` (returns JSON with file list)

#### Example Usage

```html
<!-- Load SDK from local CDN server -->
<script type="module">
  import { SherpaSDK } from 'http://localhost:4100/dist/sherpa-sdk.0.0.14.esm.min.js';
  
  const sdk = new SherpaSDK();
  await sdk.boot({
    key: 'your-workspace-key',
    user: {
      id: 'user-123',
      name: 'John Doe',
      email: 'john@example.com',
    },
  });
</script>
```

#### Development Scripts

```bash
# Main development command (hot reload + CDN server)
pnpm dev

# Alternative: Old Vite dev server (port 4000)
pnpm dev:old

# Watch and build only
pnpm build:watch

# CDN server only
pnpm serve:cdn
```

The development server watches for changes in the dist folder and logs updates to the console. Files are served with CORS headers enabled, making it perfect for testing SDK integration across different domains during development.

### Build Configuration

The SDK uses aggressive minification via terser for optimal bundle sizes. To prevent method mangling issues across chunks, critical SDK methods are protected in the reserved list:

#### Protected Methods

The following methods are protected from mangling in `vite.config.ts`:

```javascript
const reservedList = [
  // SDK Core Methods
  'getInstance', // Singleton pattern preservation
  'boot', // SDK initialization
  'shutdown', // SDK cleanup
  'startTour', // Tour initiation
  'endTour', // Tour termination
  'nextStep', // Tour navigation
  'previousStep', // Tour navigation
  'goToStep', // Tour navigation
  'showSearch', // UI control
  'hideSearch', // UI control
  'track', // Analytics
  'updateUser', // User management
  'openDocs', // Docs management
  'closeDocs', // Docs management
  'closeAllDocs', // Docs management

  // Framework Methods (already included)
  'addEventListener',
  'querySelector',
  'render',
  'update',
  'connectedCallback',
  'disconnectedCallback',
  'get',
  'set',
  'subscribe',
  'atom',
  'computed',
  'map',
  'action',
  'listen',
];
```

#### Adding New Protected Methods

When adding new public methods that are called across chunks, add them to the `reservedList` in `vite.config.ts` to prevent terser from mangling them:

```javascript
// ❌ Without protection - will be mangled to single letters
class MyClass {
  async newPublicMethod() {
    /* ... */
  }
}

// ✅ With protection - method name preserved
const reservedList = [
  // ... existing methods
  'newPublicMethod', // Add here
];
```

### Common Issues

#### Method Not Found Errors

If you see errors like `n.Y is not a function` or `this.O.o is not a function`, it means a method is being mangled across chunks. Fix by:

1. Identify the original method name from the source code
2. Add it to the `reservedList` in `vite.config.ts`
3. Rebuild with `pnpm build`

#### Cross-Chunk Method Calls

When methods are called across different chunks (main bundle → component chunks), they must be in the reserved list to maintain consistent naming.

## Support

- Documentation: https://sherpa.how/docs
- Issues: https://github.com/sherpa/sherpa-js/issues
- Email: support@sherpa.how

## Publishing & CDN

### For Maintainers

#### Automated Version Bump & Publish (Recommended)

Use the automated bump-and-publish script for streamlined releases:

```bash
# Patch release (1.0.0 → 1.0.1) to production
pnpm run bump-publish

# Minor release (1.0.0 → 1.1.0) to production
pnpm run bump-publish minor

# Major release (1.0.0 → 2.0.0) to production
pnpm run bump-publish major

# Beta/dev releases (adds -dev suffix)
pnpm run bump-publish patch dev
pnpm run bump-publish minor beta

# Dry run to see what would happen
pnpm run bump-publish major --dry-run
```

**What the script does:**

1. ✅ Validates git status and shows current branch
2. 📝 Bumps version in package.json (semver compliant)
3. 🏗️ Builds the project (production or beta build)
4. 🔐 Generates CDN integrity hashes
5. 📦 Commits version bump to git
6. 🚀 Publishes to npm with appropriate tag (`latest` or `beta`)
7. 🏷️ Creates and pushes git tag (production only)
8. 📊 Shows installation and CDN usage instructions

**Script Options:**

- `--bump, -b`: Version bump type (`patch`, `minor`, `major`)
- `--target, -t`: Publish target (`production`, `dev`, `beta`)
- `--dry-run, -d`: Show what would be done without executing
- `--help, -h`: Show help message

#### Manual Publishing (Legacy)

To publish manually:

```bash
# 1. Update version in package.json
# 2. Test everything
pnpm test && pnpm type-check

# 3. Build and prepare for publishing
pnpm run prepublishOnly

# 4. Publish to npm (requires permissions)
pnpm run publish:npm

# 5. Verify on jsDelivr (wait 1-5 minutes)
# https://cdn.jsdelivr.net/npm/@sherpa/client@VERSION/
```

### For Users

**CDN Integration (Recommended):**

```html
<script type="module">
  import { SherpaSDK } from 'https://cdn.jsdelivr.net/npm/@sherpa/client@0.0.1/dist/sherpa-sdk.0.0.1.esm.js';
  const sdk = new SherpaSDK();
  await sdk.boot({ key: 'your-workspace-key' });
</script>
```

**npm Installation:**

```

```