@owlmeans/socket 0.1.2 → 0.1.4

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.
Files changed (3) hide show
  1. package/README.md +41 -391
  2. package/package.json +6 -5
  3. package/tsconfig.json +6 -10
package/README.md CHANGED
@@ -1,434 +1,84 @@
1
1
  # @owlmeans/socket
2
2
 
3
- Common WebSocket communication library for OwlMeans applications. This package provides a unified abstraction for real-time communication across server, web, and mobile environments with support for RPC calls, event handling, authentication, and message queuing.
3
+ Shared WebSocket connection types and message protocol for OwlMeans real-time communication.
4
4
 
5
5
  ## Overview
6
6
 
7
- The `@owlmeans/socket` package provides:
8
-
9
- - **Connection Abstraction**: Unified interface for WebSocket connections across platforms
10
- - **RPC Communication**: Remote procedure call support with timeout and error handling
11
- - **Event System**: Publish/subscribe event handling for real-time updates
12
- - **Authentication Integration**: Built-in authentication flow support
13
- - **Message Queuing**: Queue management for reliable message delivery
14
- - **Request/Response Pattern**: Structured request/response communication
15
- - **Error Handling**: Comprehensive error handling with resilient error types
7
+ - Defines the `Connection` interface used by both server and client socket implementations
8
+ - `MessageType` enum covers all message categories: Call, Result, Event, Request, Response, Auth, System
9
+ - `EventMessage<T>` is the typed event payload received by `connection.observe()`
10
+ - Used in viable for real-time thinking journal updates and file watching
16
11
 
17
12
  ## Installation
18
13
 
19
14
  ```bash
20
- npm install @owlmeans/socket
21
- ```
22
-
23
- ## Core Concepts
24
-
25
- ### Connection Interface
26
-
27
- The `Connection` interface provides a unified API for WebSocket communication, supporting various message types and communication patterns.
28
-
29
- ### Message Types
30
-
31
- Different message types enable various communication patterns:
32
- - **Call/Result**: RPC-style method calls with responses
33
- - **Request/Response**: Structured request/response patterns
34
- - **Event**: Publish/subscribe event notifications
35
- - **Auth**: Authentication-specific messages
36
-
37
- ### Authentication Integration
38
-
39
- Built-in support for authentication flows with stage-based progression and secure communication.
40
-
41
- ## API Reference
42
-
43
- ### Types
44
-
45
- #### `Connection`
46
- Core connection interface for WebSocket communication.
47
-
48
- ```typescript
49
- interface Connection {
50
- stage: AuthenticationStage // Current authentication stage
51
- notify: <T>(event: string, payload: T) => Promise<void> // Send events
52
- observe: <T>(event: string, handler: (event: EventMessage<T>) => Promise<void>) => () => void // Listen to events
53
- call: <R, T extends any[]>(method: string, ...payload: T) => Promise<R> // RPC calls
54
- perform: <R, T extends any[]>(method: string, handler: CallHendler<R, T>) => void // Handle RPC calls
55
- request: <T, R>(payload: T, observer?: (payload: R) => Promise<boolean>) => Promise<() => void> // Send requests
56
- reply: <T>(id: string, payload: T) => Promise<void> // Reply to requests
57
- auth: <T, R>(stage: AuthenticationStage, payload: T) => Promise<R> // Authentication
58
- close: () => Promise<void> // Close connection
59
- }
15
+ bun add @owlmeans/socket
60
16
  ```
61
17
 
62
- #### `Message<T>`
63
- Base message structure for all communication.
64
-
65
- ```typescript
66
- interface Message<T> {
67
- type: MessageType // Message type identifier
68
- id?: string // Unique message ID
69
- sender?: string // Sender identifier
70
- recipient?: string // Recipient identifier
71
- dt?: number // Timestamp
72
- payload: T // Message payload
73
- }
74
- ```
18
+ ## Usage
75
19
 
76
- #### `MessageType`
77
- Enumeration of supported message types.
20
+ Send a typed event and observe responses:
78
21
 
79
22
  ```typescript
80
- enum MessageType {
81
- Call = 'call', // RPC method calls
82
- Result = 'result', // RPC method results
83
- Error = 'error', // Error responses
84
- Request = 'request', // Request messages
85
- Response = 'response', // Response messages
86
- Event = 'event', // Event notifications
87
- Message = 'message', // General messages
88
- Auth = 'auth', // Authentication messages
89
- System = 'system' // System messages
90
- }
91
- ```
92
-
93
- ## Usage Examples
94
-
95
- ### Basic Connection Usage
23
+ import type { EventMessage, Connection } from '@owlmeans/socket'
24
+ import { MessageType } from '@owlmeans/socket'
96
25
 
