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

uneeq-state-manager

v1.3.1

Published

Uneeq State Manager SDK - Client library for managing chatbot session state

Readme

Uneeq State Manager SDK

A TypeScript client library for managing chatbot session state with real-time PubSub capabilities.

Table of Contents

  1. Installation
  2. Quick Start
  3. Configuration
  4. API Reference
  5. PubSub (Real-time Subscriptions)
  6. Error Handling
  7. TypeScript Support
  8. Examples
  9. License

Installation

npm install uneeq-state-manager
yarn add uneeq-state-manager

Requirements

  • Node.js 18.0.0 or higher
  • TypeScript 5.0 or higher (for development)

Quick Start

import { StateManager } from 'uneeq-state-manager';

// Initialize the State Manager
const stateManager = new StateManager({
  endpoint: 'https://api.example.com',
  apiKey: 'your-api-key',
});

// Access a workspace and create a session
const workspace = stateManager.workspace('my-workspace');
const session = workspace.session('user-session-123');

// Create the session with a 1 hour TTL
await session.create({ ttl: 3600 });

// Store session state
await session.set('user', { name: 'John', age: 30 });

// Retrieve session state
const user = await session.get('user');
console.log(user); // { name: 'John', age: 30 }

// End the session when done
await session.end();

Configuration

StateManagerConfig Options

interface StateManagerConfig {
  /** API endpoint URL for the State Manager Engine */
  endpoint: string;

  /** Authentication key for API requests */
  apiKey: string;

  /** Optional default workspace ID */
  workspaceId?: string;

  /** Request timeout in milliseconds (default: 30000) */
  timeout?: number;

  /** Maximum retry attempts (default: 3) */
  maxRetries?: number;

  /** Initial retry delay in milliseconds (default: 1000) */
  retryDelay?: number;
}

Configuration Example

const stateManager = new StateManager({
  endpoint: process.env.UNEEQ_ENDPOINT || 'https://api.example.com',
  apiKey: process.env.UNEEQ_API_KEY,
  timeout: 60000,
  maxRetries: 5,
  retryDelay: 2000,
});

API Reference

StateManager

The main entry point for the SDK.

workspace(workspaceId: string): Workspace

Gets a workspace instance for accessing sessions.

const workspace = stateManager.workspace('my-workspace');

Session

Manages session lifecycle and session-scoped state.

create(config?: SessionConfig): Promise<void>

Creates/initializes the session on the server.

await session.create({
  ttl: 3600, // Session expires in 1 hour
  metadata: { userId: 'user-123' },
});

getInfo(): Promise<SessionInfo>

Retrieves session information.

const info = await session.getInfo();
console.log(`Status: ${info.status}`);
console.log(`Expires at: ${info.expiresAt}`);
console.log(`State keys: ${info.stateKeys.join(', ')}`);

set<T>(key: string, data: T): Promise<void>

Sets a session state value.

await session.set('user', { name: 'John', age: 30 });
await session.set('conversation-count', 5);
await session.set('active', true);

get<T>(key: string): Promise<T | null>

Gets a session state value.

const user = await session.get<{ name: string; age: number }>('user');
if (user) {
  console.log(`User: ${user.name}`);
}

getAll<T>(): Promise<T>

Gets all session state as a single object.

const allState = await session.getAll();
console.log(allState); // { user: {...}, count: 5, active: true }

update<T>(key: string, updateFn: (current: T) => T): Promise<T>

Atomically updates a session state value.

const newCount = await session.update('count', (current) => current + 1);

const updatedUser = await session.update('user', (user) => ({
  ...user,
  lastSeen: new Date(),
}));

delete(key: string): Promise<void>

Deletes a session state value.

await session.delete('tempData');

has(key: string): Promise<boolean>

Checks if a state key exists.

if (await session.has('user')) {
  const user = await session.get('user');
}

keepAlive(): Promise<void>

Extends the session's TTL (call on user activity).

await session.keepAlive();

end(): Promise<void>

Terminates the session and removes all data.

await session.end();

publishToTopic<T>(topicId: string, data: T): Promise<PublishResult>

Publishes a message to a topic (session-scoped).

const result = await session.publishToTopic('messages', {
  text: 'Hello from Flowise!',
  type: 'assistant',
});
console.log(`Delivered to ${result.deliveredTo} subscribers`);

getSessionId(): string / getWorkspaceId(): string

Returns the session or workspace ID.

console.log(`Session: ${session.getSessionId()}`);
console.log(`Workspace: ${session.getWorkspaceId()}`);

PubSub (Real-time Subscriptions)

The SDK includes a PubSub client for real-time message subscriptions using Socket.IO.

Creating a PubSub Client

import { PubSubClient } from 'uneeq-state-manager';

