@laplace.live/event-bridge-sdk 0.0.1 → 0.0.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/index.ts +227 -0
- package/package.json +4 -3
package/index.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import type { LaplaceEvent, LaplaceEventTypes } from '@laplace.live/event-types'
|
|
2
|
+
|
|
3
|
+
// Create a conditional type that maps from event type string to event object type
|
|
4
|
+
export type EventTypeMap = {
|
|
5
|
+
[K in LaplaceEventTypes]: Extract<LaplaceEvent, { type: K }>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type EventHandler<T extends LaplaceEvent> = (event: T) => void
|
|
9
|
+
export type EventTypeHandler = (event: LaplaceEvent) => void
|
|
10
|
+
export type AnyEventHandler = (event: LaplaceEvent) => void
|
|
11
|
+
|
|
12
|
+
export interface ConnectionOptions {
|
|
13
|
+
url?: string
|
|
14
|
+
token?: string
|
|
15
|
+
reconnect?: boolean
|
|
16
|
+
reconnectInterval?: number
|
|
17
|
+
maxReconnectAttempts?: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class LaplaceEventClient {
|
|
21
|
+
private ws: WebSocket | null = null
|
|
22
|
+
private eventHandlers = new Map<string, EventHandler<any>[]>()
|
|
23
|
+
private anyEventHandlers: AnyEventHandler[] = []
|
|
24
|
+
private reconnectTimer: number | null = null
|
|
25
|
+
private reconnectAttempts = 0
|
|
26
|
+
private clientId: string | null = null
|
|
27
|
+
private isConnected = false
|
|
28
|
+
|
|
29
|
+
private options: Required<ConnectionOptions> = {
|
|
30
|
+
url: 'ws://localhost:9696',
|
|
31
|
+
token: '',
|
|
32
|
+
reconnect: true,
|
|
33
|
+
reconnectInterval: 3000,
|
|
34
|
+
maxReconnectAttempts: 10,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
constructor(options: ConnectionOptions = {}) {
|
|
38
|
+
this.options = { ...this.options, ...options }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Connect to the LAPLACE Event Bridge
|
|
43
|
+
* @returns A promise that resolves when the connection is established
|
|
44
|
+
*/
|
|
45
|
+
public connect(): Promise<void> {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
try {
|
|
48
|
+
if (this.ws) {
|
|
49
|
+
this.ws.close()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const protocols: string[] = []
|
|
53
|
+
if (this.options.token) {
|
|
54
|
+
// Add the token as the second protocol parameter
|
|
55
|
+
protocols.push('laplace-event-bridge-role-client', this.options.token)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.ws = new WebSocket(this.options.url, protocols)
|
|
59
|
+
|
|
60
|
+
this.ws.onopen = () => {
|
|
61
|
+
this.isConnected = true
|
|
62
|
+
this.reconnectAttempts = 0
|
|
63
|
+
console.log('Connected to LAPLACE Event Bridge')
|
|
64
|
+
resolve()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
this.ws.onmessage = event => {
|
|
68
|
+
try {
|
|
69
|
+
const data = JSON.parse(event.data)
|
|
70
|
+
|
|
71
|
+
// Store client ID from the established message
|
|
72
|
+
if (data.type === 'established' && data.clientId) {
|
|
73
|
+
this.clientId = data.clientId
|
|
74
|
+
console.log(`Connection established with client ID: ${this.clientId}`)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Process the event
|
|
78
|
+
this.processEvent(data)
|
|
79
|
+
} catch (err) {
|
|
80
|
+
console.error('Failed to parse event data:', err)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.ws.onerror = error => {
|
|
85
|
+
console.error('WebSocket error:', error)
|
|
86
|
+
reject(error)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.ws.onclose = () => {
|
|
90
|
+
this.isConnected = false
|
|
91
|
+
console.log('Disconnected from LAPLACE Event Bridge')
|
|
92
|
+
|
|
93
|
+
if (this.options.reconnect && this.reconnectAttempts < this.options.maxReconnectAttempts) {
|
|
94
|
+
this.reconnectAttempts++
|
|
95
|
+
console.log(`Attempting to reconnect (${this.reconnectAttempts}/${this.options.maxReconnectAttempts})...`)
|
|
96
|
+
this.reconnectTimer = setTimeout(() => {
|
|
97
|
+
this.connect().catch(err => {
|
|
98
|
+
console.error('Reconnection failed:', err)
|
|
99
|
+
})
|
|
100
|
+
}, this.options.reconnectInterval) as unknown as number
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} catch (err) {
|
|
104
|
+
reject(err)
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Disconnect from the LAPLACE Event Bridge
|
|
111
|
+
*/
|
|
112
|
+
public disconnect(): void {
|
|
113
|
+
if (this.reconnectTimer) {
|
|
114
|
+
clearTimeout(this.reconnectTimer)
|
|
115
|
+
this.reconnectTimer = null
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (this.ws) {
|
|
119
|
+
this.ws.close()
|
|
120
|
+
this.ws = null
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.isConnected = false
|
|
124
|
+
this.clientId = null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Register an event handler for a specific event type
|
|
129
|
+
* @param eventType The event type to listen for
|
|
130
|
+
* @param handler The handler function to call when the event is received
|
|
131
|
+
*/
|
|
132
|
+
public on<T extends LaplaceEventTypes>(eventType: T, handler: (event: EventTypeMap[T]) => void): void {
|
|
133
|
+
if (!this.eventHandlers.has(eventType)) {
|
|
134
|
+
this.eventHandlers.set(eventType, [])
|
|
135
|
+
}
|
|
136
|
+
this.eventHandlers.get(eventType)!.push(handler)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Register a handler for all events
|
|
141
|
+
* @param handler The handler function to call for any event
|
|
142
|
+
*/
|
|
143
|
+
public onAny(handler: AnyEventHandler): void {
|
|
144
|
+
this.anyEventHandlers.push(handler)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Remove an event handler for a specific event type
|
|
149
|
+
* @param eventType The event type to remove the handler for
|
|
150
|
+
* @param handler The handler function to remove
|
|
151
|
+
*/
|
|
152
|
+
public off<T extends LaplaceEventTypes>(eventType: T, handler: (event: EventTypeMap[T]) => void): void {
|
|
153
|
+
if (!this.eventHandlers.has(eventType)) {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const handlers = this.eventHandlers.get(eventType)!
|
|
158
|
+
const index = handlers.indexOf(handler)
|
|
159
|
+
|
|
160
|
+
if (index !== -1) {
|
|
161
|
+
handlers.splice(index, 1)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (handlers.length === 0) {
|
|
165
|
+
this.eventHandlers.delete(eventType)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Remove a handler for all events
|
|
171
|
+
* @param handler The handler function to remove
|
|
172
|
+
*/
|
|
173
|
+
public offAny(handler: AnyEventHandler): void {
|
|
174
|
+
const index = this.anyEventHandlers.indexOf(handler)
|
|
175
|
+
if (index !== -1) {
|
|
176
|
+
this.anyEventHandlers.splice(index, 1)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Check if the client is connected to the bridge
|
|
182
|
+
*/
|
|
183
|
+
public isConnectedToBridge(): boolean {
|
|
184
|
+
return this.isConnected
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get the client ID assigned by the bridge
|
|
189
|
+
*/
|
|
190
|
+
public getClientId(): string | null {
|
|
191
|
+
return this.clientId
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Send an event to the bridge
|
|
196
|
+
* @param event The event to send
|
|
197
|
+
*/
|
|
198
|
+
public send(event: LaplaceEvent): void {
|
|
199
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
200
|
+
throw new Error('Not connected to LAPLACE Event Bridge')
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
this.ws.send(JSON.stringify(event))
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private processEvent(event: LaplaceEvent): void {
|
|
207
|
+
// Call specific event handlers
|
|
208
|
+
if (this.eventHandlers.has(event.type)) {
|
|
209
|
+
for (const handler of this.eventHandlers.get(event.type)!) {
|
|
210
|
+
try {
|
|
211
|
+
handler(event)
|
|
212
|
+
} catch (err) {
|
|
213
|
+
console.error(`Error in event handler for type ${event.type}:`, err)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Call any event handlers
|
|
219
|
+
for (const handler of this.anyEventHandlers) {
|
|
220
|
+
try {
|
|
221
|
+
handler(event)
|
|
222
|
+
} catch (err) {
|
|
223
|
+
console.error('Error in any event handler:', err)
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@laplace.live/event-bridge-sdk",
|
|
3
3
|
"description": "LAPLACE Event Bridge SDK",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.2",
|
|
5
5
|
"module": "index.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"build": "bun build index.ts --outdir dist --target browser --minify"
|
|
8
|
+
"build": "bun build index.ts --outdir dist --target browser --minify",
|
|
9
|
+
"publish": "bun run build && bun publish"
|
|
9
10
|
},
|
|
10
11
|
"exports": {
|
|
11
12
|
".": {
|
|
@@ -15,7 +16,7 @@
|
|
|
15
16
|
},
|
|
16
17
|
"files": [
|
|
17
18
|
"dist",
|
|
18
|
-
"
|
|
19
|
+
"index.ts",
|
|
19
20
|
"README.md",
|
|
20
21
|
"LICENSE"
|
|
21
22
|
],
|