Elaras/

JavaScript SDK

@elaras/chat-sdk is a zero-dependency TypeScript SDK that wraps the Elaras Chat API. Use it when you want to build a completely custom chat UI without the widget.

Installation

npm install @elaras/chat-sdk

Quick start — streaming

import {ChatClient} from '@elaras/chat-sdk';

const client = new ChatClient({chatbotKey: 'cbt_your_key_here'});

const sessionId = client.getOrCreateSessionId();

for await (const event of client.stream(sessionId, 'What are your opening hours?')) {
  if (event.type === 'delta') {
    process.stdout.write(event.content); // stream tokens to the UI
  } else if (event.type === 'done') {
    console.log('\nCredits used:', event.credits_used);
  } else if (event.type === 'error') {
    console.error('Error:', event.message);
  }
}

Creating a client

import {ChatClient} from '@elaras/chat-sdk';

const client = new ChatClient({
  chatbotKey: 'cbt_your_key_here',
  // apiUrl defaults to 'https://api.elaras.ai'
  apiUrl: 'https://api.elaras.ai',
});

Options

OptionTypeRequiredDescription
chatbotKeystringYesYour public chatbot key (cbt_...)
apiUrlstringNoOverride the API base URL. Defaults to https://api.elaras.ai

Methods

getConfig()

Fetches the chatbot's public configuration — name, greeting, appearance settings, and lead capture setup. Called automatically by stream() if needed; you only need to call it directly if you want to read config values before starting a conversation.

const config = await client.getConfig();

console.log(config.name);              // "Aria"
console.log(config.greeting_message); // "Hi! How can I help?"
console.log(config.collect_leads);    // true
console.log(config.appearance?.primary_color); // "#00C4A7"

Returns: ChatbotConfig

interface ChatbotConfig {
  id:               string;
  name:             string;
  avatar_url?:      string | null;
  greeting_message: string | null;
  collect_leads:    boolean;
  lead_prompt:      string | null;
  appearance: {
    primary_color?: string;
    position?:      'bottom-right' | 'bottom-left';
    bubble_text?:   string;
    powered_by?:    boolean;
    theme?:         'light' | 'dark' | 'auto';
  } | null;
  triage_questions: {
    ask_name:  { enabled: boolean; question: string };
    ask_email: { enabled: boolean; question: string };
    custom:    { question: string }[];
  } | null;
}

stream(sessionId, message)

Sends a message and returns an async generator that yields streaming events as the AI responds. Uses a WebSocket connection for real-time token delivery.

for await (const event of client.stream(sessionId, 'Tell me about your plans.')) {
  switch (event.type) {
    case 'delta':
      // A new token arrived — append to the current message
      appendToUI(event.content);
      break;

    case 'done':
      // Response complete
      console.log('Message ID:', event.message_id);
      console.log('Credits used:', event.credits_used);
      break;

    case 'error':
      console.error('Error code:', event.code);
      console.error('Error message:', event.message);
      break;
  }
}

Event types:

EventFieldsDescription
deltacontent: stringNext token chunk from the AI
donemessage_id: number, credits_used: numberResponse complete
errormessage: string, code?: stringAn error occurred

send(sessionId, message)

Sends a message and waits for the complete AI response synchronously (no streaming). Useful for server-side or simple integrations where you do not need real-time delivery.

const result = await client.send(sessionId, 'What are your prices?');

console.log(result.response);      // Full AI response text
console.log(result.message_id);    // Database ID of the saved message
console.log(result.credits_used);  // Credits consumed

Returns:

interface CompletionResult {
  message_id: number;
  response: string;
  credits_used: number;
}

getOrCreateSessionId()

Returns the current session UUID from localStorage, or generates a new one if none exists. Call this once when your chat component mounts.

const sessionId = client.getOrCreateSessionId();
// e.g. "a1b2c3d4-e5f6-7890-abcd-ef1234567890"

The session ID is stored in localStorage under elaras_session_{chatbotKey} and persists across page reloads.


clearSessionId()

Removes the session UUID from localStorage, causing the next call to getOrCreateSessionId() to generate a fresh session. Use this for a "start over" button.

client.clearSessionId();
const freshSessionId = client.getOrCreateSessionId(); // New UUID

getSession(sessionId)

Fetches the session and its full message history from the API.

const session = await client.getSession(sessionId);

for (const msg of session.messages) {
  console.log(`[${msg.role}] ${msg.content}`);
}

Returns:

interface Session {
  session: string;     // Session UUID
  messages: ChatMessage[];
}

interface ChatMessage {
  id: number;
  session_id: string;
  role: 'user' | 'assistant' | 'system';
  content: string;
  credits_used: number | null;
  feedback: 'up' | 'down' | null;
  created_at: string;
}

clearSession(sessionId)

Deletes all messages in the session on the server. The session UUID remains valid — the next message will start a fresh conversation.

await client.clearSession(sessionId);

submitLead(sessionId, lead)

Associates an email address (and optional name) with the session. Triggers the lead.captured webhook event.

await client.submitLead(sessionId, {
  email: '[email protected]',
  name: 'Jordan',         // optional
});

submitTriage(sessionId, answers)

Submits pre-chat triage answers collected before the conversation begins.

await client.submitTriage(sessionId, [
  {type: 'name',   question: 'What is your name?',         answer: 'Jordan'},
  {type: 'email',  question: 'What is your email?',        answer: '[email protected]'},
  {type: 'custom', question: 'What can we help you with?', answer: 'Billing question'},
]);

Each answer has these fields:

FieldTypeValues
typestring'name' | 'email' | 'custom'
questionstringThe question text
answerstringThe user's answer

submitFeedback(messageId, rating)

Records thumbs-up or thumbs-down feedback for an AI response.

await client.submitFeedback(42, 'up');   // thumbs up
await client.submitFeedback(42, 'down'); // thumbs down

Full example — streaming chat UI (vanilla JS)

import {ChatClient} from '@elaras/chat-sdk';

const client = new ChatClient({chatbotKey: 'cbt_your_key_here'});
const sessionId = client.getOrCreateSessionId();

const messagesEl = document.getElementById('messages')!;
const inputEl    = document.getElementById('input')! as HTMLInputElement;
const sendBtn    = document.getElementById('send')!;

// Load history on mount
const session = await client.getSession(sessionId);
for (const msg of session.messages) {
  appendMessage(msg.role, msg.content);
}

sendBtn.addEventListener('click', async () => {
  const text = inputEl.value.trim();
  if (!text) return;

  inputEl.value = '';
  appendMessage('user', text);

  const aiEl = appendMessage('assistant', '');

  for await (const event of client.stream(sessionId, text)) {
    if (event.type === 'delta') {
      aiEl.textContent += event.content;
    } else if (event.type === 'error') {
      aiEl.textContent = 'Something went wrong. Please try again.';
    }
  }
});

function appendMessage(role: 'user' | 'assistant', content: string): HTMLElement {
  const el = document.createElement('div');
  el.className = `message message--${role}`;
  el.textContent = content;
  messagesEl.appendChild(el);
  messagesEl.scrollTop = messagesEl.scrollHeight;
  return el;
}

Error handling

All methods throw a ChatError on non-2xx responses:

import {ChatClient, ChatError} from '@elaras/chat-sdk';

try {
  const result = await client.send(sessionId, 'Hello');
} catch (err) {
  if (err instanceof ChatError) {
    console.error(err.message);  // Human-readable message
    console.error(err.code);     // Error code (if provided)
    console.error(err.status);   // HTTP status code
  }
}