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 🙏

© 2025 – Pkg Stats / Ryan Hefner

navi-widget-sdk

v1.1.0

Published

Navi Chat Widget SDK - React, vanilla JS, headless client, and stream handler

Readme

Navi Widget SDK

A flexible chat widget SDK for integrating Navi AI into your applications. Supports both React components and vanilla JavaScript.

Installation

npm install navi-widget-sdk

Usage

React Component

The SDK provides a NaviChat component with two display modes:

Floating Mode (Default)

A floating button that opens a chat window when clicked:

import { NaviChat } from 'navi-widget-sdk/react';

function App() {
  return (
    <NaviChat
      widgetId="your-widget-id"
      position="bottom-right"  // or "bottom-left"
    />
  );
}

Embedded Mode

A static chat component that can be placed anywhere in your layout:

import { NaviChat } from 'navi-widget-sdk/react';

function App() {
  return (
    <div style={{ height: '600px', width: '400px' }}>
      <NaviChat
        widgetId="your-widget-id"
        mode="embedded"
      />
    </div>
  );
}

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | widgetId | string | required | Widget ID from Navi dashboard | | mode | 'floating' \| 'embedded' | 'floating' | Display mode | | position | 'bottom-right' \| 'bottom-left' | 'bottom-right' | Position for floating mode | | defaultOpen | boolean | false | Initial open state for floating mode | | baseUrl | string | window.location.origin | Navi API base URL | | sessionToken | string | - | Existing session token to resume a conversation | | userToken | string | - | User identity token for verified users | | runtimeParams | Record<string, unknown> | - | Runtime parameters for agent execution (see below) | | theme | Partial<NaviWidgetTheme> | - | Custom theme overrides | | greeting | string | 'Hello! How can I help you today?' | Initial greeting message | | placeholder | string | 'Type your message...' | Input placeholder text | | title | string | 'Chat with us' | Widget title | | className | string | - | Additional CSS class name | | style | React.CSSProperties | - | Inline styles | | onOpen | () => void | - | Callback when widget opens | | onClose | () => void | - | Callback when widget closes | | onMessageSent | (message: string) => void | - | Callback when user sends a message | | onMessageReceived | (message: NaviMessage) => void | - | Callback when response is received | | onStatusUpdate | (status: string) => void | - | Callback when status updates (e.g., "Searching...") | | onError | (error: Error) => void | - | Error callback |

Custom Theme

<NaviChat
  widgetId="your-widget-id"
  theme={{
    primaryColor: '#10b981',      // Button and user message color
    backgroundColor: '#ffffff',   // Chat window background
    textColor: '#1f2937',         // Text color
    headerColor: '#10b981',       // Header background
    borderRadius: 16,             // Border radius in pixels
  }}
/>

With Identity Verification

For verified users, pass the user token generated on your server:

<NaviChat
  widgetId="your-widget-id"
  userToken={generateUserToken(userId)} // From your backend
/>

With Runtime Parameters

Runtime parameters are dynamic values that can be injected at execution time and referenced in agent configurations using ${params.key} syntax:

<NaviChat
  widgetId="your-widget-id"
  runtimeParams={{
    user_token: 'jwt-abc123',
    api_key: 'sk-secret-key',
    user_id: 42,
    organization_id: 'org-123'
  }}
/>

Where runtime parameters can be used in agent configuration:

  • MCP server headers: Authorization: Bearer ${params.user_token}
  • HTTP request headers: X-API-Key: ${params.api_key}
  • Custom functions: tools.getParam('user_id')
  • Agent instructions: You are helping user ${params.user_id}

Built-in parameters (automatically available):

| Parameter | Description | |-----------|-------------| | params.current_date | Current date (YYYY-MM-DD) | | params.current_datetime | Full ISO datetime | | params.current_timestamp | Unix timestamp in ms | | params.execution_id | Unique execution identifier |


Vanilla JavaScript (HTML Embed)

For non-React websites, use the vanilla JavaScript widget:

Basic Usage

Add this script tag to your HTML, just before the closing </body> tag:

<script
  src="https://your-navi-url.com/widget.js"
  data-widget-id="your-widget-id"
  async
></script>

Configuration Options

<script
  src="https://your-navi-url.com/widget.js"
  data-widget-id="your-widget-id"
  data-position="bottom-left"
  data-auto-open="true"
  data-user-token="optional-user-token"
  data-base-url="https://api.your-navi.com"
  async
></script>

| Attribute | Description | |-----------|-------------| | data-widget-id | Required. Widget ID from Navi dashboard | | data-position | 'bottom-right' or 'bottom-left' (default: 'bottom-right') | | data-auto-open | 'true' to auto-open widget on load | | data-user-token | User identity token for verified users | | data-base-url | Custom API base URL |