97
- ```typescript
98
- import { Connection, MessageType } from '@owlmeans/socket'
99
-
100
- // Assuming connection is established
101
- const connection: Connection = await createConnection()
102
-
103
- // Send an event
104
- await connection.notify('user-online', { userId: '123', status: 'active' })
105
-
106
- // Listen for events
107
- const unsubscribe = connection.observe('chat-message', async (event) => {
108
- console.log('New message:', event.payload)
26
+ // Observe events on a connection
27
+ const unsubscribe = connection.observe<FileUpdate>('file-update', async (event: EventMessage<FileUpdate>) => {
28
+ console.log('file updated:', event.payload)
109
29
  })
110
30
 
111
- // Make RPC call
112
- const result = await connection.call('getUserProfile', '123')
113
- console.log('User profile:', result)
114
-
115
- // Handle RPC calls
116
- connection.perform('echo', async (message: string) => {
117
- return `Echo: ${message}`
118
- })
31
+ // Notify connected clients
32
+ await connection.notify('file-update', { path: '/src/app.ts', content: '...' })
119
33
  ```
120
34
 
121
- ### Event System
35
+ RPC call over WebSocket:
122
36
 
123
37
  ```typescript
124
- // Publisher
125
- await connection.notify('order-status-changed', {
126
- orderId: 'order-123',
127
- status: 'shipped',
128
- timestamp: Date.now()
129
- })
130
-
131
- // Subscriber
132
- const unsubscribe = connection.observe('order-status-changed', async (event) => {
133
- const { orderId, status } = event.payload
134
- console.log(`Order ${orderId} is now ${status}`)
135
-
136
- // Update UI or trigger other actions
137
- await updateOrderDisplay(orderId, status)
138
- })
139
-
140
- // Cleanup
141
- unsubscribe()
38
+ const result = await connection.call<ProjectSlot>('project.slot', projectId)
142
39
  ```
143
40
 
144
- ### RPC Communication
41
+ Checking the message type in a raw message handler:
145
42
 
146
43
  ```typescript
147
- // Client-side: Make calls
148
- try {
149
- const users = await connection.call('getUsers', { page: 1, limit: 10 })
150
- const user = await connection.call('getUserById', '123')
151
- const updated = await connection.call('updateUser', '123', { name: 'John Doe' })
152
- } catch (error) {
153
- console.error('RPC call failed:', error)
154
- }
44
+ import { MessageType } from '@owlmeans/socket'
155
45
 
156
- // Server-side: Handle calls
157
- connection.perform('getUsers', async (options: { page: number, limit: number }) => {
158
- const users = await userService.list(options)
159
- return users
160
- })
161
-
162
- connection.perform('getUserById', async (id: string) => {
163
- const user = await userService.get(id)
164
- if (!user) {
165
- throw new Error('User not found')
166
- }
167
- return user
168
- })
169
-
170
- connection.perform('updateUser', async (id: string, data: Partial<User>) => {
171
- return await userService.update(id, data)
172
- })
173
- ```
174
-
175
- ### Request/Response Pattern
176
-
177
- ```typescript
178
- // Send request and handle responses
179
- const unsubscribe = await connection.request(
180
- { action: 'stream-data', filters: { category: 'important' } },
181
- async (response) => {
182
- console.log('Received chunk:', response)
183
- // Return true to continue receiving, false to stop
184
- return response.hasMore
185
- }
186
- )
187
-
188
- // Handle incoming requests
189
- const unsubscribeHandler = connection.acknowledge(async (id: string, payload: any) => {
190
- const { action, filters } = payload
191
-
192
- if (action === 'stream-data') {
193
- // Process request and send responses
194
- const chunks = await getDataChunks(filters)
195
-
196
- for (const chunk of chunks) {
197
- await connection.reply(id, {
198
- data: chunk,
199
- hasMore: chunk.index < chunks.length - 1
200
- })
201
- }
202
-
203
- return true // Request handled
204
- }
205
-
206
- return false // Request not handled
207
- })
208
- ```
209
-
210
- ### Authentication Flow
211
-
212
- ```typescript
213
- // Authenticate connection
214
- try {
215
- // Start authentication
216
- let stage = AuthenticationStage.Init
217
- let result = await connection.auth(stage, { clientId: 'my-app' })
218
-
219
- // Continue authentication based on challenge
220
- if (result.challenge) {
221
- stage = AuthenticationStage.Authenticate
222
- result = await connection.auth(stage, {
223
- response: await generateAuthResponse(result.challenge)
224
- })
225
- }
226
-
227
- console.log('Authentication successful:', result)
228
- } catch (error) {
229
- console.error('Authentication failed:', error)
46
+ if (message.type === MessageType.Event) {
47
+ // handle event
230
48
  }
231
-
232
- // Check authentication status
233
- if (connection.stage === AuthenticationStage.Authenticated) {
234
- // Perform authenticated operations
235
- await connection.call('getProtectedData')
236
- }
237
- ```
238
-
239
- ### Message Queuing
240
-
241
- ```typescript
242
- // Enqueue messages for delivery
243
- await connection.enqueue({
244
- type: 'user-notification',
245
- userId: '123',
246
- message: 'Welcome!'
247
- })
248
-
249
- await connection.enqueue({
250
- type: 'system-alert',
251
- level: 'warning',
252
- text: 'Maintenance scheduled'
253
- }, 'maintenance-alert-1')
254
-
255
- // Check queue status
256
- const queueSize = connection.enqueued()
257
- console.log(`${queueSize} messages queued`)
258
-
259
- // Consume queued messages
260
- const consumed = connection.consume()
261
- if (consumed) {
262
- const [payload, id, remaining] = consumed
263
- console.log('Consumed message:', payload, 'ID:', id, 'Remaining:', remaining)
264
- }
265
-
266
- // Consume with filter
267
- const alertsOnly = connection.consume((payload: any) => payload.type === 'system-alert')
268
- ```
269
-
270
- ### Connection Lifecycle
271
-
272
- ```typescript
273
- // Listen to connection events
274
- const unsubscribeListener = connection.listen(async (message) => {
275
- console.log('Connection message:', message)
276
-
277
- // Handle connection-level events
278
- if (typeof message === 'string') {
279
- console.log('Raw message:', message)
280
- } else {
281
- switch (message.type) {
282
- case MessageType.System:
283
- console.log('System message:', message.payload)
284
- break
285
- case MessageType.Error:
286
- console.error('Connection error:', message.payload)
287
- break
288
- }
289
- }
290
- })
291
-
292
- // Handle connection cleanup
293
- const handleConnectionClose = async () => {
294
- // Unsubscribe from events
295
- unsubscribeListener()
296
-
297
- // Clean up resources
298
- await connection.close()
299
- }
300
-
301
- // Handle process termination
302
- process.on('SIGTERM', handleConnectionClose)
303
- process.on('SIGINT', handleConnectionClose)
304
49
  ```