const pubsub = new PubSubClient({
  endpoint: 'https://api.example.com',
  apiKey: 'your-api-key',
  workspaceId: 'my-workspace',
  sessionId: 'session-123', // Required for session-scoped subscriptions
});

PubSubConfig Options

interface PubSubConfig {
  /** Socket.IO server endpoint URL */
  endpoint: string;

  /** Authentication key */
  apiKey: string;

  /** Workspace identifier */
  workspaceId: string;

  /** Session ID (required for subscriptions) */
  sessionId: string;

  /** Auto-connect on creation (default: false) */
  autoConnect?: boolean;

  /** Enable automatic reconnection (default: true) */
  reconnection?: boolean;

  /** Max reconnection attempts (default: 10) */
  reconnectionAttempts?: number;

  /** Reconnection delay in ms (default: 1000) */
  reconnectionDelay?: number;
}

Subscribing to Topics

Simple handler:

const subscription = pubsub.subscribe('messages', (message) => {
  console.log('Received:', message.data);
  console.log('Published at:', message.publishedAt);
});

// Unsubscribe when done
subscription.unsubscribe();

With full options:

const subscription = pubsub.subscribe('messages', {
  onMessage: (message) => {
    console.log('Message from Flowise:', message.data);
  },
  onError: (error) => {
    console.error('Subscription error:', error);
  },
  onSubscribed: (subscriberCount) => {
    console.log(`Subscribed! ${subscriberCount} total subscribers`);
  },
  onUnsubscribed: () => {
    console.log('Unsubscribed from topic');
  },
});

Event Handling

// Connection events
pubsub.on('connect', () => {
  console.log('Connected to PubSub server');
});

pubsub.on('disconnect', () => {
  console.log('Disconnected from PubSub server');
});

pubsub.on('error', (error) => {
  console.error('PubSub error:', error);
});

// Session lifecycle
pubsub.on('session-ended', ({ sessionId, reason }) => {
  console.log(`Session ${sessionId} ended: ${reason}`);
});

Connection Management

// Manual connection
await pubsub.connect();

// Check connection status
if (pubsub.isConnected) {
  console.log('Connected');
}

// Disconnect and cleanup
await pubsub.disconnect();

Publishing Messages

Use the session's publishToTopic method to send messages (typically from Flowise to frontend):

// From your session instance (e.g., in Flowise)
const result = await session.publishToTopic('messages', {
  text: 'Here is your answer!',
  type: 'assistant',
});

console.log(`Message delivered to ${result.deliveredTo} subscribers`);

Error Handling

The SDK provides specialized error classes for different scenarios.

Error Types

| Error Class | HTTP Status | Description | |---|---|---| | StateManagerError | - | Base error class | | AuthenticationError | 401 | Invalid API credentials | | AuthorizationError | 403 | Insufficient permissions | | NotFoundError | 404 | Resource not found | | ValidationError | 400 | Invalid request parameters | | RateLimitError | 429 | Rate limit exceeded | | NetworkError | - | Network connectivity issues | | TimeoutError | - | Request timeout |

Error Handling Example

import {
  StateManagerError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
} from 'uneeq-state-manager';

try {
  const user = await session.get('user');
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Invalid API key:', error.message);
  } else if (error instanceof NotFoundError) {
    console.error('Session not found:', error.message);
  } else if (error instanceof RateLimitError) {
    console.error('Rate limited, retry later');
  } else if (error instanceof StateManagerError) {
    console.error(`Error (${error.code}):`, error.message);
  }
}

TypeScript Support

The SDK is built with TypeScript and provides full type safety.

Typed Session State

// Define your state types
interface ConversationState {
  messages: Array<{ role: 'user' | 'assistant'; content: string }>;
  currentTopic: string;
  sentiment: number;
}

// Use with full type safety
const session = workspace.session('conv-123');
await session.create();

// Set typed state
await session.set<ConversationState>('conversation', {
  messages: [{ role: 'user', content: 'Hello' }],
  currentTopic: 'support',
  sentiment: 0.8,
});

// Get with type inference
const conv = await session.get<ConversationState>('conversation');
if (conv) {
  console.log(conv.messages.length);
  console.log(conv.sentiment);
}

// Type-safe updates
const updated = await session.update<ConversationState>(
  'conversation',
  (current) => ({
    ...current,
    messages: [...current.messages, { role: 'assistant', content: 'Hi!' }],
    sentiment: (current.sentiment + 0.9) / 2,
  })
);

Typed PubSub Messages

interface FlowiseMessage {
  text: string;
  type: 'user' | 'assistant';
  timestamp?: string;
}