Programmatic Control

After the widget loads, you can control it programmatically:

// Open the widget
window.naviWidgetInstance.open();

// Close the widget
window.naviWidgetInstance.close();

// Toggle open/close
window.naviWidgetInstance.toggle();

// Set user token (for identity verification)
window.naviWidgetInstance.setUserToken('user-token-here');

// Set/Get session token (for session persistence)
window.naviWidgetInstance.setSession('session-token');
const token = window.naviWidgetInstance.getSession();

// Clear chat history
window.naviWidgetInstance.clearHistory();

// Destroy the widget
window.naviWidgetInstance.destroy();

Manual Initialization

For more control, you can initialize the widget manually:

<script src="https://your-navi-url.com/widget.js"></script>
<script>
  // Wait for the script to load
  document.addEventListener('DOMContentLoaded', function() {
    window.NaviWidget = new NaviWidget({
      widgetId: 'your-widget-id',
      position: 'bottom-right',
      autoOpen: false,
      userToken: 'optional-user-token',
      baseUrl: 'https://api.your-navi.com',
      sessionToken: 'optional-session-token',
      greeting: 'Hello! How can I help?',
      placeholder: 'Type your message...',
      title: 'Chat with us',
      theme: {
        primaryColor: '#6366f1',
        backgroundColor: '#ffffff',
        textColor: '#1f2937',
        headerColor: '#6366f1',
        borderRadius: 12,
      },
      onOpen: function() {
        console.log('Widget opened');
      },
      onClose: function() {
        console.log('Widget closed');
      },
      onMessageSent: function(message) {
        console.log('User sent:', message);
      },
      onMessageReceived: function(message) {
        console.log('Bot replied:', message.content);
      },
      onStatusUpdate: function(status) {
        console.log('Status:', status);
      },
      onError: function(error) {
        console.error('Widget error:', error);
      }
    });
  });
</script>

Full Options Reference

| Option | Type | Default | Description | |--------|------|---------|-------------| | widgetId | string | required | Widget ID from Navi dashboard | | position | 'bottom-right' \| 'bottom-left' | 'bottom-right' | Widget position | | autoOpen | boolean | false | Auto-open widget on load | | baseUrl | string | window.location.origin | Navi API base URL | | sessionToken | string | - | Existing session token to resume a conversation | | userToken | string | - | User identity token for verified users | | greeting | string | 'Hello! How can I help you today?' | Initial greeting message | | placeholder | string | 'Type your message...' | Input placeholder text | | title | string | 'Chat with us' | Widget title | | theme | Partial<NaviWidgetTheme> | - | Custom theme overrides | | onOpen | () => void | - | Callback when widget opens | | onClose | () => void | - | Callback when widget closes | | onMessageSent | (message: string) => void | - | Callback when user sends a message | | onMessageReceived | (message: NaviMessage) => void | - | Callback when response is received | | onStatusUpdate | (status: string) => void | - | Callback when status updates (e.g., "Searching...") | | onError | (error: Error) => void | - | Error callback |


Headless Mode (API Client)

For custom integrations without any UI, such as middleware proxies, CLI applications, or server-side integrations, use the NaviHeadlessClient:

Installation & Import

import { NaviHeadlessClient } from 'navi-widget-sdk';
// or
import { NaviHeadlessClient } from 'navi-widget-sdk/headless';

Basic Usage

const client = new NaviHeadlessClient({
  widgetId: 'your-widget-id',
  baseUrl: 'https://your-navi-instance.com',
});

// Create a session (required before sending messages)
const sessionToken = await client.createSession();

// Send a message with streaming callbacks
await client.sendMessage('Hello!', {
  onDelta: (text) => process.stdout.write(text),
  onStatus: (status) => console.log('Status:', status),
  onComplete: (response) => console.log('\nDone:', response),
  onError: (error) => console.error('Error:', error),
});

Configuration Options

| Option | Type | Description | |--------|------|-------------| | widgetId | string | Required. Widget ID from Navi dashboard | | baseUrl | string | Required. Navi API base URL | | sessionToken | string | Optional. Existing session token to resume a conversation | | userToken | string | Optional. User identity token for verified users | | runtimeParams | Record<string, unknown> | Optional. Runtime parameters for agent execution |

Stream Callbacks

| Callback | Parameters | Description | |----------|------------|-------------| | onDelta | (text: string) | Called for each text chunk as it streams | | onStatus | (status: string) | Called when status updates (e.g., "Searching...", "Processing...") | | onComplete | (fullResponse: string) | Called when the response is complete | | onError | (error: Error) | Called when an error occurs |

