sleepy-socket 0.6.2 → 0.7.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.
- package/README.md +13 -13
- package/dist/index.d.ts +79 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +420 -0
- package/dist/index.js.map +1 -0
- package/dist/messages.d.ts +26 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +20 -0
- package/dist/messages.js.map +1 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +16 -0
- package/dist/utils.js.map +1 -0
- package/package.json +20 -3
- package/src/{index.js → index.ts} +215 -109
- package/src/messages.ts +46 -0
- package/src/utils.ts +22 -0
- package/src/messages.js +0 -21
- package/src/utils.js +0 -19
package/dist/utils.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const defaultIdGenerator = () => crypto.randomUUID();
|
|
2
|
+
let _uuidFn = defaultIdGenerator;
|
|
3
|
+
export function joinRoute(...segments) {
|
|
4
|
+
const joined = segments
|
|
5
|
+
.filter(Boolean)
|
|
6
|
+
.join('/')
|
|
7
|
+
.replace(/\/{2,}/g, '/');
|
|
8
|
+
return joined.startsWith('/') ? joined : `/${joined}`;
|
|
9
|
+
}
|
|
10
|
+
export function id() {
|
|
11
|
+
return _uuidFn();
|
|
12
|
+
}
|
|
13
|
+
export function setIdGenerator(fn) {
|
|
14
|
+
_uuidFn = fn;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAAgB,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,CAAA;AAExE,IAAI,OAAO,GAAgB,kBAAkB,CAAA;AAE7C,MAAM,UAAU,SAAS,CAAE,GAAG,QAAkB;IAC9C,MAAM,MAAM,GAAG,QAAQ;SACpB,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC;SACT,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;IAE1B,OAAO,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAA;AACvD,CAAC;AAED,MAAM,UAAU,EAAE;IAChB,OAAO,OAAO,EAAE,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,cAAc,CAAE,EAAe;IAC7C,OAAO,GAAG,EAAE,CAAA;AACd,CAAC"}
|
package/package.json
CHANGED
|
@@ -3,9 +3,20 @@
|
|
|
3
3
|
"description": "A dependency-free WebSocket client for sleepy-serv",
|
|
4
4
|
"author": "Travis J True",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "0.
|
|
7
|
-
"exports":
|
|
6
|
+
"version": "0.7.0",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"bun": "./src/index.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
8
14
|
"type": "module",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"src",
|
|
18
|
+
"!src/**/*.test.*"
|
|
19
|
+
],
|
|
9
20
|
"repository": {
|
|
10
21
|
"type": "git",
|
|
11
22
|
"url": "git+https://github.com/travistrue2008/sleepy-serv.git",
|
|
@@ -19,6 +30,12 @@
|
|
|
19
30
|
"websocket",
|
|
20
31
|
"www"
|
|
21
32
|
],
|
|
22
|
-
"
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=22"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc -p tsconfig.build.json",
|
|
38
|
+
"typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.portable.json"
|
|
39
|
+
},
|
|
23
40
|
"dependencies": {}
|
|
24
41
|
}
|
|
@@ -1,21 +1,97 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { joinRoute } from './utils'
|
|
1
|
+
import { MessageType, createMessage } from './messages.js'
|
|
2
|
+
import { joinRoute } from './utils.js'
|
|
3
3
|
|
|
4
|
-
export * from './messages'
|
|
5
|
-
export * from './utils'
|
|
4
|
+
export * from './messages.js'
|
|
5
|
+
export * from './utils.js'
|
|
6
6
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
export type TimeoutHandle = ReturnType<typeof setTimeout>
|
|
8
|
+
export type IntervalHandle = ReturnType<typeof setInterval>
|
|
9
|
+
|
|
10
|
+
export const Queue = {
|
|
11
|
+
None: 'none',
|
|
12
|
+
Fifo: 'fifo',
|
|
13
|
+
Lifo: 'lifo',
|
|
14
|
+
} as const
|
|
15
|
+
|
|
16
|
+
export type Queue = typeof Queue[keyof typeof Queue]
|
|
17
|
+
|
|
18
|
+
export type ReconnectOptions = {
|
|
19
|
+
minDelay?: number
|
|
20
|
+
maxDelay?: number
|
|
21
|
+
factor?: number
|
|
22
|
+
random?: () => number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type ConnectOptions = {
|
|
26
|
+
queue?: Queue
|
|
27
|
+
secure?: boolean
|
|
28
|
+
timeout?: number
|
|
29
|
+
serverTimeout?: number
|
|
30
|
+
mountPath?: string
|
|
31
|
+
reconnect?: ReconnectOptions | false
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type RequestOptions = {
|
|
35
|
+
headers?: Headers
|
|
36
|
+
query?: Record<string, unknown>
|
|
37
|
+
body?: unknown
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type ResponseMessage = {
|
|
41
|
+
id: string
|
|
42
|
+
clientId: string
|
|
43
|
+
type: typeof MessageType.Response
|
|
44
|
+
timestamp: string
|
|
45
|
+
status: number
|
|
46
|
+
headers: Record<string, string>
|
|
47
|
+
body: unknown
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type NotificationMessage = {
|
|
51
|
+
id: string
|
|
52
|
+
clientId: string
|
|
53
|
+
type: typeof MessageType.Notification
|
|
54
|
+
timestamp: string
|
|
55
|
+
event: string
|
|
56
|
+
headers: Record<string, string>
|
|
57
|
+
body: unknown
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type EventHandler = (payload: NotificationMessage) => void
|
|
61
|
+
|
|
62
|
+
export type TicketData = {
|
|
63
|
+
clientId: string
|
|
64
|
+
ticket: string
|
|
65
|
+
data: unknown
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
type ReconnectConfig = {
|
|
69
|
+
minDelay: number
|
|
70
|
+
maxDelay: number
|
|
71
|
+
factor: number
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
type DispatchedMessage = {
|
|
75
|
+
id: string
|
|
76
|
+
ready: boolean
|
|
77
|
+
timer: ReturnType<typeof setTimeout>
|
|
78
|
+
response: ResponseMessage | null
|
|
79
|
+
resolve: (value: ResponseMessage) => void
|
|
80
|
+
reject: (reason: Error) => void
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
type NormalizedRequestOpts = {
|
|
84
|
+
headers: Headers
|
|
85
|
+
query: Record<string, unknown>
|
|
86
|
+
body: unknown
|
|
11
87
|
}
|
|
12
88
|
|
|
13
89
|
const RECONNECT_JITTER = 0.5
|
|
14
90
|
const JSON_CONTENT_TYPE = 'application/json;charset=utf-8'
|
|
15
91
|
|
|
16
92
|
export default class SleepySocketClient {
|
|
17
|
-
#id = null
|
|
18
|
-
#queueType =
|
|
93
|
+
#id: string | null = null
|
|
94
|
+
#queueType: Queue = Queue.None
|
|
19
95
|
#ready = false
|
|
20
96
|
#closing = false
|
|
21
97
|
#secure = false
|
|
@@ -23,75 +99,82 @@ export default class SleepySocketClient {
|
|
|
23
99
|
#serverTimeout = 120_000
|
|
24
100
|
#heartbeatInterval = 30_000
|
|
25
101
|
#mountPath = ''
|
|
26
|
-
#host = null
|
|
27
|
-
#port = null
|
|
28
|
-
#token = null
|
|
29
|
-
#socket = null
|
|
30
|
-
#random = Math.random
|
|
31
|
-
#livenessTimer = null
|
|
32
|
-
#heartbeatTimer = null
|
|
33
|
-
#reconnectTimer = null
|
|
34
|
-
#reconnectConfig = null
|
|
35
|
-
#connectionData = null
|
|
36
|
-
#listeners = new Map()
|
|
37
|
-
#dispatchedMessages = []
|
|
38
|
-
|
|
39
|
-
get id () {
|
|
102
|
+
#host: string | null = null
|
|
103
|
+
#port: number | null = null
|
|
104
|
+
#token: string | null = null
|
|
105
|
+
#socket: WebSocket | null = null
|
|
106
|
+
#random: () => number = Math.random
|
|
107
|
+
#livenessTimer: ReturnType<typeof setTimeout> | null = null
|
|
108
|
+
#heartbeatTimer: ReturnType<typeof setInterval> | null = null
|
|
109
|
+
#reconnectTimer: ReturnType<typeof setTimeout> | null = null
|
|
110
|
+
#reconnectConfig: ReconnectConfig | null = null
|
|
111
|
+
#connectionData: unknown = null
|
|
112
|
+
#listeners = new Map<string, Set<EventHandler>>()
|
|
113
|
+
#dispatchedMessages: DispatchedMessage[] = []
|
|
114
|
+
|
|
115
|
+
get id (): string | null {
|
|
40
116
|
return this.#id
|
|
41
117
|
}
|
|
42
118
|
|
|
43
|
-
get isConnected () {
|
|
119
|
+
get isConnected (): boolean {
|
|
44
120
|
return this.#ready
|
|
45
121
|
}
|
|
46
122
|
|
|
47
|
-
get
|
|
48
|
-
return this.#
|
|
123
|
+
get isSecure (): boolean {
|
|
124
|
+
return this.#secure
|
|
49
125
|
}
|
|
50
126
|
|
|
51
|
-
get
|
|
52
|
-
return this.#
|
|
127
|
+
get queueType (): Queue {
|
|
128
|
+
return this.#queueType
|
|
53
129
|
}
|
|
54
130
|
|
|
55
|
-
get timeout () {
|
|
131
|
+
get timeout (): number {
|
|
56
132
|
return this.#timeout
|
|
57
133
|
}
|
|
58
134
|
|
|
59
|
-
get heartbeatInterval () {
|
|
135
|
+
get heartbeatInterval (): number {
|
|
60
136
|
return this.#heartbeatInterval
|
|
61
137
|
}
|
|
62
138
|
|
|
63
|
-
get serverTimeout () {
|
|
139
|
+
get serverTimeout (): number {
|
|
64
140
|
return this.#serverTimeout
|
|
65
141
|
}
|
|
66
142
|
|
|
67
|
-
get token () {
|
|
143
|
+
get token (): string | null {
|
|
68
144
|
return this.#token
|
|
69
145
|
}
|
|
70
146
|
|
|
71
|
-
get mountPath () {
|
|
147
|
+
get mountPath (): string {
|
|
72
148
|
return this.#mountPath
|
|
73
149
|
}
|
|
74
150
|
|
|
75
|
-
get socket () {
|
|
151
|
+
get socket (): WebSocket | null {
|
|
76
152
|
return this.#socket
|
|
77
153
|
}
|
|
78
154
|
|
|
79
|
-
get connectionData () {
|
|
155
|
+
get connectionData (): unknown {
|
|
80
156
|
return this.#connectionData
|
|
81
157
|
}
|
|
82
158
|
|
|
83
|
-
static async connect (
|
|
84
|
-
|
|
159
|
+
static async connect (
|
|
160
|
+
host: string,
|
|
161
|
+
port: number,
|
|
162
|
+
opts: ConnectOptions = {},
|
|
163
|
+
): Promise<SleepySocketClient> {
|
|
164
|
+
if (opts.queue && !Object.values(Queue).includes(opts.queue)) {
|
|
85
165
|
throw new RangeError(`Invalid queue type: ${opts.queue}`)
|
|
86
166
|
}
|
|
87
167
|
|
|
88
168
|
const client = new this()
|
|
89
|
-
|
|
90
|
-
const reconnect =
|
|
169
|
+
|
|
170
|
+
const reconnect: ReconnectOptions =
|
|
171
|
+
opts.reconnect && typeof opts.reconnect === 'object'
|
|
172
|
+
? opts.reconnect
|
|
173
|
+
: {}
|
|
91
174
|
|
|
92
175
|
client.#host = host
|
|
93
176
|
client.#port = port
|
|
94
|
-
client.#queueType = opts.queue ??
|
|
177
|
+
client.#queueType = opts.queue ?? Queue.None
|
|
95
178
|
client.#secure = opts.secure ?? false
|
|
96
179
|
client.#timeout = opts.timeout ?? 30_000
|
|
97
180
|
client.#serverTimeout = opts.serverTimeout ?? 120_000
|
|
@@ -112,21 +195,21 @@ export default class SleepySocketClient {
|
|
|
112
195
|
return client
|
|
113
196
|
}
|
|
114
197
|
|
|
115
|
-
#baseUrl () {
|
|
198
|
+
#baseUrl (): string {
|
|
116
199
|
const protocol = this.#secure ? 'https' : 'http'
|
|
117
200
|
|
|
118
201
|
return `${protocol}://${this.#host}:${this.#port}${this.#mountPath}`
|
|
119
202
|
}
|
|
120
203
|
|
|
121
|
-
async #createTicket () {
|
|
204
|
+
async #createTicket (): Promise<TicketData> {
|
|
122
205
|
const response = await fetch(`${this.#baseUrl()}/ws`, {
|
|
123
206
|
method: 'POST',
|
|
124
207
|
})
|
|
125
208
|
|
|
126
|
-
return response.json()
|
|
209
|
+
return await response.json() as TicketData
|
|
127
210
|
}
|
|
128
211
|
|
|
129
|
-
async #reclaimTicket () {
|
|
212
|
+
async #reclaimTicket (): Promise<TicketData | null> {
|
|
130
213
|
const url = `${this.#baseUrl()}/ws/${this.#id}`
|
|
131
214
|
|
|
132
215
|
const response = await fetch(url, {
|
|
@@ -140,10 +223,10 @@ export default class SleepySocketClient {
|
|
|
140
223
|
return null
|
|
141
224
|
}
|
|
142
225
|
|
|
143
|
-
return response.json()
|
|
226
|
+
return await response.json() as TicketData
|
|
144
227
|
}
|
|
145
228
|
|
|
146
|
-
async #requestTicket () {
|
|
229
|
+
async #requestTicket (): Promise<TicketData> {
|
|
147
230
|
if (this.#id && this.#token) {
|
|
148
231
|
const reclaimed = await this.#reclaimTicket()
|
|
149
232
|
|
|
@@ -155,25 +238,31 @@ export default class SleepySocketClient {
|
|
|
155
238
|
return this.#createTicket()
|
|
156
239
|
}
|
|
157
240
|
|
|
158
|
-
#socketUrl (ticket) {
|
|
241
|
+
#socketUrl (ticket: string): string {
|
|
159
242
|
const protocol = this.#secure ? 'wss' : 'ws'
|
|
160
243
|
const authority = `${this.#host}:${this.#port}${this.#mountPath}`
|
|
161
244
|
|
|
162
245
|
return `${protocol}://${authority}/ws?ticket=${ticket}`
|
|
163
246
|
}
|
|
164
247
|
|
|
165
|
-
#openSocket (
|
|
166
|
-
|
|
248
|
+
#openSocket (
|
|
249
|
+
res: TicketData,
|
|
250
|
+
succeed: () => void,
|
|
251
|
+
fail: (message: string) => void,
|
|
252
|
+
): void {
|
|
253
|
+
const socket = new WebSocket(this.#socketUrl(res.ticket))
|
|
254
|
+
|
|
255
|
+
this.#socket = socket
|
|
167
256
|
this.#connectionData = res.data
|
|
168
257
|
|
|
169
|
-
const onError = () => fail('Connection failed.')
|
|
258
|
+
const onError = (): void => fail('Connection failed.')
|
|
170
259
|
|
|
171
|
-
const onWelcome = event => {
|
|
260
|
+
const onWelcome = (event: MessageEvent): void => {
|
|
172
261
|
const message = JSON.parse(event.data)
|
|
173
262
|
|
|
174
|
-
|
|
263
|
+
socket.removeEventListener('message', onWelcome)
|
|
175
264
|
|
|
176
|
-
if (message.type !==
|
|
265
|
+
if (message.type !== MessageType.Welcome) {
|
|
177
266
|
fail('Expected a welcome message.')
|
|
178
267
|
|
|
179
268
|
return
|
|
@@ -183,8 +272,8 @@ export default class SleepySocketClient {
|
|
|
183
272
|
this.#token = message.body.token
|
|
184
273
|
this.#heartbeatInterval = message.body.heartbeatInterval
|
|
185
274
|
|
|
186
|
-
|
|
187
|
-
|
|
275
|
+
socket.addEventListener('message', ev => this.#handleMessage(ev))
|
|
276
|
+
socket.addEventListener('close', ev => this.#handleClose(ev))
|
|
188
277
|
|
|
189
278
|
this.#startHeartbeat()
|
|
190
279
|
this.#armLiveness()
|
|
@@ -194,15 +283,15 @@ export default class SleepySocketClient {
|
|
|
194
283
|
succeed()
|
|
195
284
|
}
|
|
196
285
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
286
|
+
socket.addEventListener('open', () => {
|
|
287
|
+
socket.removeEventListener('error', onError)
|
|
288
|
+
socket.addEventListener('message', onWelcome)
|
|
200
289
|
}, { once: true })
|
|
201
290
|
|
|
202
|
-
|
|
291
|
+
socket.addEventListener('error', onError)
|
|
203
292
|
}
|
|
204
293
|
|
|
205
|
-
#establish () {
|
|
294
|
+
#establish (): Promise<void> {
|
|
206
295
|
return new Promise((resolve, reject) => {
|
|
207
296
|
let settled = false
|
|
208
297
|
|
|
@@ -217,7 +306,7 @@ export default class SleepySocketClient {
|
|
|
217
306
|
reject(new Error('Connection timed out.'))
|
|
218
307
|
}, this.#timeout)
|
|
219
308
|
|
|
220
|
-
const fail = message => {
|
|
309
|
+
const fail = (message: string): void => {
|
|
221
310
|
if (settled) {
|
|
222
311
|
return
|
|
223
312
|
}
|
|
@@ -228,7 +317,7 @@ export default class SleepySocketClient {
|
|
|
228
317
|
reject(new Error(message))
|
|
229
318
|
}
|
|
230
319
|
|
|
231
|
-
const succeed = () => {
|
|
320
|
+
const succeed = (): void => {
|
|
232
321
|
if (settled) {
|
|
233
322
|
return
|
|
234
323
|
}
|
|
@@ -245,16 +334,18 @@ export default class SleepySocketClient {
|
|
|
245
334
|
})
|
|
246
335
|
}
|
|
247
336
|
|
|
248
|
-
#armLiveness () {
|
|
249
|
-
|
|
337
|
+
#armLiveness (): void {
|
|
338
|
+
if (this.#livenessTimer) {
|
|
339
|
+
clearTimeout(this.#livenessTimer)
|
|
340
|
+
}
|
|
250
341
|
|
|
251
342
|
this.#livenessTimer = setTimeout(() => {
|
|
252
343
|
this.#socket?.close()
|
|
253
344
|
}, this.serverTimeout)
|
|
254
345
|
}
|
|
255
346
|
|
|
256
|
-
#scheduleReconnect (attempt) {
|
|
257
|
-
const { minDelay, maxDelay, factor } =
|
|
347
|
+
#scheduleReconnect (attempt: number, config: ReconnectConfig): void {
|
|
348
|
+
const { minDelay, maxDelay, factor } = config
|
|
258
349
|
const base = Math.min(minDelay * factor ** attempt, maxDelay)
|
|
259
350
|
const delay = base * (1 + this.#random() * RECONNECT_JITTER)
|
|
260
351
|
|
|
@@ -272,26 +363,28 @@ export default class SleepySocketClient {
|
|
|
272
363
|
return
|
|
273
364
|
}
|
|
274
365
|
|
|
275
|
-
this.#scheduleReconnect(attempt + 1)
|
|
366
|
+
this.#scheduleReconnect(attempt + 1, config)
|
|
276
367
|
}
|
|
277
368
|
}, delay)
|
|
278
369
|
}
|
|
279
370
|
|
|
280
|
-
#startHeartbeat () {
|
|
371
|
+
#startHeartbeat (): void {
|
|
281
372
|
this.#heartbeatTimer = setInterval(() => {
|
|
282
|
-
const message = createMessage(this.#id
|
|
373
|
+
const message = createMessage(this.#id!, MessageType.Heartbeat)
|
|
283
374
|
|
|
284
|
-
this.#socket
|
|
375
|
+
this.#socket!.send(JSON.stringify(message))
|
|
285
376
|
}, this.#heartbeatInterval)
|
|
286
377
|
}
|
|
287
378
|
|
|
288
|
-
#stopHeartbeat () {
|
|
289
|
-
|
|
379
|
+
#stopHeartbeat (): void {
|
|
380
|
+
if (this.#heartbeatTimer) {
|
|
381
|
+
clearInterval(this.#heartbeatTimer)
|
|
382
|
+
}
|
|
290
383
|
|
|
291
384
|
this.#heartbeatTimer = null
|
|
292
385
|
}
|
|
293
386
|
|
|
294
|
-
#normalizeRequestOpts (opts) {
|
|
387
|
+
#normalizeRequestOpts (opts: RequestOptions): NormalizedRequestOpts {
|
|
295
388
|
if (opts.headers !== undefined && !(opts.headers instanceof Headers)) {
|
|
296
389
|
throw new TypeError('opts.headers must be a Headers instance')
|
|
297
390
|
}
|
|
@@ -313,7 +406,11 @@ export default class SleepySocketClient {
|
|
|
313
406
|
}
|
|
314
407
|
}
|
|
315
408
|
|
|
316
|
-
#sendRequest (
|
|
409
|
+
#sendRequest (
|
|
410
|
+
method: string,
|
|
411
|
+
route: string,
|
|
412
|
+
opts: RequestOptions = {},
|
|
413
|
+
): Promise<ResponseMessage> {
|
|
317
414
|
if (!this.#ready) {
|
|
318
415
|
throw new Error('Socket is closed')
|
|
319
416
|
}
|
|
@@ -321,7 +418,7 @@ export default class SleepySocketClient {
|
|
|
321
418
|
const { headers, query, body } = this.#normalizeRequestOpts(opts)
|
|
322
419
|
const fullRoute = joinRoute(this.#mountPath, route)
|
|
323
420
|
|
|
324
|
-
const message = createMessage(this.#id
|
|
421
|
+
const message = createMessage(this.#id!, MessageType.Request, {
|
|
325
422
|
method,
|
|
326
423
|
query,
|
|
327
424
|
body,
|
|
@@ -351,15 +448,18 @@ export default class SleepySocketClient {
|
|
|
351
448
|
response: null,
|
|
352
449
|
})
|
|
353
450
|
|
|
354
|
-
this.#socket
|
|
451
|
+
this.#socket!.send(JSON.stringify(message))
|
|
355
452
|
})
|
|
356
453
|
}
|
|
357
454
|
|
|
358
|
-
#handleClose (event) {
|
|
455
|
+
#handleClose (event: CloseEvent): void {
|
|
359
456
|
this.#ready = false
|
|
360
457
|
|
|
361
458
|
this.#stopHeartbeat()
|
|
362
|
-
|
|
459
|
+
|
|
460
|
+
if (this.#livenessTimer) {
|
|
461
|
+
clearTimeout(this.#livenessTimer)
|
|
462
|
+
}
|
|
363
463
|
|
|
364
464
|
for (const entry of this.#dispatchedMessages) {
|
|
365
465
|
clearTimeout(entry.timer)
|
|
@@ -381,10 +481,10 @@ export default class SleepySocketClient {
|
|
|
381
481
|
return
|
|
382
482
|
}
|
|
383
483
|
|
|
384
|
-
this.#scheduleReconnect(0)
|
|
484
|
+
this.#scheduleReconnect(0, this.#reconnectConfig)
|
|
385
485
|
}
|
|
386
486
|
|
|
387
|
-
#handleRequest (data) {
|
|
487
|
+
#handleRequest (data: ResponseMessage): void {
|
|
388
488
|
const entry = this.#dispatchedMessages.find(item => item.id === data.id)
|
|
389
489
|
|
|
390
490
|
if (!entry) {
|
|
@@ -399,23 +499,23 @@ export default class SleepySocketClient {
|
|
|
399
499
|
this.#drain()
|
|
400
500
|
}
|
|
401
501
|
|
|
402
|
-
#handleNotification (data) {
|
|
502
|
+
#handleNotification (data: NotificationMessage): void {
|
|
403
503
|
this.#emit('notification', data)
|
|
404
504
|
}
|
|
405
505
|
|
|
406
|
-
#handleMessage (event) {
|
|
506
|
+
#handleMessage (event: MessageEvent): void {
|
|
407
507
|
this.#armLiveness()
|
|
408
508
|
|
|
409
509
|
const data = JSON.parse(event.data)
|
|
410
510
|
|
|
411
511
|
switch (data.type) {
|
|
412
|
-
case
|
|
512
|
+
case MessageType.Heartbeat:
|
|
413
513
|
return
|
|
414
514
|
|
|
415
|
-
case
|
|
515
|
+
case MessageType.Response:
|
|
416
516
|
return this.#handleRequest(data)
|
|
417
517
|
|
|
418
|
-
case
|
|
518
|
+
case MessageType.Notification:
|
|
419
519
|
return this.#handleNotification(data)
|
|
420
520
|
|
|
421
521
|
default:
|
|
@@ -423,46 +523,46 @@ export default class SleepySocketClient {
|
|
|
423
523
|
}
|
|
424
524
|
}
|
|
425
525
|
|
|
426
|
-
#processNone () {
|
|
526
|
+
#processNone (): void {
|
|
427
527
|
this.#dispatchedMessages = this.#dispatchedMessages.filter(entry => {
|
|
428
528
|
if (entry.ready) {
|
|
429
|
-
entry.resolve(entry.response)
|
|
529
|
+
entry.resolve(entry.response!)
|
|
430
530
|
}
|
|
431
531
|
|
|
432
532
|
return !entry.ready
|
|
433
533
|
})
|
|
434
534
|
}
|
|
435
535
|
|
|
436
|
-
#processFifo () {
|
|
536
|
+
#processFifo (): void {
|
|
437
537
|
while (this.#dispatchedMessages[0]?.ready) {
|
|
438
538
|
const [entry] = this.#dispatchedMessages.splice(0, 1)
|
|
439
539
|
|
|
440
|
-
entry.resolve(entry.response)
|
|
540
|
+
entry.resolve(entry.response!)
|
|
441
541
|
}
|
|
442
542
|
}
|
|
443
543
|
|
|
444
|
-
#processLifo () {
|
|
544
|
+
#processLifo (): void {
|
|
445
545
|
while (this.#dispatchedMessages.at(-1)?.ready) {
|
|
446
546
|
const entry = this.#dispatchedMessages.pop()
|
|
447
547
|
|
|
448
|
-
entry
|
|
548
|
+
entry!.resolve(entry!.response!)
|
|
449
549
|
}
|
|
450
550
|
}
|
|
451
551
|
|
|
452
|
-
#drain () {
|
|
552
|
+
#drain (): void {
|
|
453
553
|
switch (this.#queueType) {
|
|
454
|
-
case
|
|
554
|
+
case Queue.None:
|
|
455
555
|
return this.#processNone()
|
|
456
556
|
|
|
457
|
-
case
|
|
557
|
+
case Queue.Fifo:
|
|
458
558
|
return this.#processFifo()
|
|
459
559
|
|
|
460
|
-
case
|
|
560
|
+
case Queue.Lifo:
|
|
461
561
|
return this.#processLifo()
|
|
462
562
|
}
|
|
463
563
|
}
|
|
464
564
|
|
|
465
|
-
#emit (event, payload) {
|
|
565
|
+
#emit (event: string, payload: NotificationMessage): void {
|
|
466
566
|
const handlers = this.#listeners.get(event)
|
|
467
567
|
|
|
468
568
|
if (!handlers) {
|
|
@@ -478,19 +578,19 @@ export default class SleepySocketClient {
|
|
|
478
578
|
}
|
|
479
579
|
}
|
|
480
580
|
|
|
481
|
-
on (event, handler) {
|
|
581
|
+
on (event: string, handler: EventHandler): void {
|
|
482
582
|
if (!this.#listeners.has(event)) {
|
|
483
583
|
this.#listeners.set(event, new Set())
|
|
484
584
|
}
|
|
485
585
|
|
|
486
|
-
this.#listeners.get(event)
|
|
586
|
+
this.#listeners.get(event)!.add(handler)
|
|
487
587
|
}
|
|
488
588
|
|
|
489
|
-
off (event, handler) {
|
|
589
|
+
off (event: string, handler: EventHandler): void {
|
|
490
590
|
this.#listeners.get(event)?.delete(handler)
|
|
491
591
|
}
|
|
492
592
|
|
|
493
|
-
async close () {
|
|
593
|
+
async close (): Promise<void> {
|
|
494
594
|
if (this.#closing) {
|
|
495
595
|
throw new Error('Socket is closed')
|
|
496
596
|
}
|
|
@@ -499,8 +599,14 @@ export default class SleepySocketClient {
|
|
|
499
599
|
this.#ready = false
|
|
500
600
|
|
|
501
601
|
this.#stopHeartbeat()
|
|
502
|
-
|
|
503
|
-
|
|
602
|
+
|
|
603
|
+
if (this.#livenessTimer) {
|
|
604
|
+
clearTimeout(this.#livenessTimer)
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
if (this.#reconnectTimer) {
|
|
608
|
+
clearTimeout(this.#reconnectTimer)
|
|
609
|
+
}
|
|
504
610
|
|
|
505
611
|
this.#reconnectTimer = null
|
|
506
612
|
|
|
@@ -511,27 +617,27 @@ export default class SleepySocketClient {
|
|
|
511
617
|
}
|
|
512
618
|
}
|
|
513
619
|
|
|
514
|
-
head (route, opts = {}) {
|
|
620
|
+
head (route: string, opts: RequestOptions = {}): Promise<ResponseMessage> {
|
|
515
621
|
return this.#sendRequest('HEAD', route, opts)
|
|
516
622
|
}
|
|
517
623
|
|
|
518
|
-
get (route, opts = {}) {
|
|
624
|
+
get (route: string, opts: RequestOptions = {}): Promise<ResponseMessage> {
|
|
519
625
|
return this.#sendRequest('GET', route, opts)
|
|
520
626
|
}
|
|
521
627
|
|
|
522
|
-
post (route, opts = {}) {
|
|
628
|
+
post (route: string, opts: RequestOptions = {}): Promise<ResponseMessage> {
|
|
523
629
|
return this.#sendRequest('POST', route, opts)
|
|
524
630
|
}
|
|
525
631
|
|
|
526
|
-
put (route, opts = {}) {
|
|
632
|
+
put (route: string, opts: RequestOptions = {}): Promise<ResponseMessage> {
|
|
527
633
|
return this.#sendRequest('PUT', route, opts)
|
|
528
634
|
}
|
|
529
635
|
|
|
530
|
-
patch (route, opts = {}) {
|
|
636
|
+
patch (route: string, opts: RequestOptions = {}): Promise<ResponseMessage> {
|
|
531
637
|
return this.#sendRequest('PATCH', route, opts)
|
|
532
638
|
}
|
|
533
639
|
|
|
534
|
-
delete (route, opts = {}) {
|
|
640
|
+
delete (route: string, opts: RequestOptions = {}): Promise<ResponseMessage> {
|
|
535
641
|
return this.#sendRequest('DELETE', route, opts)
|
|
536
642
|
}
|
|
537
643
|
}
|