Monorepo Structure
This repository contains multiple packages:
- Server (Go) (
packages/server): Standalone Go implementation of the WebSocket bridge (recommended) - Server (Bun, deprecated) (
packages/server-bun): Original Bun/Node.js implementation kept for reference - SDK (
packages/sdk): TypeScript/JavaScript client for connecting to the bridge - Examples (
examples/): Usage examples for the SDK
Features
- Role-based connection system (server/client)
- Server-to-clients message broadcasting
- SDK support for receiving as a client or publishing as the server role
- Token-based authentication
- Reconnection support
Requirements
- Bun v1.2.0 or higher (required for managing the monorepo and running the SDK / Bun server)
- Go 1.23.0 or higher (only for building or running the Go server from source; the project selects the Go 1.24.2 toolchain)
Installation
You can run the server in different methods:
- Pre-compiled binaries (easiest for non-technical users)
- Go server (easy to deploy, recommended)
laplace-event-fetcherbridge mode (recommended for stability)- Bun server (deprecated, only for reference)
- Source code (for advanced users and developers)
Pre-compiled Binaries
If you're not familiar with programming or command-line tools, the easiest way to run the LAPLACE Event Bridge server is to download a pre-compiled binary from our GitHub releases:
-
Download the server
- Go to the GitHub Releases page
- Find the latest release with
@laplace.live/event-bridge-serverin the name - Download the appropriate file for your operating system:
- Windows:
leb-server-windows-x64.exe - macOS:
leb-server-darwin-arm64 - Linux (x64):
leb-server-linux-x64 - Linux (arm64):
leb-server-linux-arm64
- Windows:
-
Make it executable (macOS/Linux only):
- Open Terminal
- Navigate to your Downloads folder:
cd ~/Downloads - Run:
chmod +x leb-server-*(replace * with your actual filename)
-
Run the server:
- Windows: Double-click the
.exefile - macOS: In Terminal, run
./leb-server-darwin-arm64 - Linux: In Terminal, run
./leb-server-linux-x64(replacex64witharm64when needed)
- Windows: Double-click the
The server will start and display a message when it's ready to accept connections.
Bridge Server (Go)
The recommended bridge server is now a single-binary Go application located in packages/server. Building or running it does not require Bun – only the Go tool-chain.
For full documentation see packages/server/README.md, but a quick start looks like this:
# Enter the Go module and run from source
cd packages/server
go run . --debug
# Or build a native binary
go build -o leb-server .
./leb-server --host 0.0.0.0 --auth "your-secure-token"The server listens on http://localhost:9696 by default.
Event Fetcher Bridge Mode
In the latest version of laplace-event-fetcher (v2.2.0 and above), you can enable the WebSocket bridge mode to run the event fetcher as a bridge server for better stability. With this mode, you do not need to keep the LAPLACE Chat dashboard running as it will run as the event fetcher + bridge server for you.
Bridge Server (Bun, Deprecated)
The original Bun/Node.js implementation lives in packages/server-bun. It is feature-equivalent but has been superseded by the Go version for performance and deployment simplicity. It is still shipped for anyone relying on it.
# Start the Bun server
bun run --cwd packages/server-bun start --debug --auth "your-secure-token"Server Comparison
| Feature | Bridge Server (Go) | Event Fetcher Bridge Mode |
|---|---|---|
| Installation | Single binary or Go toolchain | Requires LAPLACE Event Fetcher v2.2.0+ |
| Environment | Local (standalone binary) | Container |
| Deployment | Easy - single file deployment | Needs server running |
| Event Source | LAPLACE Chat console or SDK server role | Built into Event Fetcher |
| Reuse Local Connection | Yes | No |
| Configuration | Command-line flags | Event fetcher config |
| Stability | Depends on your local network | Better stability |
| Best For | Hobby projects integration, small scale | Production ready and large scale for MCN agencies, or users already using event fetcher |
LLM Prompt
Paste the prompt below into your AI assistant, or keep it in a rules file such as CLAUDE.md or AGENTS.md, and it has the background it needs to write integrations for you. The documentation URLs it cites are all fetchable
You are helping me build an integration on top of LAPLACE Event Bridge, the WebSocket
bridge that relays real-time Bilibili live events — chat messages, gifts, super chats,
guard purchases, stream state — from LAPLACE Chat (https://chat.laplace.live) to local
clients.
Before writing any code, fetch the reference documents listed at the end — they are
the single source of truth for event types, payload fields and the client API. Do
not rely on memory and do not invent names.
## Setup
- Install `@laplace.live/event-bridge-sdk`. It runs anywhere with `WebSocket` and
`fetch` globals: Node.js 22+, Bun and browsers. Event payload interfaces live in
its dependency `@laplace.live/event-types`.
- A bridge server must be running: either the `leb-server` binary fed by LAPLACE Chat
or an SDK v1.2.0+ producer using `role: 'server'`, or LAPLACE Event Fetcher v2.2.0+
in bridge mode (standalone). Default endpoint: `ws://localhost:9696`.
- Auth is optional: when the server was started with `--auth`, pass the same string
as `token`.
## Client
```ts
import { LaplaceEventBridgeClient } from "@laplace.live/event-bridge-sdk";
const bridge = new LaplaceEventBridgeClient({
url: "ws://localhost:9696", // default
token: "your-auth-token", // only when the server enables auth
});
bridge.on("message", (event) => {
console.log(`${event.username}: ${event.message}`); // typed as Message
});
const offAny = bridge.onAny((event) => console.log(event.type, event.origin));
await bridge.connect();
// later: offAny(); bridge.disconnect();
```
## Producer (Server Role)
SDK v1.2.0+ can instead occupy the event-producing server role. This connects to
a running standalone Event Bridge server; it does not start the bridge server itself.
```ts
const producer = new LaplaceEventBridgeClient({
url: "ws://localhost:9696",
token: "your-auth-token",
role: "server",
});
await producer.connect();
producer.send(event); // event must be a LaplaceEvent
```
Only server-role messages are broadcast. A client-role `send()` is acknowledged by
the bridge but is not relayed to other connections.
The bridge is one-way — servers broadcast, clients listen — and reconnection is
automatic. Handlers are typed from the event name. Every event carries `type`, `id`
and `origin` (the canonical room id — filter on it when one bridge serves several
rooms). The exact event names, payload fields and the rest of the client API live in
the reference below — look them up instead of guessing.
## Reference
Fetch these before writing code:
- https://laplace.live/chat/event-bridge.en.mdx — this page as raw Markdown: server
setup, SDK client and producer roles, connection state, room discovery
- https://chat.laplace.live/event-types/ — every event type and payload field
- https://github.com/laplace-live/event-bridge — server and SDK source with runnable
examplesSDK
The SDK provides a type-safe connection to the event bridge. It can receive events as a client or produce them as the server role.
Installation
npm install @laplace.live/event-bridge-sdkUsage
import { LaplaceEventBridgeClient } from "@laplace.live/event-bridge-sdk";
const client = new LaplaceEventBridgeClient({
url: "ws://localhost:9696",
token: "your-auth-token", // If auth is enabled
});
// Connect to the bridge
await client.connect();
// Listen for specific events
client.on("message", (event) => {
console.log("Received message:", event);
});
// Listen for all events
client.onAny((event) => {
console.log("Received event:", event.type);
});Connection Options
LaplaceEventBridgeClient accepts the following optional connection settings:
Prop
Type
Server Role
SDK v1.2.0 and later can connect as the event producer. With role: 'server', each LaplaceEvent passed to
send() is broadcast by the bridge to all clients:
import { LaplaceEventBridgeClient } from "@laplace.live/event-bridge-sdk";
const producer = new LaplaceEventBridgeClient({
url: "ws://localhost:9696",
token: "your-auth-token",
role: "server",
});
await producer.connect();
function broadcast(event: Parameters<typeof producer.send>[0]) {
producer.send(event);
}The server role is an event-producing endpoint connected to a running standalone Event Bridge server; it does
not start the bridge server itself. The default client role receives events. Its send() calls are acknowledged
but are not relayed to other connections. Event Fetcher Bridge Mode produces events internally and ignores incoming
messages other than heartbeat pongs, so it cannot relay messages from SDK producers.
Connection State
onConnectionStateChange() immediately invokes a newly registered handler with the current state, so detail
can be undefined on that first call. Later transitions provide the close reason and current reconnect count when
available:
client.onConnectionStateChange((state, detail) => {
console.log(state, detail?.reconnectAttempts);
if (detail?.closeEvent) {
console.log(detail.closeEvent.code, detail.closeEvent.reason);
}
});
console.log(client.getReconnectAttempts());getReconnectAttempts() returns the attempts made during the current outage, or 0 while connected or idle.
Prop
Type
The server role, connection-state details, and getReconnectAttempts()
require SDK v1.2.0 or later.
Room Discovery
When the server is a LAPLACE Event Fetcher in bridge mode, it exposes an /info HTTP endpoint listing the configured rooms. The SDK can fetch it without an active WebSocket connection — useful for letting users pick which rooms to receive.
Use the client.getInfo() method (reuses the client's url / token):
const client = new LaplaceEventBridgeClient({
url: "ws://localhost:9696",
token,
});
const info = await client.getInfo();
if (info) {
console.log(`Fetcher v${info.version} exposes ${info.rooms.length} room(s)`);
for (const room of info.rooms) {
console.log(`${room.roomId}: ${room.username ?? "unknown"}`);
}
} else {
// Plain Event Bridge server or an older fetcher — fall back to manual entry.
}Or the standalone fetchInfo() function, which needs no client object:
import { fetchInfo } from "@laplace.live/event-bridge-sdk";
const info = await fetchInfo({ url: "ws://localhost:9696", token, signal });Both resolve to null (they never throw) when /info is unavailable — an old fetcher, a plain Event Bridge server, an aborted request, or any network/parse error — so callers can silently fall back to manual room entry.
The returned shapes are FetcherInfo and FetcherRoom, both exported from the SDK:
import type { FetcherInfo, FetcherRoom } from "@laplace.live/event-bridge-sdk";
interface FetcherRoom {
status: number; // 0 when resolved, otherwise an error code (e.g. 404)
uid: number;
roomId: number; // Canonical room id; matches the `origin` field on incoming events
shortRoomId: number;
username: string | null;
}
interface FetcherInfo {
version: string;
uptime: string;
connectedAt: number;
websocketBridge: boolean;
websocketClients: number;
rooms: FetcherRoom[];
}Room discovery requires LAPLACE Event Fetcher v2.2.0+ running in bridge mode and SDK v1.1.0 or higher.
LaplaceEvent
LaplaceEvent is the core type of the event bridge system, representing events exchanged between LAPLACE Chat and connected clients. Each event contains standardized data for various chat streams from Bilibili Live.
All events share a common type field that identifies the event category and additional fields specific to each event type.
You can read more about the event types in the Event Types documentation.
Use Cases
- Integrate with Discord, OBS, VTube Studio
- Create custom chat layouts in your preferred frontend
- Connect to 3rd party services like streamer.bot or SAMMI
- ...any other use case you can think of
Development
SDK Release Process
The SDK (@laplace.live/event-bridge-sdk) follows a structured release process using changesets for version management.
-
Make your changes to the SDK in
packages/sdk/ -
Create a changeset to document your changes:
bunx @changesets/cli- Select
@laplace.live/event-bridge-sdkfrom the package list - Choose the appropriate version bump (patch/minor/major)
- Write a clear description of the changes
- Select
-
Commit your changes including the generated changeset file:
git add . git commit -m "feat(sdk): your change description"
License
AGPL and MIT
Last updated on September 19, 2026