305
50
 
306
- ### Error Handling
51
+ ## API
307
52
 
308
- ```typescript
309
- import { SocketError } from '@owlmeans/socket'
310
-
311
- try {
312
- await connection.call('riskyOperation', data)
313
- } catch (error) {
314
- if (error instanceof SocketError) {
315
- console.error('Socket error:', error.message)
316
-
317
- // Handle specific socket errors
318
- switch (error.code) {
319
- case 'TIMEOUT':
320
- console.log('Call timed out')
321
- break
322
- case 'CONNECTION_LOST':
323
- console.log('Connection lost, attempting reconnect...')
324
- await reconnectSocket()
325
- break
326
- case 'AUTH_FAILED':
327
- console.log('Authentication failed')
328
- await reauthenticate()
329
- break
330
- }
331
- }
332
- }
333
- ```
334
-
335
- ## Advanced Features
53
+ ### `Connection`
336
54
 
337
- ### Custom Message Preparation
55
+ The main interface for WebSocket connections. Key methods:
338
56
 
339
- ```typescript
340
- // Implement custom message preparation
341
- const customConnection: Connection = {
342
- ...baseConnection,
343
-
344
- prepare: <T>(message: Message<T>, isRequest?: boolean) => {
345
- // Add custom headers or encryption
346
- return {
347
- ...message,
348
- sender: 'my-service',
349
- dt: Date.now(),
350
- // Add custom processing
351
- }
352
- }
353
- }
354
- ```
57
+ - `notify<T>(event, payload)` — emit an event to the other side
58
+ - `observe<T>(event, handler)` subscribe to events; returns unsubscribe function
59
+ - `call<R, T[]>(method, ...payload)` — make an RPC call and await the result
60
+ - `perform<R, T[]>(method, handler)` — register an RPC handler
61
+ - `request<T, R>(payload, observer?)` — send a streaming request
62
+ - `auth<T, R>(stage, payload)` perform a WebSocket auth handshake step
63
+ - `stage: AuthenticationStage` current auth state of the connection
355
64
 
356
- ### Timeout Configuration
65
+ ### `MessageType`
357
66
 
358
67
  ```typescript
359
- // Set default timeout
360
- connection.defaultCallTimeout = 30000 // 30 seconds
361
-
362
- // Use custom timeout for specific calls
363
- try {
364
- const result = await connection.call('longRunningOperation', data)
365
- } catch (error) {
366
- if (error.message.includes('timeout')) {
367
- console.log('Operation timed out')
368
- }
68
+ enum MessageType {
69
+ Call, Result, Error, Request, Response, Event, Message, Auth, System
369
70
  }
370
71
  ```
