@mono-labs/dev 0.1.251 → 0.1.255
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/dist/cache-relay.d.ts +162 -0
- package/dist/cache-relay.d.ts.map +1 -0
- package/dist/cache-relay.js +300 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/local-server/index.d.ts.map +1 -1
- package/dist/local-server/index.js +7 -1
- package/dist/local-server/types.d.ts +2 -0
- package/dist/local-server/types.d.ts.map +1 -1
- package/dist/websocket/channel-store.d.ts +28 -0
- package/dist/websocket/channel-store.d.ts.map +1 -0
- package/dist/websocket/channel-store.js +91 -0
- package/dist/websocket/index.d.ts +8 -1
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +27 -1
- package/dist/websocket/socket-emitter.d.ts +25 -0
- package/dist/websocket/socket-emitter.d.ts.map +1 -0
- package/dist/websocket/socket-emitter.js +49 -0
- package/dist/websocket/types.d.ts +9 -0
- package/dist/websocket/types.d.ts.map +1 -1
- package/package.json +9 -1
- package/src/cache-relay.ts +487 -0
- package/src/index.ts +24 -0
- package/src/local-server/index.ts +7 -1
- package/src/local-server/types.ts +2 -0
- package/src/websocket/channel-store.ts +116 -0
- package/src/websocket/index.ts +27 -1
- package/src/websocket/socket-emitter.ts +64 -0
- package/src/websocket/types.ts +10 -0
package/src/websocket/index.ts
CHANGED
|
@@ -4,12 +4,19 @@ import { ActionRouter } from './action-router'
|
|
|
4
4
|
import { ConnectionRegistry } from './connection-registry'
|
|
5
5
|
import { buildRequestContext } from './event-synthesizer'
|
|
6
6
|
import { LocalGatewayClient } from './local-gateway-client'
|
|
7
|
+
import { InMemoryChannelStore, RedisChannelStore } from './channel-store'
|
|
8
|
+
import { SocketEmitter } from './socket-emitter'
|
|
9
|
+
import { initCacheRelay } from '../cache-relay'
|
|
7
10
|
import type { ConnectionId, SocketAdapterConfig } from './types'
|
|
8
11
|
|
|
9
|
-
export type { ConnectionId, PostToConnectionFn, SocketAdapterConfig } from './types'
|
|
12
|
+
export type { ConnectionId, PostToConnectionFn, SocketAdapterConfig, RedisConfig } from './types'
|
|
10
13
|
export { ConnectionRegistry } from './connection-registry'
|
|
11
14
|
export { LocalGatewayClient } from './local-gateway-client'
|
|
12
15
|
export { ActionRouter } from './action-router'
|
|
16
|
+
export { InMemoryChannelStore, RedisChannelStore } from './channel-store'
|
|
17
|
+
export type { ChannelStore } from './channel-store'
|
|
18
|
+
export { SocketEmitter } from './socket-emitter'
|
|
19
|
+
export type { EmitTarget } from './socket-emitter'
|
|
13
20
|
|
|
14
21
|
/**
|
|
15
22
|
* Attaches a full socket adapter to a WebSocketServer instance.
|
|
@@ -26,6 +33,22 @@ export function attachSocketAdapter(wss: WebSocketServer, config?: SocketAdapter
|
|
|
26
33
|
const postToConnection = gatewayClient.asFunction()
|
|
27
34
|
const actionRouter = new ActionRouter()
|
|
28
35
|
|
|
36
|
+
// Create channel store
|
|
37
|
+
let channelStore = config?.channelStore
|
|
38
|
+
if (!channelStore) {
|
|
39
|
+
if (config?.useRedis) {
|
|
40
|
+
const host = config.redis?.host ?? 'localhost'
|
|
41
|
+
const port = config.redis?.port ?? 6379
|
|
42
|
+
initCacheRelay(`${host}:${port}`)
|
|
43
|
+
channelStore = new RedisChannelStore({ keyPrefix: config.redis?.keyPrefix })
|
|
44
|
+
} else {
|
|
45
|
+
channelStore = new InMemoryChannelStore()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Create socket emitter
|
|
50
|
+
const socketEmitter = new SocketEmitter({ postToConnection, connectionRegistry, channelStore })
|
|
51
|
+
|
|
29
52
|
// Register consumer-provided routes
|
|
30
53
|
if (config?.routes) {
|
|
31
54
|
for (const [action, handler] of Object.entries(config.routes)) {
|
|
@@ -131,6 +154,7 @@ export function attachSocketAdapter(wss: WebSocketServer, config?: SocketAdapter
|
|
|
131
154
|
)
|
|
132
155
|
}
|
|
133
156
|
|
|
157
|
+
await channelStore.removeAll(connectionId)
|
|
134
158
|
await disconnectHandler(connectionId)
|
|
135
159
|
connectionRegistry.unregister(connectionId)
|
|
136
160
|
wsToConnectionId.delete(ws)
|
|
@@ -141,6 +165,8 @@ export function attachSocketAdapter(wss: WebSocketServer, config?: SocketAdapter
|
|
|
141
165
|
postToConnection,
|
|
142
166
|
connectionRegistry,
|
|
143
167
|
actionRouter,
|
|
168
|
+
channelStore,
|
|
169
|
+
socketEmitter,
|
|
144
170
|
getConnectionId: (ws: WebSocket) => wsToConnectionId.get(ws),
|
|
145
171
|
}
|
|
146
172
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ConnectionRegistry } from './connection-registry'
|
|
2
|
+
import type { ChannelStore } from './channel-store'
|
|
3
|
+
import type { ConnectionId, PostToConnectionFn } from './types'
|
|
4
|
+
|
|
5
|
+
export type EmitTarget =
|
|
6
|
+
| { userId: string }
|
|
7
|
+
| { orgId: string }
|
|
8
|
+
| { connectionId: string }
|
|
9
|
+
| { channel: string }
|
|
10
|
+
| 'broadcast'
|
|
11
|
+
|
|
12
|
+
export class SocketEmitter {
|
|
13
|
+
private postToConnection: PostToConnectionFn
|
|
14
|
+
private connectionRegistry: ConnectionRegistry
|
|
15
|
+
private channelStore: ChannelStore
|
|
16
|
+
|
|
17
|
+
constructor(deps: {
|
|
18
|
+
postToConnection: PostToConnectionFn
|
|
19
|
+
connectionRegistry: ConnectionRegistry
|
|
20
|
+
channelStore: ChannelStore
|
|
21
|
+
}) {
|
|
22
|
+
this.postToConnection = deps.postToConnection
|
|
23
|
+
this.connectionRegistry = deps.connectionRegistry
|
|
24
|
+
this.channelStore = deps.channelStore
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async emit(target: EmitTarget, data: unknown): Promise<void> {
|
|
28
|
+
const connectionIds = await this.resolveConnectionIds(target)
|
|
29
|
+
if (connectionIds.length === 0) return
|
|
30
|
+
|
|
31
|
+
const payload = typeof data === 'string' ? data : JSON.stringify(data)
|
|
32
|
+
|
|
33
|
+
await Promise.allSettled(
|
|
34
|
+
connectionIds.map(async (connId) => {
|
|
35
|
+
try {
|
|
36
|
+
await this.postToConnection(connId, payload)
|
|
37
|
+
} catch (err: unknown) {
|
|
38
|
+
const e = err as { statusCode?: number; name?: string }
|
|
39
|
+
if (e?.statusCode === 410 || e?.name === 'GoneException') return
|
|
40
|
+
console.error(`[SocketEmitter] failed to send to ${connId}:`, err)
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private async resolveConnectionIds(target: EmitTarget): Promise<ConnectionId[]> {
|
|
47
|
+
if (target === 'broadcast') {
|
|
48
|
+
return this.connectionRegistry.getAll()
|
|
49
|
+
}
|
|
50
|
+
if ('connectionId' in target) {
|
|
51
|
+
return [target.connectionId]
|
|
52
|
+
}
|
|
53
|
+
if ('userId' in target) {
|
|
54
|
+
return this.connectionRegistry.getConnectionsByUserId(target.userId)
|
|
55
|
+
}
|
|
56
|
+
if ('orgId' in target) {
|
|
57
|
+
return this.connectionRegistry.getConnectionsByOrgId(target.orgId)
|
|
58
|
+
}
|
|
59
|
+
if ('channel' in target) {
|
|
60
|
+
return this.channelStore.getSubscribers(target.channel)
|
|
61
|
+
}
|
|
62
|
+
return []
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/websocket/types.ts
CHANGED
|
@@ -54,6 +54,13 @@ export type ConnectHandlerFn = (
|
|
|
54
54
|
/** Handler called on $disconnect */
|
|
55
55
|
export type DisconnectHandlerFn = (connectionId: ConnectionId) => Promise<void>
|
|
56
56
|
|
|
57
|
+
/** Redis connection configuration */
|
|
58
|
+
export interface RedisConfig {
|
|
59
|
+
host?: string
|
|
60
|
+
port?: number
|
|
61
|
+
keyPrefix?: string
|
|
62
|
+
}
|
|
63
|
+
|
|
57
64
|
/** Configuration for the socket adapter */
|
|
58
65
|
export interface SocketAdapterConfig {
|
|
59
66
|
domainName?: string
|
|
@@ -63,4 +70,7 @@ export interface SocketAdapterConfig {
|
|
|
63
70
|
disconnectHandler?: DisconnectHandlerFn
|
|
64
71
|
routes?: Record<string, ActionHandler>
|
|
65
72
|
defaultHandler?: ActionHandler
|
|
73
|
+
channelStore?: import('./channel-store').ChannelStore
|
|
74
|
+
useRedis?: boolean
|
|
75
|
+
redis?: RedisConfig
|
|
66
76
|
}
|