@syncar/server 1.0.0-alpha.1 → 1.0.0-alpha.2

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 CHANGED
@@ -1,139 +1,206 @@
1
- # @synca/server
1
+ # @syncar/server
2
2
 
3
- > Node.js WebSocket server for real-time synchronization with pub/sub broadcasting and composable middleware.
3
+ > Real-time WebSocket server with pub/sub channels and composable middleware.
4
4
 
5
- [![npm version](https://badge.fury.io/js/%40synca%2Fserver.svg)](https://www.npmjs.com/package/@synca/server)
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![npm version](https://badge.fury.io/js/%40syncar%2Fserver.svg)](https://www.npmjs.com/package/@syncar/server)
6
+ ![MIT License](https://img.shields.io/badge/license-MIT-blue)
7
7
 
8
- ## Features
8
+ ## Why Syncar?
9
9
 
10
- - **Real-time WebSocket Communication** - Fast, bidirectional messaging powered by `ws`.
11
- - **Composable Middleware** - Hono-style middleware for auth, logging, rate limiting, and more.
12
- - **Broadcast & Multicast Channels** - Topic-based messaging patterns with automatic chunking.
13
- - **Handshake Authentication** - Dedicated hook for authenticating clients during connection.
14
- - **Type-Safe API** - Full TypeScript support for messages, context, and state.
15
- - **Automatic Chunking** - Handles high-volume broadcasts without blocking the event loop.
10
+ - **Simple API** Create servers in 3 lines of code
11
+ - **Type-safe** Full TypeScript support
12
+ - **Flexible Channels** Broadcast (all clients) or Multicast (subscribers only)
13
+ - **Middleware** — Hono-style composable middleware for auth, logging, rate limiting
14
+ - **Production Ready** 97%+ test coverage, automatic reconnection, chunked broadcasts
16
15
 
17
16
  ## Installation
18
17
 
19
18
  ```bash
20
- npm install @synca/server
19
+ npm install @syncar/server
21
20
  ```
22
21
 
23
22
  ## Quick Start
24
23
 
25
24
  ```typescript
26
- import { createSyncaServer } from '@synca/server'
25
+ import { createSyncarServer } from '@syncar/server'
27
26
 
28
- const server = createSyncaServer({ port: 3000 })
29
-
30
- // 1. Add Middleware
31
- server.use(async (c, next) => {
32
- console.log(`[${c.req.action}] client:${c.req.client?.id}`)
33
- await next()
34
- })
27
+ // Create and start server
28
+ const server = createSyncarServer({ port: 3000 })
29
+ await server.start()
35
30
 
36
- // 2. Create Channels
37
- const chat = server.createMulticast<string>('chat')
31
+ // Create a chat channel (multicast - subscribers only)
32
+ const chat = server.createMulticast<{ text: string; user: string }>('chat')
38
33
 
39
- // Optional: Custom message handling (disables auto-relay)
34
+ // Handle incoming messages
40
35
  chat.onMessage((data, client) => {
41
- console.log(`Received: ${data}`)
42
- chat.publish(`User said: ${data}`, { exclude: [client.id] })
36
+ console.log(`${client.id}: ${data.text}`)
37
+ chat.publish(data, { exclude: [client.id] }) // Broadcast to others
43
38
  })
39
+ ```
44
40
 
45
- // 3. Start Server
46
- await server.start()
41
+ ## Core Concepts
42
+
43
+ ### Channels
44
+
45
+ | Type | Description | Use Case |
46
+ | ----------- | ------------------------------------ | ----------------------------------- |
47
+ | `Broadcast` | Sends to **all** connected clients | System announcements, notifications |
48
+ | `Multicast` | Sends to **subscribed** clients only | Chat rooms, topic-based feeds |
49
+
50
+ ```typescript
51
+ // Broadcast - everyone receives
52
+ const broadcast = server.createBroadcast<string>()
53
+ broadcast.publish('Server maintenance in 5 minutes')
54
+
55
+ // Multicast - only subscribers receive
56
+ const chat = server.createMulticast<Message>('chat')
57
+ chat.publish({ text: 'Hello', user: 'Alice' })
47
58
  ```
48
59
 
49
- ## Middleware
60
+ ### Client Connection
61
+
62
+ ```typescript
63
+ // WebSocket connect
64
+ const ws = new WebSocket('ws://localhost:3000')
65
+
66
+ // Subscribe to multicast channel
67
+ ws.send(JSON.stringify({ action: 'subscribe', channel: 'chat' }))
68
+
69
+ // Send message to channel
70
+ ws.send(
71
+ JSON.stringify({
72
+ action: 'message',
73
+ channel: 'chat',
74
+ data: { text: 'Hello' },
75
+ }),
76
+ )
77
+ ```
50
78
 
51
- Synca uses a powerful middleware system inspired by Hono. Middleware can intercept `connect`, `disconnect`, `message`, `subscribe`, and `unsubscribe` actions.
79
+ ## Middleware
52
80
 
53
- ### Built-in Middleware
81
+ Add middleware globally or per-channel:
54
82
 
55
83
  ```typescript
56
- import {
57
- createAuthMiddleware,
58
- createLoggingMiddleware,
59
- createRateLimitMiddleware
60
- } from '@synca/server'
61
-
62
- // Global Auth
63
- server.use(createAuthMiddleware({
64
- verifyToken: async (token) => ({ id: '123', name: 'User' })
65
- }))
66
-
67
- // Channel-specific Middleware
68
- const adminChannel = server.createMulticast('admin')
69
- adminChannel.use(async (c, next) => {
70
- if (c.get('user')?.role !== 'admin') {
71
- return c.reject('Unauthorized')
72
- }
73
- await next()
84
+ import { createAuthMiddleware, createRateLimitMiddleware } from '@syncar/server'
85
+
86
+ const server = createSyncarServer({
87
+ port: 3000,
88
+ middleware: [
89
+ createAuthMiddleware({
90
+ verifyToken: async (token) => verifyJwt(token),
91
+ getToken: (ctx) => ctx.message?.data?.token,
92
+ }),
93
+ createRateLimitMiddleware({ maxRequests: 100, windowMs: 60000 }),
94
+ ],
95
+ })
96
+
97
+ // Channel-specific middleware
98
+ const admin = server.createMulticast('admin')
99
+ admin.use(async (c, next) => {
100
+ if (c.get('user')?.role !== 'admin') return c.reject('Unauthorized')
101
+ await next()
74
102
  })
75
103
  ```
76
104
 
77
- ## Handshake Authentication
105
+ Built-in middleware: `createAuthMiddleware`, `createLoggingMiddleware`, `createRateLimitMiddleware`, `createChannelWhitelistMiddleware`
78
106
 
79
- Validate clients before the WebSocket connection is even established.
107
+ ## Server Options
80
108
 
81
109
  ```typescript
82
- server.authenticate(async (request) => {
83
- const token = request.headers['authorization']
84
- if (!token) throw new Error('Missing token')
85
-
86
- const userId = await verify(token)
87
- return userId // This becomes the client.id
110
+ createSyncarServer({
111
+ port: 3000, // Server port
112
+ host: '0.0.0.0', // Bind address
113
+ path: '/syncar', // WebSocket endpoint
114
+ enablePing: true, // Auto ping/pong
115
+ pingInterval: 30000, // Ping interval (ms)
116
+ broadcastChunkSize: 500, // Chunk size for large broadcasts
117
+ logger: console, // Custom logger
118
+ middleware: [], // Global middleware
88
119
  })
89
120
  ```
90
121
 
91
- ## Channels
92
-
93
- ### Broadcast Channel
94
- Sends messages to **all** connected clients. No subscription needed.
122
+ ## Server Lifecycle
95
123
 
96
124
  ```typescript
97
- const broadcast = server.createBroadcast<string>()
98
- broadcast.publish('Global alert!')
125
+ // Start server
126
+ await server.start()
127
+
128
+ // Get statistics
129
+ const stats = server.getStats()
130
+ // { clientCount, channelCount, subscriptionCount, startedAt }
131
+
132
+ // Stop server (closes all connections)
133
+ await server.stop()
99
134
  ```
100
135
 
101
- ### Multicast Channel
102
- Topic-based messaging for **subscribed** clients.
136
+ ## With Existing HTTP Server
103
137
 
104
138
  ```typescript
105
- const room = server.createMulticast<string>('room-1')
139
+ import { createServer } from 'http'
140
+ import { Syncar } from '@syncar/server'
106
141
 
107
- // Manual subscription
108
- room.subscribe('client-id')
142
+ const httpServer = createServer()
143
+ const server = new Syncar({ server: httpServer })
109
144
 
110
- // Message handling (with auto-relay if no handler is set)
111
- room.onMessage((data, client) => {
112
- // data is typed
113
- })
145
+ await server.start()
146
+ httpServer.listen(3000)
114
147
  ```
115
148
 
116
149
  ## API Reference
117
150
 
118
- ### Server API
119
- | Method | Description |
120
- | :--- | :--- |
121
- | `start()` | Starts the server. |
122
- | `stop()` | Stops the server. |
123
- | `use(middleware)` | Registers global middleware. |
124
- | `authenticate(hook)` | Sets the handshake authentication hook. |
125
- | `createBroadcast<T>()` | Gets/creates the global broadcast channel. |
126
- | `createMulticast<T>(name)` | Gets/creates a named multicast channel. |
127
- | `getStats()` | Returns active clients, channels, and subscriptions. |
128
-
129
- ### Channel API
130
- | Method | Description |
131
- | :--- | :--- |
132
- | `publish(data, options?)` | Sends message to subscribers. |
133
- | `onMessage(handler)` | Registers a custom message handler. |
134
- | `use(middleware)` | Registers channel-specific middleware. |
135
- | `subscribe(clientId)` | Manually subscribes a client. |
136
- | `unsubscribe(clientId)` | Manually unsubscribes a client. |
151
+ ### Syncar Class
152
+
153
+ ```typescript
154
+ // Lifecycle
155
+ start(): Promise<void>
156
+ stop(): Promise<void>
157
+
158
+ // Channels
159
+ createBroadcast<T>(): BroadcastChannel<T>
160
+ createMulticast<T>(name: string): MulticastChannel<T>
161
+ hasChannel(name: string): boolean
162
+ getChannels(): string[]
163
+
164
+ // Middleware & Auth
165
+ use(middleware: Middleware): void
166
+ authenticate(hook: (request: IncomingMessage) => Promise<string>): void
167
+
168
+ // Utilities
169
+ getStats(): ServerStats
170
+ getConfig(): Readonly<ServerConfig>
171
+ getRegistry(): ClientRegistry
172
+ ```
173
+
174
+ ### Channel Methods (Broadcast/Multicast)
175
+
176
+ ```typescript
177
+ // Publishing
178
+ publish(data: T, options?: { exclude?: string[], to?: string[] }): Promise<void>
179
+
180
+ // Handlers
181
+ onMessage(handler: (data: T, client: Client) => void): void
182
+
183
+ // Middleware
184
+ use(middleware: Middleware): void
185
+
186
+ // Subscription (Multicast only)
187
+ subscribe(clientId: string): void
188
+ unsubscribe(clientId: string): void
189
+ ```
190
+
191
+ ## Error Types
192
+
193
+ ```typescript
194
+ import {
195
+ ConfigError, // Invalid configuration
196
+ TransportError, // WebSocket connection issues
197
+ ChannelError, // Channel operation errors
198
+ ClientError, // Client-specific errors
199
+ ValidationError, // Invalid input data
200
+ StateError, // Invalid server state
201
+ MiddlewareRejectionError, // Middleware blocked action
202
+ } from '@syncar/server'
203
+ ```
137
204
 
138
205
  ## License
139
206