371
72
 
372
- ### Connection Multiplexing
373
-
374
- ```typescript
375
- // Handle multiple concurrent operations
376
- const operations = [
377
- connection.call('operation1', data1),
378
- connection.call('operation2', data2),
379
- connection.call('operation3', data3)
380
- ]
381
-
382
- const results = await Promise.allSettled(operations)
383
- results.forEach((result, index) => {
384
- if (result.status === 'fulfilled') {
385
- console.log(`Operation ${index + 1} succeeded:`, result.value)
386
- } else {
387
- console.error(`Operation ${index + 1} failed:`, result.reason)
388
- }
389
- })
390
- ```
391
-
392
- ## Integration with OwlMeans Ecosystem
393
-
394
- The `@owlmeans/socket` package integrates with:
395
-
396
- - **@owlmeans/auth**: Authentication stages and flows
397
- - **@owlmeans/error**: Resilient error handling
398
- - **@owlmeans/client-socket**: Client-side WebSocket implementation
399
- - **@owlmeans/server-socket**: Server-side WebSocket implementation
400
- - **@owlmeans/context**: Service registration and lifecycle management
401
-
402
- ## Constants
403
-
404
- ```typescript
405
- const CALL_TIMEOUT = 60000 // Default RPC call timeout (60 seconds)
406
- ```
407
-
408
- ## Best Practices
73
+ ### `EventMessage<T>`
409
74
 
410
- ### Connection Management
411
- - Always handle connection lifecycle events
412
- - Implement proper reconnection logic
413
- - Clean up event listeners on disconnect
414
- - Use appropriate timeouts for different operations
75
+ The payload structure for `observe()` handlers: `{ type, payload: T, ... }`.
415
76
 
416
- ### Error Handling
417
- - Implement comprehensive error handling for all communication patterns
418
- - Use appropriate retry strategies for failed operations
419
- - Log connection events for debugging
420
- - Handle authentication failures gracefully
77
+ ### `CALL_TIMEOUT`
421
78
 
422
- ### Performance
423
- - Use appropriate message batching for high-frequency events
424
- - Implement efficient event filtering
425
- - Consider message compression for large payloads
426
- - Monitor connection performance and adjust timeouts
79
+ Default RPC call timeout in milliseconds (60 000).
427
80
 
428
- ### Security
429
- - Always authenticate connections before sensitive operations
430
- - Validate all incoming messages and payloads
431
- - Use secure WebSocket connections (WSS) in production
432
- - Implement proper authorization checks for RPC methods
81
+ ## Related Packages
433
82
 
434
- Fixes #32.
83
+ - [`@owlmeans/server-socket`](../server-socket) — server-side connection implementation
84
+ - [`@owlmeans/client-socket`](../client-socket) — client-side connection implementation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/socket",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -21,14 +21,15 @@
21
21
  }
22
22
  },
23
23
  "dependencies": {
24
- "@owlmeans/auth": "^0.1.2",
25
- "@owlmeans/basic-ids": "^0.1.2",
26
- "@owlmeans/error": "^0.1.2"
24
+ "@owlmeans/auth": "^0.1.4",
25
+ "@owlmeans/basic-ids": "^0.1.4",
26
+ "@owlmeans/error": "^0.1.4"
27
27
  },
28
28
  "devDependencies": {
29
+ "@owlmeans/dep-config": "workspace:*",
29
30
  "nodemon": "^3.1.11",
30
31
  "npm-check": "^6.0.1",
31
- "typescript": "^5.8.3"
32
+ "typescript": "^6.0.2"
32
33
  },
33
34
  "publishConfig": {
34
35
  "access": "public"
package/tsconfig.json CHANGED
@@ -1,15 +1,11 @@
1
1
  {
2
2
  "extends": [
3
- "../tsconfig.default.json",
4
- "../tsconfig.react.json",
3
+ "@owlmeans/dep-config/tsconfig.base.json",
4
+ "@owlmeans/dep-config/tsconfig.react.json"
5
5
  ],
6
6
  "compilerOptions": {
7
- "rootDir": "./src/", /* Specify the root folder within your source files. */
8
- "outDir": "./build/", /* Specify an output folder for all emitted files. */
7
+ "rootDir": "./src/",
8
+ "outDir": "./build/"
9
9
  },
10
- "exclude": [
11
- "./dist/**/*",
12
- "./build/**/*",
13
- "./*.ts"
14
- ]
15
- }
10
+ "exclude": ["./dist/**/*", "./build/**/*", "./*.ts"]
11
+ }