sleepy-socket 0.6.1 → 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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAA;AAE/B,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;IACpB,YAAY,EAAE,cAAc;CACpB,CAAA;AAuBV,MAAM,UAAU,aAAa,CAC3B,QAAgB,EAChB,IAAiB,EACjB,OAAuB,EAAE;IAEzB,OAAO;QACL,GAAG,IAAI;QACP,EAAE,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE;QACnB,QAAQ;QACR,IAAI;QACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI,OAAO,EAAE;QACtC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI;KACxB,CAAA;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ export type IdGenerator = () => string;
2
+ export declare const defaultIdGenerator: IdGenerator;
3
+ export declare function joinRoute(...segments: string[]): string;
4
+ export declare function id(): string;
5
+ export declare function setIdGenerator(fn: IdGenerator): void;
6
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,MAAM,MAAM,CAAA;AAEtC,eAAO,MAAM,kBAAkB,EAAE,WAAuC,CAAA;AAIxE,wBAAgB,SAAS,CAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAOxD;AAED,wBAAgB,EAAE,IAAK,MAAM,CAE5B;AAED,wBAAgB,cAAc,CAAE,EAAE,EAAE,WAAW,GAAG,IAAI,CAErD"}
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
@@ -2,9 +2,21 @@
2
2
  "name": "sleepy-socket",
3
3
  "description": "A dependency-free WebSocket client for sleepy-serv",
4
4
  "author": "Travis J True",
5
- "version": "0.6.1",
6
- "exports": "./src/index.js",
5
+ "license": "MIT",
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
+ },
7
14
  "type": "module",
15
+ "files": [
16
+ "dist",
17
+ "src",
18
+ "!src/**/*.test.*"
19
+ ],
8
20
  "repository": {
9
21
  "type": "git",
10
22
  "url": "git+https://github.com/travistrue2008/sleepy-serv.git",
@@ -18,6 +30,12 @@
18
30
  "websocket",
19
31
  "www"
20
32
  ],
21
- "scripts": {},
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
+ },
22
40
  "dependencies": {}
23
41
  }
@@ -1,21 +1,97 @@
1
- import { TYPES, createMessage } from './messages'
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 const QUEUE = {
8
- NONE: 'none',
9
- FIFO: 'fifo',
10
- LIFO: 'lifo',
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 = QUEUE.NONE
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 queueType () {
48
- return this.#queueType
123
+ get isSecure (): boolean {
124
+ return this.#secure
49
125
  }
50
126
 
51
- get secure () {
52
- return this.#secure
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 (host, port, opts = {}) {
84
- if (opts.queue && !Object.values(QUEUE).includes(opts.queue)) {
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
- const hasReconnect = opts.reconnect && typeof opts.reconnect === 'object'
90
- const reconnect = hasReconnect ? opts.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 ?? QUEUE.NONE
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 (res, succeed, fail) {
166
- this.#socket = new WebSocket(this.#socketUrl(res.ticket))
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
- this.#socket.removeEventListener('message', onWelcome)
263
+ socket.removeEventListener('message', onWelcome)
175
264
 
176
- if (message.type !== TYPES.WELCOME) {
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
- this.#socket.addEventListener('message', ev => this.#handleMessage(ev))
187
- this.#socket.addEventListener('close', ev => this.#handleClose(ev))
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
- this.#socket.addEventListener('open', () => {
198
- this.#socket.removeEventListener('error', onError)
199
- this.#socket.addEventListener('message', onWelcome)
286
+ socket.addEventListener('open', () => {
287
+ socket.removeEventListener('error', onError)
288
+ socket.addEventListener('message', onWelcome)
200
289
  }, { once: true })
201
290
 
202
- this.#socket.addEventListener('error', onError)
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
- clearTimeout(this.#livenessTimer)
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 } = this.#reconnectConfig
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, TYPES.HEARTBEAT)
373
+ const message = createMessage(this.#id!, MessageType.Heartbeat)
283
374
 
284
- this.#socket.send(JSON.stringify(message))
375
+ this.#socket!.send(JSON.stringify(message))
285
376
  }, this.#heartbeatInterval)
286
377
  }
287
378
 
288
- #stopHeartbeat () {
289
- clearInterval(this.#heartbeatTimer)
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 (method, route, opts = {}) {
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, TYPES.REQUEST, {
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.send(JSON.stringify(message))
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
- clearTimeout(this.#livenessTimer)
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 TYPES.HEARTBEAT:
512
+ case MessageType.Heartbeat:
413
513
  return
414
514
 
415
- case TYPES.RESPONSE:
515
+ case MessageType.Response:
416
516
  return this.#handleRequest(data)
417
517
 
418
- case TYPES.NOTIFICATION:
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.resolve(entry.response)
548
+ entry!.resolve(entry!.response!)
449
549
  }
450
550
  }
451
551
 
452
- #drain () {
552
+ #drain (): void {
453
553
  switch (this.#queueType) {
454
- case QUEUE.NONE:
554
+ case Queue.None:
455
555
  return this.#processNone()
456
556
 
457
- case QUEUE.FIFO:
557
+ case Queue.Fifo:
458
558
  return this.#processFifo()
459
559
 
460
- case QUEUE.LIFO:
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).add(handler)
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
- clearTimeout(this.#livenessTimer)
503
- clearTimeout(this.#reconnectTimer)
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
  }