@sejatordev/ws-client
v1.0.0
Published
WebSocket client ringan dengan konsep **channel-based** (mirip Pusher), mendukung **auto reconnect**, **manual reconnect**, **heartbeat**, dan **pong timeout**.
Readme
@sejator/ws-client
WebSocket client ringan dengan konsep channel-based (mirip Pusher), mendukung auto reconnect, manual reconnect, heartbeat, dan pong timeout.
Cocok untuk:
- Real-time order & notifikasi
- Dashboard admin
- Public / private channel
- Browser & bundler modern (ESM / UMD)
✨ Fitur
- 🔌 Auto connect & auto reconnect
- 🔁 Manual reconnect API
- ❤️ Heartbeat + pong timeout protection
- 📡 Channel & event system
- 🔄 Auto re-subscribe saat reconnect
- 🔐 Private channel authentication
- 🛡️ CSRF token support (cookie-based)
- 🧠 Fully typed event (TypeScript)
- 🌐 URL auto normalize (http → ws, /ws)
🔗 Implementasi (SDK untuk @sejator/ws-server)
@sejator/ws-client dirancang khusus sebagai SDK resmi untuk berkomunikasi dengan WebSocket Server @sejator/ws-server.
Client ini mengikuti penuh protokol, event, dan format payload yang digunakan oleh @sejator/ws-server, sehingga:
- ✅ Plug & Play (tanpa konfigurasi rumit)
- ✅ Auto kompatibel dengan:
- Channel system
- Private channel authentication
- Heartbeat & pong
- Reconnect strategy
- ❌ Tidak ditujukan untuk WebSocket server lain yang tidak mengikuti spesifikasi
@sejator/ws-server
⚠️ PENTING
Pastikan backend WebSocket kamu menggunakan@sejator/ws-server, karena:
- Event seperti
connect_success,auth_failed,pong, dll- Struktur auth (
APP_KEY:signature)- Endpoint default (
/ws)
Semuanya bergantung pada implementasi server tersebut.
🔄 Arsitektur Client ↔ Server
Browser / Frontend
│
│ @sejator/ws-client
▼
WebSocket Protocol (Channel-based)
│
│ @sejator/ws-server
▼
Application Backend⚙️ Cara Kerja
- Client melakukan koneksi ke endpoint WebSocket server (
/ws) - Server membalas dengan:
socket_idactivity_timeout
- Client:
- Menjaga koneksi dengan heartbeat
- Auto reconnect jika terputus
- Saat subscribe
private-*channel:- Client meminta auth ke backend
- Server memverifikasi signature
- Event dari server langsung dipetakan ke channel client
📦 Instalasi
✅ Opsi 1 — Clone dari GitHub (Recommended)
git clone https://github.com/sejator/ws-client.git
cd ws-client
npm install
npm run build
Hasil build tersedia di folder:
dist/
├─ ws-client.es.js
├─ ws-client.umd.js
├─ index.d.ts✅ Opsi 2 — Import manual ke project (ESM)
Copy file hasil build ke project kamu:
dist/ws-client.es.jsLalu import:
import { WSClient } from '@sejator/ws-client';✅ Opsi 3 — Browser (UMD tanpa bundler)
Gunakan file UMD hasil build (ws-client.umd.js):
<script src="dist/ws-client.umd.js"></script>
<script>
const { WSClient } = window.WSClient;
</script>🚀 Penggunaan
1️⃣ ESM (Vite / Next.js / Node modern)
import { WSClient } from '@sejator/ws-client';
const client = new WSClient('http://localhost:3000', {
key: 'YOUR_APP_KEY',
logger: true,
});
client.on('connect_success', (data) => {
console.log('Connected with socket id:', data.socket_id);
});
client.on('state_change', ({ previous, current }) => {
console.log('State:', previous, '→', current);
});
client.on('reconnecting', ({ manual }) => {
console.log('Reconnecting...', manual ? '(manual)' : '(auto)');
});
client.on('auth_failed', (err) => {
console.error('Auth failed:', err);
});
client.on('error', (err) => {
console.error('WebSocket error', err);
});
const channel = client.subscribe('public-orders');
channel.bind('order.created', (payload) => {
console.log('Order created:', payload);
});
channel.bindAll((event, data) => {
console.log('Event All:', event, data);
});
// unsubscribe dari channel
channel.unsubscribe();
// remove event dari channel
channel.unbind('order.created');2️⃣ UMD (Browser tanpa bundler)
<script src="/dist/ws-client.umd.js"></script>
<script>
const { WSClient } = window.WSClient;
const client = new WSClient('http://localhost:3000', {
key: 'YOUR_APP_KEY',
logger: true,
});
client.on('connect_success', () => {
console.log('Connected...');
});
const channel = client.subscribe('public-orders');
channel.bind('order.created', (data) => {
console.log('Order created:', data);
});
</script>📌 Namespace UMD: window.WSClient
📺 Public Channel
const channel = client.subscribe('public-orders');
atau;
const channel = client.subscribe('orders');
channel.bind('order.created', (data) => {
console.log(data);
});
channel.unbind('order.created');🔐 Private Channel
Channel dengan prefix private- memerlukan auth token dari backend.
const channel = client.subscribe('private-orders');
channel.bind('order.updated', (data) => {
console.log(data);
});🔌 Client Options
interface WSClientOptions {
key: string; // required
logger?: boolean; // default false
reconnect?: boolean; // default true
maxReconnectDelay?: number; // default 30000 (ms)
// 🔐 Auth options
authEndpoint?: string;
authHeaders?: () => Record<string, string>;
auth?: (params: {
socketId: string;
channel: string;
headers?: Readonly<Record<string, string>>;
query?: Record<string, string>;
}) => Promise<{ auth: string }>;
}🔐 Authentication (Auth)
Ada 2 cara untuk melakukan auth private channel.
⚠️ PENTING — Response Backend
Backend WAJIB mengembalikan response JSON dengan minimal field berikut:
{
"data": {
"auth": "APP_KEY:signature_hash"
}
}Format response yang direkomendasikan:
{
"success": true,
"code": 200,
"data": {
"auth": "APP_KEY:signature_hash"
}
}📌 Catatan:
- Field data.auth WAJIB ada dan bertipe string
- Field lain (success, code, dll) opsional
- Jika data.auth tidak ada / null:
- ❌ Subscribe private channel akan gagal
- 🔔 Client memicu event
auth_failed
✅ Opsi 1 — authEndpoint (paling mudah)
Client akan otomatis melakukan POST ke endpoint backend.
const client = new WSClient('http://localhost:3000', {
key: 'YOUR_APP_KEY',
authEndpoint: '/ws/auth',
});Yang dikirim ke backend:
{
"socket_id": "...",
"channel": "private-orders"
}- ✔ Cookie otomatis dikirim
- ✔ CSRF token otomatis ditambahkan (X-XSRF-TOKEN)
✅ Opsi 2 — auth function (fleksibel)
Gunakan jika kamu ingin custom fetch / axios / logic sendiri.
const client = new WSClient('http://localhost:3000', {
key: 'YOUR_APP_KEY',
auth: async ({ socketId, channel, headers }) => {
const res = await fetch('/ws/auth', {
method: 'POST',
credentials: 'include',
headers,
body: JSON.stringify({
socket_id: socketId,
channel,
}),
});
const json = await res.json();
return { auth: json.data.auth };
},
});🛡️ CSRF Protection
Client secara otomatis:
- Mengambil token dari cookie XSRF-TOKEN
- Mengirimkannya sebagai header X-XSRF-TOKEN
Tidak perlu konfigurasi tambahan di client.
📌 Cocok untuk:
- Laravel
- Django
- Express (csurf)
📡 Event Client
| Event | Payload | Deskripsi |
| ----------------- | --------------------------------- | --------------------------------------------- |
| connect_success | { socket_id, activity_timeout } | Koneksi berhasil |
| disconnected | void | Socket terputus |
| reconnecting | { manual: boolean } | Reconnect dimulai |
| auth_failed | string | App key tidak valid/Tidak punya akses channel |
| state_change | { previous, current } | Perubahan state client |
| error | unknown | Error WebSocket |
🔁 Reconnect Strategy
- Exponential backoff
- Auto retry sampai
maxReconnectDelay - Manual reconnect tersedia
client.reconnect();❤️ Heartbeat & Pong Timeout
- Client mengirim ping
- Server membalas pong
- Timeout → force reconnect
🌐 URL Normalization
@sejator/ws-client menerima URL HTTP maupun WebSocket, lalu menormalisasikannya otomatis agar sesuai dengan endpoint WebSocket server.
Apa yang dilakukan client?
Client akan:
1. Mengubah protokol:
http://→ws://https://→wss://
2. Menambahkan path WebSocket default /ws
3. Menghapus trailing slash (/) jika ada
Dengan begitu, client selalu terhubung ke endpoint WebSocket yang benar tanpa konfigurasi tambahan.
Contoh
Input URL dari user:
new WSClient('http://localhost:3000', { key: 'APP_KEY' });Akan otomatis dinormalisasi menjadi:
ws://localhost:3000/wsContoh lain:
| Input | URL akhir |
| ------------------------- | -------------------------- |
| https://api.example.com | wss://api.example.com/ws |
| ws://localhost:3000 | ws://localhost:3000/ws |
| localhost:3000 | ws://localhost:3000/ws |
📦 Build
npm run buildOutput:
dist/
├─ ws-client.es.js
├─ ws-client.umd.js
├─ *.map
├─ index.d.tsKontak & Dukungan
Maintainer: @sejator
Email: [email protected]
Donasi: https://saweria.co/sejator
