reachlo 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -21
- package/examples/vanilla-js-chat/index.html +29 -0
- package/examples/vanilla-js-chat/main.js +65 -0
- package/examples/vanilla-js-chat/style.css +112 -0
- package/index.js +1 -1
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
# Reachlo SDK
|
|
2
2
|
|
|
3
|
-
**Real-time infrastructure for AI streaming.**
|
|
3
|
+
**Real-time infrastructure for AI streaming. Built to be radically cheaper than traditional real-time platforms.**
|
|
4
4
|
|
|
5
|
-
Reachlo is a
|
|
5
|
+
Reachlo is a drop-in real-time backend designed for AI-first products. Whether you're streaming LLM tokens, building collaborative canvases, or syncing multi-agent systems, Reachlo handles the scale — without punishing per-message pricing.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Why Reachlo?
|
|
10
|
+
|
|
11
|
+
* **⚡ Built for AI Streaming**
|
|
12
|
+
Optimized for high-frequency, small-packet token streams from LLMs and agents.
|
|
13
|
+
|
|
14
|
+
* **💰 Bandwidth-Based Pricing**
|
|
15
|
+
Pay for data transfer, not messages. Streaming workloads are often **up to 10× cheaper** than event-based platforms.
|
|
16
|
+
|
|
17
|
+
* **🌍 Global Edge Architecture**
|
|
18
|
+
Designed for single-digit millisecond latency in most regions.
|
|
19
|
+
|
|
20
|
+
* **🛠️ Zero Config**
|
|
21
|
+
No brokers, no clusters, no tuning. Just an API key and you’re live.
|
|
22
|
+
|
|
23
|
+
---
|
|
6
24
|
|
|
7
25
|
## Installation
|
|
8
26
|
|
|
@@ -10,43 +28,86 @@ Reachlo is a lightweight, WebSocket-based real-time messaging layer designed for
|
|
|
10
28
|
npm install reachlo
|
|
11
29
|
```
|
|
12
30
|
|
|
31
|
+
---
|
|
32
|
+
|
|
13
33
|
## Quick Start
|
|
14
34
|
|
|
15
35
|
### 1. Connect
|
|
16
36
|
|
|
17
|
-
Initialize the client
|
|
37
|
+
Initialize the client using an API key from the [Reachlo Dashboard](https://reachlo.pages.dev).
|
|
18
38
|
|
|
19
|
-
```
|
|
39
|
+
```js
|
|
20
40
|
import Reachlo from 'reachlo';
|
|
21
41
|
|
|
22
42
|
const client = new Reachlo('YOUR_API_KEY');
|
|
23
|
-
|
|
24
43
|
await client.connect();
|
|
25
44
|
```
|
|
26
45
|
|
|
27
|
-
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### 2. Stream AI Responses
|
|
28
49
|
|
|
29
|
-
|
|
50
|
+
Ideal for ChatGPT-style typing effects and live AI output.
|
|
30
51
|
|
|
31
|
-
```
|
|
32
|
-
const
|
|
52
|
+
```js
|
|
53
|
+
const stream = client.channel('ai-response-session-123');
|
|
33
54
|
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
55
|
+
// Subscribe to token updates
|
|
56
|
+
stream.subscribe((token) => {
|
|
57
|
+
renderToUI(token);
|
|
37
58
|
});
|
|
38
59
|
|
|
39
|
-
//
|
|
40
|
-
|
|
60
|
+
// Publish tokens from your backend or agent
|
|
61
|
+
stream.publish("The ");
|
|
62
|
+
stream.publish("future ");
|
|
63
|
+
stream.publish("is ");
|
|
64
|
+
stream.publish("real-time.");
|
|
41
65
|
```
|
|
42
66
|
|
|
43
|
-
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Use Cases
|
|
70
|
+
|
|
71
|
+
### 🤖 LLM Token Streaming
|
|
72
|
+
|
|
73
|
+
Stream tokens the moment they’re generated — no buffering, no batching.
|
|
74
|
+
|
|
75
|
+
### 👥 Real-Time Collaboration
|
|
76
|
+
|
|
77
|
+
Sync cursors, documents, canvases, and shared state across users.
|
|
78
|
+
|
|
79
|
+
### 📊 Live Data Feeds
|
|
80
|
+
|
|
81
|
+
Deliver real-time metrics, alerts, and notifications at scale.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Comparison
|
|
86
|
+
|
|
87
|
+
| Feature | Pusher / Ably | Reachlo |
|
|
88
|
+
| --------------- | --------------- | -------------------------- |
|
|
89
|
+
| Pricing Model | Per Message | **Per GB (Bandwidth)** |
|
|
90
|
+
| Streaming Cost | High | **Significantly Lower** |
|
|
91
|
+
| Architecture | Regional | **Global Edge** |
|
|
92
|
+
| AI Optimization | General Purpose | **Token-Stream Optimized** |
|
|
93
|
+
| Setup Time | ~10 Minutes | **~1 Minute** |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Advanced Configuration
|
|
98
|
+
|
|
99
|
+
For self-hosted or custom deployments:
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
const client = new Reachlo('YOUR_API_KEY', {
|
|
103
|
+
url: 'wss://your-custom-backend.com'
|
|
104
|
+
});
|
|
105
|
+
```
|
|
44
106
|
|
|
45
|
-
|
|
46
|
-
- **WebSocket Native**: Built on top of `uWebSockets.js` for extreme performance.
|
|
47
|
-
- **Channel Routing**: Automatically routes messages to the correct channel listeners.
|
|
48
|
-
- **Authentication**: Simple API key-based auth handled transparently.
|
|
107
|
+
---
|
|
49
108
|
|
|
50
|
-
##
|
|
109
|
+
## Links
|
|
51
110
|
|
|
52
|
-
|
|
111
|
+
* **Dashboard:** [https://reachlo.pages.dev](https://reachlo.pages.dev)
|
|
112
|
+
* **Docs:** [https://reachlo.pages.dev/docs](https://reachlo.pages.dev/docs)
|
|
113
|
+
* **Twitter:** [https://twitter.com/ReachloHQ](https://twitter.com/ReachloHQ)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Reachlo Vanilla JS Chat</title>
|
|
7
|
+
<link rel="stylesheet" href="style.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="chat-container">
|
|
11
|
+
<header>
|
|
12
|
+
<h1>Reachlo Chat</h1>
|
|
13
|
+
<div id="status" class="status">Connecting...</div>
|
|
14
|
+
</header>
|
|
15
|
+
|
|
16
|
+
<div id="messages" class="messages">
|
|
17
|
+
<!-- Messages will appear here -->
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<form id="chat-form">
|
|
21
|
+
<input type="text" id="message-input" placeholder="Type a message..." autocomplete="off">
|
|
22
|
+
<button type="submit">Send</button>
|
|
23
|
+
</form>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<!-- Ensure you have reachlo installed or link to a build -->
|
|
27
|
+
<script type="module" src="main.js"></script>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// In a real app, you would import this from 'reachlo'
|
|
2
|
+
// For this example to work without a bundler, we assume a build exists or we mock it for the structure.
|
|
3
|
+
// Since the user asked for a "vanilla-js-chat" inside the SDK repo,
|
|
4
|
+
// we'll assume they might link it.
|
|
5
|
+
// Here is the code structure as if using the SDK.
|
|
6
|
+
|
|
7
|
+
import Reachlo from '../../index.js'; // Importing directly from the SDK source for the local example
|
|
8
|
+
|
|
9
|
+
// REPLACE with your actual API key
|
|
10
|
+
const API_KEY = 'YOUR_API_KEY';
|
|
11
|
+
const CHANNEL_ID = 'demo-chat';
|
|
12
|
+
|
|
13
|
+
const client = new Reachlo(API_KEY);
|
|
14
|
+
const messagesDiv = document.getElementById('messages');
|
|
15
|
+
const statusDiv = document.getElementById('status');
|
|
16
|
+
const form = document.getElementById('chat-form');
|
|
17
|
+
const input = document.getElementById('message-input');
|
|
18
|
+
|
|
19
|
+
async function init() {
|
|
20
|
+
try {
|
|
21
|
+
statusDiv.textContent = 'Connecting...';
|
|
22
|
+
await client.connect();
|
|
23
|
+
statusDiv.textContent = 'Connected';
|
|
24
|
+
statusDiv.classList.add('connected');
|
|
25
|
+
|
|
26
|
+
const channel = client.channel(CHANNEL_ID);
|
|
27
|
+
|
|
28
|
+
// Subscribe to incoming messages
|
|
29
|
+
channel.subscribe((data) => {
|
|
30
|
+
appendMessage(data.text, 'received');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Handle sending
|
|
34
|
+
form.addEventListener('submit', (e) => {
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
const text = input.value.trim();
|
|
37
|
+
if (!text) return;
|
|
38
|
+
|
|
39
|
+
// Publish message
|
|
40
|
+
channel.publish({
|
|
41
|
+
text: text,
|
|
42
|
+
timestamp: Date.now()
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Optimistically append our own message
|
|
46
|
+
appendMessage(text, 'sent');
|
|
47
|
+
input.value = '';
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
} catch (err) {
|
|
51
|
+
console.error('Connection failed:', err);
|
|
52
|
+
statusDiv.textContent = 'Connection failed';
|
|
53
|
+
statusDiv.style.color = 'red';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function appendMessage(text, type) {
|
|
58
|
+
const msgDiv = document.createElement('div');
|
|
59
|
+
msgDiv.textContent = text;
|
|
60
|
+
msgDiv.classList.add('message', type);
|
|
61
|
+
messagesDiv.appendChild(msgDiv);
|
|
62
|
+
messagesDiv.scrollTop = messagesDiv.scrollHeight;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
init();
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--primary: #2563eb;
|
|
3
|
+
--bg: #f8fafc;
|
|
4
|
+
--chat-bg: #ffffff;
|
|
5
|
+
--text: #1e293b;
|
|
6
|
+
--border: #e2e8f0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
body {
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
11
|
+
background: var(--bg);
|
|
12
|
+
display: flex;
|
|
13
|
+
justify-content: center;
|
|
14
|
+
align-items: center;
|
|
15
|
+
height: 100vh;
|
|
16
|
+
margin: 0;
|
|
17
|
+
color: var(--text);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.chat-container {
|
|
21
|
+
width: 100%;
|
|
22
|
+
max-width: 400px;
|
|
23
|
+
background: var(--chat-bg);
|
|
24
|
+
border-radius: 12px;
|
|
25
|
+
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
height: 600px;
|
|
29
|
+
overflow: hidden;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
header {
|
|
33
|
+
padding: 1rem;
|
|
34
|
+
border-bottom: 1px solid var(--border);
|
|
35
|
+
display: flex;
|
|
36
|
+
justify-content: space-between;
|
|
37
|
+
align-items: center;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
h1 {
|
|
41
|
+
margin: 0;
|
|
42
|
+
font-size: 1.25rem;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.status {
|
|
46
|
+
font-size: 0.875rem;
|
|
47
|
+
color: #64748b;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.status.connected {
|
|
51
|
+
color: #10b981;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.messages {
|
|
55
|
+
flex: 1;
|
|
56
|
+
overflow-y: auto;
|
|
57
|
+
padding: 1rem;
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
gap: 0.5rem;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.message {
|
|
64
|
+
padding: 0.5rem 1rem;
|
|
65
|
+
border-radius: 999px;
|
|
66
|
+
max-width: 80%;
|
|
67
|
+
word-wrap: break-word;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.message.sent {
|
|
71
|
+
background: var(--primary);
|
|
72
|
+
color: white;
|
|
73
|
+
align-self: flex-end;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.message.received {
|
|
77
|
+
background: #f1f5f9;
|
|
78
|
+
align-self: flex-start;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
form {
|
|
82
|
+
padding: 1rem;
|
|
83
|
+
border-top: 1px solid var(--border);
|
|
84
|
+
display: flex;
|
|
85
|
+
gap: 0.5rem;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
input {
|
|
89
|
+
flex: 1;
|
|
90
|
+
padding: 0.75rem;
|
|
91
|
+
border: 1px solid var(--border);
|
|
92
|
+
border-radius: 999px;
|
|
93
|
+
outline: none;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
input:focus {
|
|
97
|
+
border-color: var(--primary);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
button {
|
|
101
|
+
background: var(--primary);
|
|
102
|
+
color: white;
|
|
103
|
+
border: none;
|
|
104
|
+
padding: 0.75rem 1.5rem;
|
|
105
|
+
border-radius: 999px;
|
|
106
|
+
cursor: pointer;
|
|
107
|
+
font-weight: 600;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
button:hover {
|
|
111
|
+
opacity: 0.9;
|
|
112
|
+
}
|
package/index.js
CHANGED
|
@@ -3,7 +3,7 @@ class Reachlo {
|
|
|
3
3
|
constructor(apiKey, options = {}) {
|
|
4
4
|
this.apiKey = apiKey;
|
|
5
5
|
// Default to production URL if none provided
|
|
6
|
-
this.url = options.url || 'wss://
|
|
6
|
+
this.url = options.url || 'wss://friendly-octo-barnacle.fly.dev';
|
|
7
7
|
this.socket = null;
|
|
8
8
|
this.channels = new Map();
|
|
9
9
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reachlo",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Real-time infrastructure for AI streaming.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -9,5 +9,13 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
11
|
},
|
|
12
|
-
"keywords": [
|
|
13
|
-
|
|
12
|
+
"keywords": [
|
|
13
|
+
"websocket",
|
|
14
|
+
"realtime",
|
|
15
|
+
"ai",
|
|
16
|
+
"streaming",
|
|
17
|
+
"llm",
|
|
18
|
+
"pusher-alternative",
|
|
19
|
+
"pubsub"
|
|
20
|
+
]
|
|
21
|
+
}
|