// Typed subscription (frontend receiving from Flowise)
pubsub.subscribe<FlowiseMessage>('messages', (message) => {
  console.log(message.data.text);  // string
  console.log(message.data.type);  // 'user' | 'assistant'
});

// Typed publish (Flowise sending to frontend)
await session.publishToTopic<FlowiseMessage>('messages', {
  text: 'Hello! How can I help you?',
  type: 'assistant',
  timestamp: new Date().toISOString(),
});

Examples

Basic Session Management

import { StateManager } from 'uneeq-state-manager';

async function basicSessionExample() {
  const stateManager = new StateManager({
    endpoint: 'https://api.example.com',
    apiKey: process.env.API_KEY,
  });

  const workspace = stateManager.workspace('demo-workspace');
  const session = workspace.session('user-123-session');

  try {
    // Create session with 1 hour TTL
    await session.create({ ttl: 3600 });

    // Store user information
    await session.set('user', {
      id: 'user-123',
      name: 'Alice',
      email: '[email protected]',
    });

    // Retrieve user information
    const user = await session.get('user');
    console.log('User:', user);

    // Check all session state
    const allState = await session.getAll();
    console.log('All state:', allState);

    // End session
    await session.end();
  } catch (error) {
    console.error('Error:', error);
  }
}

Chatbot Conversation Flow

import { StateManager } from 'uneeq-state-manager';

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

interface ConversationState {
  messages: Message[];
  topic: string;
  turnCount: number;
}

async function chatbotExample() {
  const stateManager = new StateManager({
    endpoint: 'https://api.example.com',
    apiKey: process.env.API_KEY,
  });

  const workspace = stateManager.workspace('chatbot-workspace');
  const session = workspace.session(`chat-${Date.now()}`);

  try {
    // Create session
    await session.create({
      ttl: 7200, // 2 hour conversation
      metadata: { type: 'customer-support' },
    });

    // Initialize conversation
    await session.set<ConversationState>('conversation', {
      messages: [],
      topic: 'support',
      turnCount: 0,
    });

    // Process user message
    const userMessage = 'I need help with my order';

    await session.update<ConversationState>('conversation', (current) => ({
      ...current,
      messages: [
        ...current.messages,
        {
          role: 'user',
          content: userMessage,
          timestamp: new Date().toISOString(),
        },
      ],
      turnCount: current.turnCount + 1,
    }));

    // Add assistant response
    await session.update<ConversationState>('conversation', (current) => ({
      ...current,
      messages: [
        ...current.messages,
        {
          role: 'assistant',
          content: 'I would be happy to help. What is your order number?',
          timestamp: new Date().toISOString(),
        },
      ],
    }));

    // Keep session alive on activity
    await session.keepAlive();

    // Retrieve conversation history
    const conversation = await session.get<ConversationState>('conversation');
    console.log('Messages:', conversation?.messages);
  } finally {
    await session.end();
  }
}

Real-time PubSub Example

This example shows how the frontend subscribes to receive messages from Flowise:

import { StateManager, PubSubClient } from 'uneeq-state-manager';

interface FlowiseMessage {
  text: string;
  type: 'user' | 'assistant';
  timestamp?: string;
}

async function frontendPubsubExample() {
  const stateManager = new StateManager({
    endpoint: 'https://api.example.com',
    apiKey: process.env.API_KEY,
  });

  const workspace = stateManager.workspace('my-workspace');
  const session = workspace.session('user-456');

  // Create session first
  await session.create({ ttl: 3600 });

  // Create PubSub client for this session
  const pubsub = new PubSubClient({
    endpoint: 'https://api.example.com',
    apiKey: process.env.API_KEY,
    workspaceId: 'my-workspace',
    sessionId: 'user-456',
  });

  // Handle connection events
  pubsub.on('connect', () => console.log('Connected to PubSub'));
  pubsub.on('error', (err) => console.error('PubSub error:', err));
  pubsub.on('session-ended', ({ reason }) => {
    console.log('Session ended:', reason);
  });

  // Subscribe to messages from Flowise
  const subscription = pubsub.subscribe<FlowiseMessage>('messages', {
    onMessage: (message) => {
      // Display message in the UI
      console.log(`[${message.data.type}]: ${message.data.text}`);
    },
    onSubscribed: (count) => {
      console.log(`Subscribed to messages (${count} subscribers)`);
    },
    onError: (error) => {
      console.error('Subscription error:', error);
    },
  });

  // Flowise publishes messages like this:
  // await session.publishToTopic<FlowiseMessage>('messages', {
  //   text: 'Hello! How can I help you?',
  //   type: 'assistant',
  // });

  // Later: cleanup
  subscription.unsubscribe();
  await pubsub.disconnect();
  await session.end();
}

License

This SDK is licensed under the MIT License.

Support

For issues or questions, please visit the GitLab repository.