API Methods

// Session Management
await client.createSession(metadata?: Record<string, unknown>): Promise<string>
client.setSession(token: string): void
client.getSession(): string | null
client.hasSession(): boolean

// Messaging
await client.sendMessage(content: string, callbacks?: NaviStreamCallbacks, runtimeParams?: Record<string, unknown>): Promise<string>
await client.sendMessageSync(content: string): Promise<string>  // Non-streaming

// History
client.getMessages(): NaviHeadlessMessage[]
client.clearMessages(): void
await client.fetchHistory(): Promise<NaviHeadlessMessage[]>

// User Identity
client.setUserToken(token: string | undefined): void

// Runtime Parameters
client.setRuntimeParams(params: Record<string, unknown> | undefined): void
client.getRuntimeParams(): Record<string, unknown> | undefined

Runtime Parameters

Runtime parameters can be set at construction, updated later, or passed per-message:

// Set at construction
const client = new NaviHeadlessClient({
  widgetId: 'your-widget-id',
  baseUrl: 'https://your-navi-instance.com',
  runtimeParams: {
    user_token: 'jwt-abc123',
    api_key: 'sk-secret-key',
  },
});

// Update later
client.setRuntimeParams({
  user_token: 'new-token',
  user_id: 42,
});

// Or pass per-message (overrides client-level params)
await client.sendMessage('Hello', {
  onDelta: (text) => console.log(text),
}, {
  user_token: 'message-specific-token',
});

Middleware Proxy Example

For proxying Navi responses through your own middleware:

// middleware/navi-proxy.ts
import { NaviHeadlessClient } from 'navi-widget-sdk';

export async function handleChatRequest(req: Request): Promise<Response> {
  const { message, sessionToken } = await req.json();

  const client = new NaviHeadlessClient({
    widgetId: process.env.NAVI_WIDGET_ID!,
    baseUrl: process.env.NAVI_API_URL!,
    sessionToken,
  });

  // Create session if not provided
  let token = sessionToken;
  if (!client.hasSession()) {
    token = await client.createSession();
  }

  // Create a TransformStream for SSE
  const { readable, writable } = new TransformStream();
  const writer = writable.getWriter();
  const encoder = new TextEncoder();

  // Send message with streaming
  client.sendMessage(message, {
    onDelta: async (text) => {
      await writer.write(encoder.encode(`data: ${JSON.stringify({ type: 'delta', text })}\n\n`));
    },
    onStatus: async (status) => {
      await writer.write(encoder.encode(`data: ${JSON.stringify({ type: 'status', status })}\n\n`));
    },
    onComplete: async (response) => {
      await writer.write(encoder.encode(`data: ${JSON.stringify({ type: 'complete', response, sessionToken: token })}\n\n`));
      await writer.close();
    },
    onError: async (error) => {
      await writer.write(encoder.encode(`data: ${JSON.stringify({ type: 'error', error: error.message })}\n\n`));
      await writer.close();
    },
  });

  return new Response(readable, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
    },
  });
}

Session Persistence

To persist conversations across requests, store and reuse the session token:

// First request - create new session
const client = new NaviHeadlessClient({
  widgetId: 'your-widget-id',
  baseUrl: 'https://your-navi-instance.com',
});
const sessionToken = await client.createSession();
// Store sessionToken (e.g., in database, cookie, or cache)

// Subsequent requests - reuse session
const client2 = new NaviHeadlessClient({
  widgetId: 'your-widget-id',
  baseUrl: 'https://your-navi-instance.com',
  sessionToken: storedSessionToken, // Pass the stored token
});

// Or set it after construction
client2.setSession(storedSessionToken);

TypeScript Types

interface NaviHeadlessConfig {
  widgetId: string;
  baseUrl: string;
  sessionToken?: string;
  userToken?: string;
  runtimeParams?: Record<string, unknown>;
}

interface NaviHeadlessMessage {
  role: 'user' | 'assistant';
  content: string;
  timestamp: Date;
}

interface NaviStreamCallbacks {
  onDelta?: (text: string) => void;
  onStatus?: (status: string) => void;
  onComplete?: (fullResponse: string) => void;
  onError?: (error: Error) => void;
}

Development

# Install dependencies
npm install

# Build the SDK
npm run build

# Watch mode
npm run dev

# Type checking
npm run typecheck

Build Output

After building, the following files are generated in dist/:

  • index.js / index.esm.js - Main library (CJS/ESM)
  • react/index.js / react/index.esm.js - React components
  • vanilla/navi-widget.js - Standalone vanilla JS widget (IIFE)
  • *.d.ts - TypeScript declarations

License

MIT