@landbot/core
v4.0.0
Published
Landbot client core
Keywords
Readme
@landbot/core
Landbot client core library. Connects to the messaging database and Landbot app servers.
Modern ES Module library built with TypeScript and Vite for building Landbot chat integrations.
✨ Features
- 🎯 ES Module only - Modern, tree-shakeable
- 📦 TypeScript support - Full type definitions included
- 🔥 Firebase integration - Real-time message synchronization
- 📡 RxJS pipelines - Reactive message streams
📦 Installation
npm install @landbot/core🚀 Quick Start
Basic Usage
import { Core } from '@landbot/core';
// Fetch configuration from your chatbot share url
const config = await fetch('https://landbot.online/v3/H-3235078-2DQVIGPPXBU1AF2X/index.html').then((res) => res.json());
const core = new Core(config);
// Initialize and get previous messages
const { messages } = await core.init();
console.log('Previous messages:', messages);
// Send a message
core.sendMessage({ type: 'text', message: 'Hey!' });TypeScript
import { type ConfigProperties, Core, type Message } from '@landbot/core';
// Fetch configuration from your chatbot share url
const config = (await fetch('https://landbot.online/v3/H-3235078-2DQVIGPPXBU1AF2X/index.html').then((res) =>
res.json(),
)) as ConfigProperties;
const core = new Core(config);
core.pipelines.$readableSequence.subscribe((message: Message) => {
console.log(`[${message.type}]`, message.rich_text ?? message.title ?? message.message);
});
await core.init();📡 Pipelines
Pipelines provide ordered, sequential message flows using RxJS Observables. This solves the problem of unordered messages from external services.
$sequence
Basic sequential flow of messages:
core.pipelines.$sequence.subscribe((message) => {
console.log(`[${message.type}]`, message.rich_text ?? message.title ?? message.message);
});$readableSequence (Recommended)
Sequential flow with delays between messages for better readability:
core.pipelines.$readableSequence.subscribe((message) => {
console.log(`[${message.type}]`, message.rich_text ?? message.title ?? message.message);
// Messages arrive with natural delays
});$typingSequence
Sequential flow with typing indicators:
core.pipelines.$typingSequence.subscribe((data) => {
if (data?.state) {
console.log('Bot is typing...');
} else if (data?.message) {
console.log('Message:', data.message);
}
});🎯 API Reference
Core Class
class Core {
constructor(config: ConfigProperties);
// Properties
config: Config & ConfigProperties;
events: EventEmitter;
pipelines: Pipelines;
storage: Storage;
client: Client;
database: Database | null;
// Methods
init(): Promise<InitializationData>;
destroy(): void;
sendMessage(data: SendingMessage): Promise<void>;
setConfig(config: Partial<ConfigProperties>): void;
}Methods
init(): Promise<InitializationData>
Initialize the core and retrieve conversation history.
const data = await core.init();
console.log(data.messages); // Previous messages
console.log(data.landbotToken); // Session token retrieved from local storage, if enabled
console.log(data.isNewSession); // Whether this is a new sessionReturns:
interface InitializationData {
landbotToken: string | null;
isNewSession: boolean;
messages: Record<string, Message>;
}sendMessage(data: SendingMessage): Promise<void>
Send a message to the conversation.
// Text message
core.sendMessage({
type: 'text',
message: 'Hello!',
});
// With custom data and payload
core.sendMessage({
type: 'button',
message: 'Option 1',
payload: '$0',
custom_data: { user_field: '123' },
});Parameters:
interface SendingMessage {
type: MessageTypes;
message: string;
payload?: string;
custom_data?: Record<string, any>;
ui_key?: string;
}destroy(): void
Clean up and destroy the core instance.
core.destroy();setConfig(config: Partial<ConfigProperties>): void
Update configuration (must be called before init()).
Pipelines
Pipelines are RxJS Observables that provide ordered message flows:
interface Pipelines {
$sequence: Subject<Message>;
$typingSequence: BehaviorSubject<TypingMessage | null>;
$readableSequence: Subject<Message>;
}$sequence
Basic sequential flow of messages:
core.pipelines.$sequence.subscribe((message: Message) => {
console.log(message);
});$readableSequence (Recommended)
Sequential flow with natural delays between messages:
core.pipelines.$readableSequence.subscribe((message: Message) => {
console.log(`[${message.type}]`, message.message || message.title);
});$typingSequence
Sequential flow with typing indicators:
core.pipelines.$typingSequence.subscribe((data: TypingMessage | null) => {
if (data?.state) {
console.log('Bot is typing...');
} else if (data?.message) {
console.log('Message:', data.message);
}
});Type:
interface TypingMessage {
key: string;
state: boolean;
message: Message;
delay?: number;
}Events
The core uses EventEmitter3 for event handling:
new_message
Triggered when a new message is received. Note: Prefer using pipelines for ordered message flow.
core.events.on('new_message', (message: Message) => {
console.log('New message:', message);
});init
Triggered when initialization is complete:
core.events.on('init', () => {
console.log('Core initialized');
});Type Definitions
Message
interface Message {
id: string;
key: string;
type: MessageTypes;
timestamp: number;
seq?: number | null;
ui_key?: string | null;
samurai?: number | string; // Bot messages have samurai property
extra?: {
[key: string]: any;
typing: 'auto' | 'custom';
typing_delay: number;
} | null;
message?: string;
title?: string;
action?: string;
}ConfigProperties
interface ConfigProperties {
// Firebase configuration
firestore: {
api_key: string;
app_id: string;
project_id: string;
};
firestoreSettings?: Record<string, unknown>;
// Server configuration
serverUrl: string | null;
brandID: number;
channelToken: string;
welcomeUrl?: string | null;
// Optional configuration
landbotToken?: string | null; // Pre-existing Landbot token
welcome?: Message[]; // Welcome messages
storage_off?: boolean; // Disable local storage
// Typing options
typing_options?: {
state: boolean;
block_custom?: boolean;
delay?: {
is_constant: boolean;
constant: number;
average_human_reading_speed: number;
max_delay: number;
};
};
}🎨 Framework Examples
React Typescript
import { useEffect, useRef, useState } from 'react';
import { type ConfigProperties, Core, type Message, type Pipelines } from '@landbot/core';
function App() {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState('');
const coreRef = useRef<Core | null>(null);
useEffect(() => {
let subscription: ReturnType<Pipelines['$readableSequence']['subscribe']>;
// Fetch configuration from your chatbot share url
fetch('https://landbot.pro/v3/H-3264766-KWEIO45R3L3OYPE1/index.json')
.then((res) => res.json())
.then((config: ConfigProperties) => {
const core = new Core(config);
coreRef.current = core;
// Make sure you're subscribed to incoming messages before core initialization
subscription = core.pipelines.$readableSequence.subscribe((message) => {
setMessages((prev) => [...prev, message]);
});
return core.init();
})
.catch(console.error);
return () => subscription?.unsubscribe();
}, []);
const handleSend = () => {
if (coreRef.current && input.trim()) {
coreRef.current.sendMessage({ type: 'text', message: input });
setInput('');
}
};
return (
<div>
<div className="messages">
{messages.map((msg) => (
<div key={msg.key} className="message">
{msg.title ?? msg.message}
</div>
))}
</div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleSend()}
/>
<button onClick={handleSend}>Send</button>
</div>
);
}