@owlmeans/server-socket 0.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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +560 -0
  3. package/build/.gitkeep +0 -0
  4. package/build/consts.d.ts +2 -0
  5. package/build/consts.d.ts.map +1 -0
  6. package/build/consts.js +2 -0
  7. package/build/consts.js.map +1 -0
  8. package/build/helper.d.ts +7 -0
  9. package/build/helper.d.ts.map +1 -0
  10. package/build/helper.js +14 -0
  11. package/build/helper.js.map +1 -0
  12. package/build/index.d.ts +6 -0
  13. package/build/index.d.ts.map +1 -0
  14. package/build/index.js +5 -0
  15. package/build/index.js.map +1 -0
  16. package/build/middleware.d.ts +3 -0
  17. package/build/middleware.d.ts.map +1 -0
  18. package/build/middleware.js +25 -0
  19. package/build/middleware.js.map +1 -0
  20. package/build/service.d.ts +5 -0
  21. package/build/service.d.ts.map +1 -0
  22. package/build/service.js +109 -0
  23. package/build/service.js.map +1 -0
  24. package/build/types.d.ts +11 -0
  25. package/build/types.d.ts.map +1 -0
  26. package/build/types.js +2 -0
  27. package/build/types.js.map +1 -0
  28. package/build/utils/connection.d.ts +6 -0
  29. package/build/utils/connection.d.ts.map +1 -0
  30. package/build/utils/connection.js +104 -0
  31. package/build/utils/connection.js.map +1 -0
  32. package/build/utils/index.d.ts +3 -0
  33. package/build/utils/index.d.ts.map +1 -0
  34. package/build/utils/index.js +3 -0
  35. package/build/utils/index.js.map +1 -0
  36. package/build/utils/server.d.ts +5 -0
  37. package/build/utils/server.d.ts.map +1 -0
  38. package/build/utils/server.js +15 -0
  39. package/build/utils/server.js.map +1 -0
  40. package/package.json +46 -0
  41. package/src/consts.ts +2 -0
  42. package/src/helper.ts +21 -0
  43. package/src/index.ts +6 -0
  44. package/src/middleware.ts +32 -0
  45. package/src/service.ts +133 -0
  46. package/src/types.ts +12 -0
  47. package/src/utils/connection.ts +124 -0
  48. package/src/utils/index.ts +3 -0
  49. package/src/utils/server.ts +21 -0
  50. package/tsconfig.json +16 -0
  51. package/tsconfig.tsbuildinfo +1 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 OwlMeans Common — Fullstack typescript framework
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,560 @@
1
+ # @owlmeans/server-socket
2
+
3
+ The **@owlmeans/server-socket** package provides WebSocket server functionality for OwlMeans Common Libraries, designed for fullstack microservices and microclients development with focus on security and proper authentication and authorization.
4
+
5
+ ## Purpose
6
+
7
+ This package serves as the server-side WebSocket implementation that:
8
+
9
+ - **Provides WebSocket server capabilities** using Fastify WebSocket integration
10
+ - **Supports real-time communication** between server and clients
11
+ - **Integrates with module system** for WebSocket route handling
12
+ - **Implements authentication and authorization** for WebSocket connections
13
+ - **Offers connection management** with lifecycle hooks and proper cleanup
14
+ - **Enables bidirectional messaging** with typed message handling
15
+
16
+ ## Core Concepts
17
+
18
+ ### Socket Service
19
+ A service that manages WebSocket server functionality and integrates with the Fastify web server to provide WebSocket endpoints.
20
+
21
+ ### Connection Handling
22
+ Provides abstraction for WebSocket connections with proper lifecycle management, authentication, and error handling.
23
+
24
+ ### Module Integration
25
+ WebSocket endpoints are defined using the OwlMeans module system, allowing for consistent routing, validation, and middleware application.
26
+
27
+ ### Authentication & Authorization
28
+ WebSocket connections can be protected using the same guard and gate system used for HTTP endpoints.
29
+
30
+ ## API Reference
31
+
32
+ ### Services
33
+
34
+ #### `createSocketService(alias?): SocketService`
35
+
36
+ Creates a WebSocket service that can be registered with a server context.
37
+
38
+ ```typescript
39
+ import { createSocketService } from '@owlmeans/server-socket'
40
+
41
+ const socketService = createSocketService('websocket')
42
+ ```
43
+
44
+ **Parameters:**
45
+ - `alias`: string (optional) - Service alias, defaults to `DEFAULT_ALIAS` ('socket-server')
46
+
47
+ **Returns:** SocketService instance
48
+
49
+ #### `SocketService`
50
+
51
+ Interface for the WebSocket service.
52
+
53
+ ```typescript
54
+ interface SocketService extends InitializedService {
55
+ update: (api: ApiServer) => Promise<void>
56
+ }
57
+ ```
58
+
59
+ **Methods:**
60
+ - `update(api)`: Configures the WebSocket server with the provided API server instance
61
+
62
+ ### Helper Functions
63
+
64
+ #### `handleConnection<T>(handler): RefedModuleHandler`
65
+
66
+ Creates a WebSocket connection handler that integrates with the module system.
67
+
68
+ ```typescript
69
+ import { handleConnection } from '@owlmeans/server-socket'
70
+ import type { Connection } from '@owlmeans/socket'
71
+
72
+ const myConnectionHandler = handleConnection<MyConnection>(
73
+ async (conn, ctx, req, res) => {
74
+ // Handle WebSocket connection
75
+ console.log('New WebSocket connection')
76
+
77
+ conn.onMessage(async (message) => {
78
+ console.log('Received:', message)
79
+ await conn.send({ type: 'echo', data: message })
80
+ })
81
+
82
+ conn.onClose(() => {
83
+ console.log('Connection closed')
84
+ })
85
+ }
86
+ )
87
+ ```
88
+
89
+ **Parameters:**
90
+ - `handler`: Function that handles WebSocket connections with signature:
91
+ - `conn`: Connection instance
92
+ - `ctx`: Server context
93
+ - `req`: Abstract request
94
+ - `res`: Abstract response
95
+
96
+ **Returns:** Module handler compatible with OwlMeans modules
97
+
98
+ ### Types
99
+
100
+ #### `Config`
101
+
102
+ Configuration interface extending ServerConfig.
103
+
104
+ ```typescript
105
+ interface Config extends ServerConfig {}
106
+ ```
107
+
108
+ #### `Context<C>`
109
+
110
+ Context interface that extends ServerContext with API server capabilities.
111
+
112
+ ```typescript
113
+ interface Context<C extends Config = Config> extends ServerContext<C>, ApiServerAppend {}
114
+ ```
115
+
116
+ ### Constants
117
+
118
+ #### `DEFAULT_ALIAS`
119
+
120
+ Default alias for the socket service.
121
+
122
+ ```typescript
123
+ const DEFAULT_ALIAS = 'socket-server'
124
+ ```
125
+
126
+ ## Usage Examples
127
+
128
+ ### Basic WebSocket Server Setup
129
+
130
+ ```typescript
131
+ import { makeServerContext, makeServerConfig } from '@owlmeans/server-context'
132
+ import { createSocketService } from '@owlmeans/server-socket'
133
+ import { createApiService } from '@owlmeans/server-api'
134
+ import { AppType } from '@owlmeans/context'
135
+
136
+ // Create server configuration
137
+ const config = makeServerConfig(AppType.Backend, 'websocket-server', {
138
+ host: 'localhost',
139
+ port: 3000
140
+ })
141
+
142
+ // Create context and services
143
+ const context = makeServerContext(config)
144
+ const apiService = createApiService()
145
+ const socketService = createSocketService()
146
+
147
+ // Register services
148
+ context.registerService(apiService)
149
+ context.registerService(socketService)
150
+
151
+ // Configure and initialize
152
+ context.configure()
153
+ await context.init()
154
+
155
+ console.log('WebSocket server running on ws://localhost:3000')
156
+ ```
157
+
158
+ ### WebSocket Module with Authentication
159
+
160
+ ```typescript
161
+ import { module, guard } from '@owlmeans/module'
162
+ import { route } from '@owlmeans/route'
163
+ import { handleConnection } from '@owlmeans/server-socket'
164
+ import type { Connection } from '@owlmeans/socket'
165
+
166
+ // Create WebSocket module with authentication
167
+ const chatModule = module(
168
+ route('chat-socket', '/ws/chat'),
169
+ guard('authenticated')
170
+ )
171
+
172
+ // Set WebSocket handler
173
+ chatModule.handle = handleConnection<Connection>(
174
+ async (conn, ctx, req, res) => {
175
+ const userId = req.auth?.user?.id
176
+
177
+ if (!userId) {
178
+ await conn.close(1008, 'Authentication required')
179
+ return
180
+ }
181
+
182
+ console.log(`User ${userId} connected to chat`)
183
+
184
+ // Join user to chat room
185
+ await joinChatRoom(conn, userId)
186
+
187
+ // Handle incoming messages
188
+ conn.onMessage(async (message) => {
189
+ if (message.type === 'chat-message') {
190
+ await broadcastMessage(userId, message.content)
191
+ }
192
+ })
193
+
194
+ // Handle disconnection
195
+ conn.onClose(() => {
196
+ console.log(`User ${userId} disconnected from chat`)
197
+ leaveChatRoom(userId)
198
+ })
199
+ }
200
+ )
201
+
202
+ // Register module with context
203
+ context.registerModule(chatModule)
204
+ ```
205
+
206
+ ### Real-time Data Streaming
207
+
208
+ ```typescript
209
+ import { handleConnection } from '@owlmeans/server-socket'
210
+ import type { Connection } from '@owlmeans/socket'
211
+
212
+ const dataStreamModule = module(
213
+ route('data-stream', '/ws/data'),
214
+ guard('authenticated')
215
+ )
216
+
217
+ dataStreamModule.handle = handleConnection<Connection>(
218
+ async (conn, ctx, req, res) => {
219
+ const userId = req.auth?.user?.id
220
+
221
+ // Start streaming data to client
222
+ const streamInterval = setInterval(async () => {
223
+ const data = await fetchLatestData(userId)
224
+ await conn.send({
225
+ type: 'data-update',
226
+ timestamp: Date.now(),
227
+ data: data
228
+ })
229
+ }, 1000)
230
+
231
+ // Handle client requests
232
+ conn.onMessage(async (message) => {
233
+ switch (message.type) {
234
+ case 'subscribe':
235
+ await subscribeToChannel(userId, message.channel)
236
+ break
237
+ case 'unsubscribe':
238
+ await unsubscribeFromChannel(userId, message.channel)
239
+ break
240
+ case 'get-history':
241
+ const history = await getHistoricalData(message.from, message.to)
242
+ await conn.send({
243
+ type: 'history-data',
244
+ requestId: message.requestId,
245
+ data: history
246
+ })
247
+ break
248
+ }
249
+ })
250
+
251
+ // Cleanup on disconnect
252
+ conn.onClose(() => {
253
+ clearInterval(streamInterval)
254
+ unsubscribeFromAllChannels(userId)
255
+ })
256
+ }
257
+ )
258
+ ```
259
+
260
+ ### WebSocket with Validation
261
+
262
+ ```typescript
263
+ import { module, filter, body } from '@owlmeans/module'
264
+ import { route } from '@owlmeans/route'
265
+ import { handleConnection } from '@owlmeans/server-socket'
266
+
267
+ // Define message validation schema
268
+ const messageSchema = {
269
+ type: 'object',
270
+ properties: {
271
+ type: { type: 'string', enum: ['join', 'leave', 'message'] },
272
+ content: { type: 'string', maxLength: 1000 },
273
+ roomId: { type: 'string' }
274
+ },
275
+ required: ['type']
276
+ }
277
+
278
+ const validatedSocketModule = module(
279
+ route('validated-socket', '/ws/validated'),
280
+ filter(body(messageSchema))
281
+ )
282
+
283
+ validatedSocketModule.handle = handleConnection<Connection>(
284
+ async (conn, ctx, req, res) => {
285
+ conn.onMessage(async (message) => {
286
+ // Message is automatically validated against schema
287
+ try {
288
+ switch (message.type) {
289
+ case 'join':
290
+ await joinRoom(conn, message.roomId)
291
+ await conn.send({ type: 'joined', roomId: message.roomId })
292
+ break
293
+ case 'leave':
294
+ await leaveRoom(conn, message.roomId)
295
+ await conn.send({ type: 'left', roomId: message.roomId })
296
+ break
297
+ case 'message':
298
+ await broadcastToRoom(message.roomId, {
299
+ type: 'room-message',
300
+ content: message.content,
301
+ sender: req.auth?.user?.id
302
+ })
303
+ break
304
+ }
305
+ } catch (error) {
306
+ await conn.send({
307
+ type: 'error',
308
+ message: error.message
309
+ })
310
+ }
311
+ })
312
+ }
313
+ )
314
+ ```
315
+
316
+ ### Connection Management
317
+
318
+ ```typescript
319
+ import { handleConnection } from '@owlmeans/server-socket'
320
+ import type { Connection } from '@owlmeans/socket'
321
+
322
+ // Global connection registry
323
+ const connections = new Map<string, Connection>()
324
+
325
+ const managedConnectionModule = module(
326
+ route('managed-connection', '/ws/managed')
327
+ )
328
+
329
+ managedConnectionModule.handle = handleConnection<Connection>(
330
+ async (conn, ctx, req, res) => {
331
+ const connectionId = generateConnectionId()
332
+
333
+ // Register connection
334
+ connections.set(connectionId, conn)
335
+
336
+ // Send connection info
337
+ await conn.send({
338
+ type: 'connection-established',
339
+ connectionId: connectionId,
340
+ serverTime: Date.now()
341
+ })
342
+
343
+ // Handle ping/pong for connection health
344
+ conn.onMessage(async (message) => {
345
+ if (message.type === 'ping') {
346
+ await conn.send({ type: 'pong', timestamp: Date.now() })
347
+ }
348
+ })
349
+
350
+ // Cleanup on disconnect
351
+ conn.onClose(() => {
352
+ connections.delete(connectionId)
353
+ console.log(`Connection ${connectionId} closed`)
354
+ })
355
+
356
+ // Send periodic server stats
357
+ const statsInterval = setInterval(async () => {
358
+ await conn.send({
359
+ type: 'server-stats',
360
+ activeConnections: connections.size,
361
+ serverUptime: process.uptime()
362
+ })
363
+ }, 30000)
364
+
365
+ conn.onClose(() => {
366
+ clearInterval(statsInterval)
367
+ })
368
+ }
369
+ )
370
+
371
+ // Function to broadcast to all connections
372
+ const broadcastToAll = async (message: any) => {
373
+ const promises = Array.from(connections.values()).map(conn =>
374
+ conn.send(message).catch(console.error)
375
+ )
376
+ await Promise.allSettled(promises)
377
+ }
378
+ ```
379
+
380
+ ### Error Handling
381
+
382
+ ```typescript
383
+ import { handleConnection } from '@owlmeans/server-socket'
384
+ import { ResilientError } from '@owlmeans/error'
385
+
386
+ const errorHandlingModule = module(
387
+ route('error-handling', '/ws/errors')
388
+ )
389
+
390
+ errorHandlingModule.handle = handleConnection<Connection>(
391
+ async (conn, ctx, req, res) => {
392
+ conn.onMessage(async (message) => {
393
+ try {
394
+ await processMessage(message)
395
+ } catch (error) {
396
+ if (error instanceof ResilientError) {
397
+ // Handle known errors gracefully
398
+ await conn.send({
399
+ type: 'error',
400
+ code: error.code,
401
+ message: error.message,
402
+ recoverable: true
403
+ })
404
+ } else {
405
+ // Handle unknown errors
406
+ console.error('Unexpected error:', error)
407
+ await conn.send({
408
+ type: 'error',
409
+ message: 'Internal server error',
410
+ recoverable: false
411
+ })
412
+ }
413
+ }
414
+ })
415
+
416
+ conn.onError((error) => {
417
+ console.error('WebSocket connection error:', error)
418
+ })
419
+ }
420
+ )
421
+ ```
422
+
423
+ ## Integration Patterns
424
+
425
+ ### With Chat Systems
426
+
427
+ ```typescript
428
+ // Real-time chat implementation
429
+ const chatRooms = new Map<string, Set<Connection>>()
430
+
431
+ const joinRoom = async (conn: Connection, roomId: string) => {
432
+ if (!chatRooms.has(roomId)) {
433
+ chatRooms.set(roomId, new Set())
434
+ }
435
+ chatRooms.get(roomId)!.add(conn)
436
+ }
437
+
438
+ const broadcastToRoom = async (roomId: string, message: any) => {
439
+ const room = chatRooms.get(roomId)
440
+ if (room) {
441
+ const promises = Array.from(room).map(conn => conn.send(message))
442
+ await Promise.allSettled(promises)
443
+ }
444
+ }
445
+ ```
446
+
447
+ ### With Gaming Applications
448
+
449
+ ```typescript
450
+ // Game server with real-time updates
451
+ const gameSessionModule = module(
452
+ route('game-session', '/ws/game/:sessionId'),
453
+ guard('authenticated')
454
+ )
455
+
456
+ gameSessionModule.handle = handleConnection<Connection>(
457
+ async (conn, ctx, req, res) => {
458
+ const sessionId = req.params.sessionId
459
+ const playerId = req.auth?.user?.id
460
+
461
+ await joinGameSession(sessionId, playerId, conn)
462
+
463
+ conn.onMessage(async (message) => {
464
+ switch (message.type) {
465
+ case 'player-move':
466
+ await processPlayerMove(sessionId, playerId, message.move)
467
+ await broadcastGameState(sessionId)
468
+ break
469
+ case 'player-action':
470
+ await processPlayerAction(sessionId, playerId, message.action)
471
+ break
472
+ }
473
+ })
474
+ }
475
+ )
476
+ ```
477
+
478
+ ### With Monitoring Systems
479
+
480
+ ```typescript
481
+ // Real-time monitoring dashboard
482
+ const monitoringModule = module(
483
+ route('monitoring', '/ws/monitor'),
484
+ guard('admin')
485
+ )
486
+
487
+ monitoringModule.handle = handleConnection<Connection>(
488
+ async (conn, ctx, req, res) => {
489
+ // Send initial system state
490
+ await conn.send({
491
+ type: 'system-state',
492
+ data: await getSystemMetrics()
493
+ })
494
+
495
+ // Subscribe to system events
496
+ const unsubscribe = await subscribeToSystemEvents(async (event) => {
497
+ await conn.send({
498
+ type: 'system-event',
499
+ event: event
500
+ })
501
+ })
502
+
503
+ conn.onClose(unsubscribe)
504
+ }
505
+ )
506
+ ```
507
+
508
+ ## Security Considerations
509
+
510
+ ### Authentication and Authorization
511
+ - **Guard Integration** - Use authentication guards to protect WebSocket endpoints
512
+ - **Token Validation** - Validate JWT tokens or session tokens before accepting connections
513
+ - **Connection Limits** - Implement connection limits per user or IP address
514
+
515
+ ### Data Validation
516
+ - **Message Validation** - Always validate incoming WebSocket messages
517
+ - **Rate Limiting** - Implement rate limiting for message frequency
518
+ - **Sanitization** - Sanitize user input to prevent injection attacks
519
+
520
+ ### Connection Security
521
+ - **TLS/SSL** - Use secure WebSocket connections (WSS) in production
522
+ - **Origin Validation** - Validate connection origins to prevent CSRF attacks
523
+ - **Connection Timeouts** - Implement proper timeout mechanisms
524
+
525
+ ## Best Practices
526
+
527
+ 1. **Implement proper error handling** - Always handle connection errors and message processing errors
528
+ 2. **Use connection pooling** - Manage connections efficiently to prevent memory leaks
529
+ 3. **Implement heartbeat mechanism** - Use ping/pong to detect dead connections
530
+ 4. **Validate all messages** - Never trust incoming WebSocket messages without validation
531
+ 5. **Handle cleanup properly** - Always clean up resources when connections close
532
+ 6. **Monitor connection health** - Track connection metrics and performance
533
+
534
+ ## Error Handling
535
+
536
+ The package integrates with OwlMeans error handling:
537
+
538
+ - **ResilientError** - For recoverable errors that clients can handle
539
+ - **Connection errors** - Proper handling of WebSocket connection failures
540
+ - **Authentication errors** - Clear error messages for authentication failures
541
+ - **Validation errors** - Detailed validation error reporting
542
+
543
+ ## Dependencies
544
+
545
+ This package depends on:
546
+ - `@owlmeans/context` - For service registration and context management
547
+ - `@owlmeans/server-api` - For API server integration
548
+ - `@owlmeans/server-context` - For server-side context management
549
+ - `@owlmeans/server-module` - For module system integration
550
+ - `@owlmeans/module` - For core module functionality
551
+ - `@owlmeans/socket` - For connection abstractions
552
+ - `@owlmeans/error` - For error handling
553
+ - `@fastify/websocket` - For WebSocket server implementation
554
+
555
+ ## Related Packages
556
+
557
+ - [`@owlmeans/socket`](../socket) - WebSocket connection abstractions
558
+ - [`@owlmeans/client-socket`](../client-socket) - Client-side WebSocket implementation
559
+ - [`@owlmeans/server-api`](../server-api) - HTTP API server functionality
560
+ - [`@owlmeans/server-module`](../server-module) - Server-side module system
package/build/.gitkeep ADDED
File without changes
@@ -0,0 +1,2 @@
1
+ export declare const DEFAULT_ALIAS = "socket-server";
2
+ //# sourceMappingURL=consts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa,kBAAkB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export const DEFAULT_ALIAS = 'socket-server';
2
+ //# sourceMappingURL=consts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAA"}
@@ -0,0 +1,7 @@
1
+ import type { AbstractRequest, AbstractResponse } from '@owlmeans/module';
2
+ import type { Context } from '@owlmeans/server-api';
3
+ import type { RefedModuleHandler } from '@owlmeans/server-module';
4
+ import type { Connection } from '@owlmeans/socket';
5
+ import type { WebSocket } from '@fastify/websocket';
6
+ export declare const handleConnection: <T extends Connection = Connection>(handler: (conn: T, ctx: Context, req: AbstractRequest<WebSocket>, res: AbstractResponse<any>) => Promise<void>) => RefedModuleHandler<AbstractResponse<any>>;
7
+ //# sourceMappingURL=helper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AACnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAGnD,eAAO,MAAM,gBAAgB,EAAE,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EAC/D,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,eAAe,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,gBAAgB,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,KAC3G,kBAAkB,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAU5C,CAAA"}
@@ -0,0 +1,14 @@
1
+ import { assertContext } from '@owlmeans/context';
2
+ import { makeConnection } from './utils/connection.js';
3
+ export const handleConnection = handler => ref => async (req, res) => {
4
+ const ctx = assertContext(ref.ref?.ctx);
5
+ try {
6
+ await handler(makeConnection(req, ctx), ctx, req, res);
7
+ }
8
+ catch (e) {
9
+ res.reject(e);
10
+ }
11
+ // Actually it does nothing - just for compatibility here
12
+ return res.value;
13
+ };
14
+ //# sourceMappingURL=helper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAMjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtD,MAAM,CAAC,MAAM,gBAAgB,GAEoB,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IACpF,MAAM,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAY,CAAA;IAClD,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;IAC/D,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,MAAM,CAAC,CAAU,CAAC,CAAA;IACxB,CAAC;IAED,yDAAyD;IACzD,OAAO,GAAG,CAAC,KAAK,CAAA;AAClB,CAAC,CAAA"}
@@ -0,0 +1,6 @@
1
+ export type * from './types.js';
2
+ export * from './middleware.js';
3
+ export * from './consts.js';
4
+ export * from './service.js';
5
+ export * from './helper.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA"}
package/build/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './middleware.js';
2
+ export * from './consts.js';
3
+ export * from './service.js';
4
+ export * from './helper.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { Middleware } from '@owlmeans/context';
2
+ export declare const createSocketMiddleware: (web?: string, socket?: string) => Middleware;
3
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAQnD,eAAO,MAAM,sBAAsB,SAAS,MAAM,sBAAuC,UAsBxF,CAAA"}
@@ -0,0 +1,25 @@
1
+ import { MiddlewareType, MiddlewareStage, assertContext } from '@owlmeans/context';
2
+ import { DEFAULT_ALIAS as WEB_ALIAS } from '@owlmeans/server-api';
3
+ import { DEFAULT_ALIAS } from './consts.js';
4
+ export const createSocketMiddleware = (web = WEB_ALIAS, socket = DEFAULT_ALIAS) => {
5
+ const middleware = {
6
+ type: MiddlewareType.Context,
7
+ stage: MiddlewareStage.Loading,
8
+ apply: async (ctx) => {
9
+ const context = assertContext(ctx, 'socket-middleware');
10
+ const webService = context.service(web);
11
+ const socketService = context.service(socket);
12
+ // @TODO There is some middlewares that are ok to work only once during context intialization
13
+ const marker = `__socketServiceAdded-${web}-${socket}`;
14
+ if (!ctx.cfg.records?.find(record => record.id === marker)) {
15
+ await socketService.update(webService);
16
+ if (ctx.cfg.records == null) {
17
+ ctx.cfg.records = [];
18
+ }
19
+ ctx.cfg.records.push({ id: marker });
20
+ }
21
+ }
22
+ };
23
+ return middleware;
24
+ };
25
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAElF,OAAO,EAAE,aAAa,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAEjE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAG3C,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,MAAc,SAAS,EAAE,MAAM,GAAG,aAAa,EAAc,EAAE;IACpG,MAAM,UAAU,GAAe;QAC7B,IAAI,EAAE,cAAc,CAAC,OAAO;QAC5B,KAAK,EAAE,eAAe,CAAC,OAAO;QAC9B,KAAK,EAAE,KAAK,EAAC,GAAG,EAAC,EAAE;YACjB,MAAM,OAAO,GAAG,aAAa,CAAkB,GAAyB,EAAE,mBAAmB,CAAC,CAAA;YAC9F,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAY,GAAG,CAAC,CAAA;YAClD,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAgB,MAAM,CAAC,CAAA;YAC5D,6FAA6F;YAE7F,MAAM,MAAM,GAAG,wBAAwB,GAAG,IAAI,MAAM,EAAE,CAAA;YACtD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC;gBAC3D,MAAM,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;gBACtC,IAAI,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;oBAC5B,GAAG,CAAC,GAAG,CAAC,OAAO,GAAG,EAAE,CAAA;gBACtB,CAAC;gBACD,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;YACtC,CAAC;QACH,CAAC;KACF,CAAA;IAED,OAAO,UAAU,CAAA;AACnB,CAAC,CAAA"}