@agg-build/sdk 4.26.0 → 4.27.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/dist/agg-websocket-CK2iXfti.mjs +1427 -0
- package/dist/agg-websocket-CK2iXfti.mjs.map +1 -0
- package/dist/agg-websocket-DJbIfxKb.js +1478 -0
- package/dist/agg-websocket-DoUDmsvW.d.mts +6009 -0
- package/dist/agg-websocket-DoUDmsvW.d.mts.map +1 -0
- package/dist/agg-websocket-DoUDmsvW.d.ts +6009 -0
- package/dist/agg-websocket-DoUDmsvW.d.ts.map +1 -0
- package/dist/browser.d.mts +67 -66
- package/dist/browser.d.mts.map +1 -0
- package/dist/browser.d.ts +67 -66
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +720 -2173
- package/dist/browser.mjs +423 -799
- package/dist/browser.mjs.map +1 -0
- package/dist/candle-builder-BNewIe9K.mjs +148 -0
- package/dist/candle-builder-BNewIe9K.mjs.map +1 -0
- package/dist/candle-builder-BULYdxB4.js +151 -0
- package/dist/index.d.mts +2 -1349
- package/dist/index.d.ts +2 -1349
- package/dist/index.js +2794 -4808
- package/dist/index.mjs +2788 -2512
- package/dist/index.mjs.map +1 -0
- package/dist/market-data.d.mts +6 -6
- package/dist/market-data.d.mts.map +1 -0
- package/dist/market-data.d.ts +6 -6
- package/dist/market-data.d.ts.map +1 -0
- package/dist/market-data.js +314 -1900
- package/dist/market-data.mjs +314 -350
- package/dist/market-data.mjs.map +1 -0
- package/dist/server.d.mts +235 -234
- package/dist/server.d.mts.map +1 -0
- package/dist/server.d.ts +235 -234
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +168 -296
- package/dist/server.mjs +163 -234
- package/dist/server.mjs.map +1 -0
- package/package.json +4 -4
- package/dist/agg-websocket-x_U4-orL.d.mts +0 -4598
- package/dist/agg-websocket-x_U4-orL.d.ts +0 -4598
- package/dist/chunk-CPMSVNBO.mjs +0 -2199
- package/dist/chunk-VD5UTAVD.mjs +0 -158
- package/dist/chunk-WNQUEZJF.mjs +0 -58
package/dist/browser.js
CHANGED
|
@@ -1,2175 +1,722 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
]);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
function
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
function
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
);
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
const impliedBids = deriveVenueChangesFromAttributedChanges(previousBids, delta.bidChanges);
|
|
712
|
-
const impliedAsks = deriveVenueChangesFromAttributedChanges(previousAsks, delta.askChanges);
|
|
713
|
-
for (const venue of /* @__PURE__ */ new Set([
|
|
714
|
-
...Object.keys(delta.venueDeltaBooks),
|
|
715
|
-
...Object.keys(impliedBids),
|
|
716
|
-
...Object.keys(impliedAsks)
|
|
717
|
-
])) {
|
|
718
|
-
let book = this.venueBooks.get(venue);
|
|
719
|
-
if (!book) {
|
|
720
|
-
book = { bids: /* @__PURE__ */ new Map(), asks: /* @__PURE__ */ new Map() };
|
|
721
|
-
this.venueBooks.set(venue, book);
|
|
722
|
-
}
|
|
723
|
-
const explicit = delta.venueDeltaBooks[venue];
|
|
724
|
-
for (const [levels2, changes] of [
|
|
725
|
-
[book.bids, mergeVenueLevelChanges(explicit == null ? void 0 : explicit.bidChanges, impliedBids[venue])],
|
|
726
|
-
[book.asks, mergeVenueLevelChanges(explicit == null ? void 0 : explicit.askChanges, impliedAsks[venue])]
|
|
727
|
-
]) {
|
|
728
|
-
for (const [price, size] of changes) {
|
|
729
|
-
if (size === 0) levels2.delete(toPriceKey(price));
|
|
730
|
-
else levels2.set(toPriceKey(price), { price, size });
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
for (const [levels2, changes] of [
|
|
735
|
-
[this.bids, delta.bidChanges],
|
|
736
|
-
[this.asks, delta.askChanges]
|
|
737
|
-
]) {
|
|
738
|
-
for (const [price, size, venues] of changes) {
|
|
739
|
-
if (size === 0) levels2.delete(toPriceKey(price));
|
|
740
|
-
else levels2.set(toPriceKey(price), { price, size, venues: __spreadValues({}, venues) });
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
this.metadata = __spreadProps(__spreadValues({}, this.metadata), {
|
|
744
|
-
outcomeId: (_a = this.metadata.outcomeId) != null ? _a : delta.outcomeId,
|
|
745
|
-
venues: __spreadValues(__spreadValues({}, this.metadata.venues), delta.venues),
|
|
746
|
-
midpoint: delta.midpoint,
|
|
747
|
-
spread: delta.spread,
|
|
748
|
-
seq: delta.seq,
|
|
749
|
-
checksum: delta.checksum,
|
|
750
|
-
timestamp: delta.timestamp
|
|
751
|
-
});
|
|
752
|
-
this.checksumValue = checksum;
|
|
753
|
-
this.cached = null;
|
|
754
|
-
return checksum;
|
|
755
|
-
}
|
|
756
|
-
view() {
|
|
757
|
-
if (this.cached) return this.cached;
|
|
758
|
-
const bids = (levels2) => [...levels2.values()].sort((a, b) => b.price - a.price);
|
|
759
|
-
const asks = (levels2) => [...levels2.values()].sort((a, b) => a.price - b.price);
|
|
760
|
-
this.cached = __spreadProps(__spreadValues({}, this.metadata), {
|
|
761
|
-
bids: bids(this.bids),
|
|
762
|
-
asks: asks(this.asks),
|
|
763
|
-
venueOrderbooks: Object.fromEntries(
|
|
764
|
-
[...this.venueBooks].map(([venue, book]) => [
|
|
765
|
-
venue,
|
|
766
|
-
{ bids: bids(book.bids), asks: asks(book.asks) }
|
|
767
|
-
])
|
|
768
|
-
)
|
|
769
|
-
});
|
|
770
|
-
return this.cached;
|
|
771
|
-
}
|
|
772
|
-
};
|
|
773
|
-
|
|
774
|
-
// src/agg-websocket.ts
|
|
775
|
-
var RECONNECT_BASE_MS = 1e3;
|
|
776
|
-
var RECONNECT_MAX_MS = 3e4;
|
|
777
|
-
var STALE_TIMEOUT_MS = 45e3;
|
|
778
|
-
var ORDERBOOK_DEBUG_TOP_LEVELS = 5;
|
|
779
|
-
var WATCHDOG_SILENCE_MS = 5 * 6e4;
|
|
780
|
-
var WATCHDOG_CHECK_INTERVAL_MS = 6e4;
|
|
781
|
-
var WATCHDOG_BATCH_MAX = 100;
|
|
782
|
-
var WATCHDOG_REQUEST_TIMEOUT_MS = 15e3;
|
|
783
|
-
var AggWebSocket = class {
|
|
784
|
-
constructor(options) {
|
|
785
|
-
this.ws = null;
|
|
786
|
-
// ── Subscription tracking ──
|
|
787
|
-
this.subs = /* @__PURE__ */ new Map();
|
|
788
|
-
this.pendingSubs = /* @__PURE__ */ new Set();
|
|
789
|
-
this.pendingTradeSubs = /* @__PURE__ */ new Set();
|
|
790
|
-
this.pendingResnapshots = /* @__PURE__ */ new Set();
|
|
791
|
-
// ── Post-connect batching (coalesces same-tick sub/unsub calls into one frame) ──
|
|
792
|
-
this.pendingFlushSubs = /* @__PURE__ */ new Set();
|
|
793
|
-
this.pendingFlushUnsubs = /* @__PURE__ */ new Set();
|
|
794
|
-
this.pendingFlushTradeSubs = /* @__PURE__ */ new Set();
|
|
795
|
-
this.pendingFlushTradeUnsubs = /* @__PURE__ */ new Set();
|
|
796
|
-
this.pendingFlushArbSubs = /* @__PURE__ */ new Set();
|
|
797
|
-
this.pendingFlushArbUnsubs = /* @__PURE__ */ new Set();
|
|
798
|
-
this.flushScheduled = false;
|
|
799
|
-
// ── Arb subscriptions ──
|
|
800
|
-
this.arbSubs = /* @__PURE__ */ new Map();
|
|
801
|
-
this.arbFeedCbs = /* @__PURE__ */ new Set();
|
|
802
|
-
/** Latest arb market update per marketId (last-value-wins, loss-tolerant). */
|
|
803
|
-
this.latestArb = /* @__PURE__ */ new Map();
|
|
804
|
-
// ── Orderbook state per market ──
|
|
805
|
-
this.books = /* @__PURE__ */ new Map();
|
|
806
|
-
/** Markets currently resyncing (awaiting snapshot after seq gap / checksum mismatch). */
|
|
807
|
-
this.resyncing = /* @__PURE__ */ new Set();
|
|
808
|
-
/**
|
|
809
|
-
* Per subscribed orderbook outcome: last time it made progress (subscribe,
|
|
810
|
-
* snapshot, applied delta) or was checked against REST (ms). Tracked from
|
|
811
|
-
* subscribe, not from the first snapshot, so a book that never arrives or
|
|
812
|
-
* is stuck resyncing is still found by the watchdog.
|
|
813
|
-
*/
|
|
814
|
-
this.bookCheckedAt = /* @__PURE__ */ new Map();
|
|
815
|
-
/** Outcomes the watchdog already resnapshotted; a repeat mismatch resubscribes. */
|
|
816
|
-
this.watchdogResnapshotted = /* @__PURE__ */ new Set();
|
|
817
|
-
this.watchdogTimer = null;
|
|
818
|
-
this.watchdogAbort = null;
|
|
819
|
-
this.watchdogPausedUntil = 0;
|
|
820
|
-
// ── Connection state ──
|
|
821
|
-
this.connecting = false;
|
|
822
|
-
this._connected = false;
|
|
823
|
-
this.reconnectAttempts = 0;
|
|
824
|
-
this.reconnectTimer = null;
|
|
825
|
-
this.staleTimer = null;
|
|
826
|
-
this.lastMessageTime = 0;
|
|
827
|
-
this.destroyed = false;
|
|
828
|
-
this.historyControllers = /* @__PURE__ */ new Set();
|
|
829
|
-
var _a, _b, _c;
|
|
830
|
-
this.deferBookViews = (_a = options.deferBookViews) != null ? _a : false;
|
|
831
|
-
this.url = options.url;
|
|
832
|
-
this.callbacks = (_b = options.callbacks) != null ? _b : {};
|
|
833
|
-
this.initialToken = options.initialToken;
|
|
834
|
-
this.enableLogs = (_c = options.enableLogs) != null ? _c : false;
|
|
835
|
-
this.bookWatchdog = options.bookWatchdog;
|
|
836
|
-
}
|
|
837
|
-
// ── Public API ──
|
|
838
|
-
get connected() {
|
|
839
|
-
return this._connected;
|
|
840
|
-
}
|
|
841
|
-
/** Decode dynamic authenticated REST bytes in the same processing environment as live data. */
|
|
842
|
-
decodeHistory(payload) {
|
|
843
|
-
return __async(this, null, function* () {
|
|
844
|
-
return decodeChartHistory(payload);
|
|
845
|
-
});
|
|
846
|
-
}
|
|
847
|
-
/** Immutable history decoder. Browser adapters execute this inside their Worker. */
|
|
848
|
-
loadHistory(manifest, options) {
|
|
849
|
-
return __async(this, null, function* () {
|
|
850
|
-
var _a, _b, _c;
|
|
851
|
-
if (this.destroyed) throw new Error("Market-data client disposed");
|
|
852
|
-
const controller = new AbortController();
|
|
853
|
-
const abort = () => {
|
|
854
|
-
var _a2;
|
|
855
|
-
return controller.abort((_a2 = options == null ? void 0 : options.signal) == null ? void 0 : _a2.reason);
|
|
856
|
-
};
|
|
857
|
-
(_a = options == null ? void 0 : options.signal) == null ? void 0 : _a.addEventListener("abort", abort, { once: true });
|
|
858
|
-
if ((_b = options == null ? void 0 : options.signal) == null ? void 0 : _b.aborted) abort();
|
|
859
|
-
this.historyControllers.add(controller);
|
|
860
|
-
try {
|
|
861
|
-
controller.signal.throwIfAborted();
|
|
862
|
-
const result = yield loadImmutableHistory({ manifest, signal: controller.signal });
|
|
863
|
-
controller.signal.throwIfAborted();
|
|
864
|
-
return result;
|
|
865
|
-
} finally {
|
|
866
|
-
this.historyControllers.delete(controller);
|
|
867
|
-
(_c = options == null ? void 0 : options.signal) == null ? void 0 : _c.removeEventListener("abort", abort);
|
|
868
|
-
}
|
|
869
|
-
});
|
|
870
|
-
}
|
|
871
|
-
/** Optional framework-independent host diagnostics, cleared on disposal. */
|
|
872
|
-
setHostDiagnostics(provider) {
|
|
873
|
-
this.hostDiagnostics = provider;
|
|
874
|
-
}
|
|
875
|
-
/** On-demand ownership diagnostics; contains no credentials or user/account data. */
|
|
876
|
-
getDiagnostics() {
|
|
877
|
-
var _a;
|
|
878
|
-
return {
|
|
879
|
-
connected: this.connected,
|
|
880
|
-
host: (_a = this.hostDiagnostics) == null ? void 0 : _a.call(this),
|
|
881
|
-
transport: this.destroyed ? "disposed" : "direct",
|
|
882
|
-
orderbookOutcomeIds: this.activeOrderbookMarkets(),
|
|
883
|
-
tradeOutcomeIds: this.activeTradeMarkets(),
|
|
884
|
-
arbMarketIds: this.activeArbMarkets(),
|
|
885
|
-
arbFeedSubscribers: this.arbFeedCbs.size,
|
|
886
|
-
cachedBooks: this.books.size,
|
|
887
|
-
cachedArb: this.latestArb.size,
|
|
888
|
-
resyncingBooks: this.resyncing.size,
|
|
889
|
-
pendingResnapshots: this.pendingResnapshots.size,
|
|
890
|
-
pendingHistoryRequests: this.historyControllers.size
|
|
891
|
-
};
|
|
892
|
-
}
|
|
893
|
-
/** Get the current orderbook state for an outcome (or null if no snapshot received yet). */
|
|
894
|
-
getBook(outcomeId) {
|
|
895
|
-
var _a, _b;
|
|
896
|
-
return (_b = (_a = this.books.get(outcomeId)) == null ? void 0 : _a.view()) != null ? _b : null;
|
|
897
|
-
}
|
|
898
|
-
/** Whether an outcome is currently resyncing (waiting for fresh snapshot). */
|
|
899
|
-
isResyncing(outcomeId) {
|
|
900
|
-
return this.resyncing.has(outcomeId);
|
|
901
|
-
}
|
|
902
|
-
/** Get the latest arb update for a market (or null if none received yet). */
|
|
903
|
-
getArb(marketId) {
|
|
904
|
-
var _a;
|
|
905
|
-
return (_a = this.latestArb.get(marketId)) != null ? _a : null;
|
|
906
|
-
}
|
|
907
|
-
/**
|
|
908
|
-
* Subscribe to per-market arb updates for a given marketId.
|
|
909
|
-
* Ref-counted: multiple callers for the same marketId share one server subscription.
|
|
910
|
-
* Returns an unsubscribe function.
|
|
911
|
-
*/
|
|
912
|
-
subscribeArb(marketId, cb) {
|
|
913
|
-
let entry = this.arbSubs.get(marketId);
|
|
914
|
-
if (!entry) {
|
|
915
|
-
entry = { refCount: 0, cbs: /* @__PURE__ */ new Set() };
|
|
916
|
-
this.arbSubs.set(marketId, entry);
|
|
917
|
-
this.ensureConnected();
|
|
918
|
-
if (this._connected) {
|
|
919
|
-
this.pendingFlushArbUnsubs.delete(marketId);
|
|
920
|
-
this.pendingFlushArbSubs.add(marketId);
|
|
921
|
-
this.scheduleFlush();
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
entry.cbs.add(cb);
|
|
925
|
-
entry.refCount++;
|
|
926
|
-
return () => {
|
|
927
|
-
const e = this.arbSubs.get(marketId);
|
|
928
|
-
if (!e) return;
|
|
929
|
-
e.cbs.delete(cb);
|
|
930
|
-
e.refCount--;
|
|
931
|
-
if (e.refCount <= 0) {
|
|
932
|
-
this.arbSubs.delete(marketId);
|
|
933
|
-
if (this._connected) {
|
|
934
|
-
if (this.pendingFlushArbSubs.has(marketId)) {
|
|
935
|
-
this.pendingFlushArbSubs.delete(marketId);
|
|
936
|
-
} else {
|
|
937
|
-
this.pendingFlushArbUnsubs.add(marketId);
|
|
938
|
-
this.scheduleFlush();
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
};
|
|
943
|
-
}
|
|
944
|
-
/**
|
|
945
|
-
* Subscribe to the global arb-feed batches.
|
|
946
|
-
* Only one server subscription is maintained regardless of how many callers.
|
|
947
|
-
* Returns an unsubscribe function.
|
|
948
|
-
*/
|
|
949
|
-
subscribeArbFeed(cb) {
|
|
950
|
-
const wasEmpty = this.arbFeedCbs.size === 0;
|
|
951
|
-
this.arbFeedCbs.add(cb);
|
|
952
|
-
if (wasEmpty) {
|
|
953
|
-
this.ensureConnected();
|
|
954
|
-
if (this._connected) {
|
|
955
|
-
this.send({ action: "subscribe", channel: "arb-feed" });
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
return () => {
|
|
959
|
-
this.arbFeedCbs.delete(cb);
|
|
960
|
-
if (this.arbFeedCbs.size === 0 && this._connected) {
|
|
961
|
-
this.send({ action: "unsubscribe", channel: "arb-feed" });
|
|
962
|
-
}
|
|
963
|
-
};
|
|
964
|
-
}
|
|
965
|
-
/**
|
|
966
|
-
* Subscribe to a feed by outcome ID.
|
|
967
|
-
* @param outcomeId The venueMarketOutcomeId to subscribe to.
|
|
968
|
-
* @param channel "orderbook" (default) or "trades".
|
|
969
|
-
* Returns an unsubscribe function (ref-counted).
|
|
970
|
-
*/
|
|
971
|
-
subscribe(outcomeId, channel = "orderbook") {
|
|
972
|
-
if (channel === "trades") {
|
|
973
|
-
return this._subscribeTrades(outcomeId);
|
|
974
|
-
}
|
|
975
|
-
let sub = this.subs.get(outcomeId);
|
|
976
|
-
if (!sub) {
|
|
977
|
-
sub = { refCount: 0, tradeRefs: 0 };
|
|
978
|
-
this.subs.set(outcomeId, sub);
|
|
979
|
-
}
|
|
980
|
-
if (sub.refCount === 0) {
|
|
981
|
-
this.bookCheckedAt.set(outcomeId, Date.now());
|
|
982
|
-
this.pendingSubs.add(outcomeId);
|
|
983
|
-
this.ensureConnected();
|
|
984
|
-
if (this._connected) {
|
|
985
|
-
this.pendingFlushUnsubs.delete(outcomeId);
|
|
986
|
-
this.pendingFlushSubs.add(outcomeId);
|
|
987
|
-
this.pendingSubs.delete(outcomeId);
|
|
988
|
-
this.scheduleFlush();
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
sub.refCount++;
|
|
992
|
-
let released = false;
|
|
993
|
-
return () => {
|
|
994
|
-
if (released) return;
|
|
995
|
-
released = true;
|
|
996
|
-
const s = this.subs.get(outcomeId);
|
|
997
|
-
if (!s) return;
|
|
998
|
-
s.refCount--;
|
|
999
|
-
if (s.refCount <= 0) {
|
|
1000
|
-
s.refCount = 0;
|
|
1001
|
-
if (s.tradeRefs <= 0) {
|
|
1002
|
-
this.subs.delete(outcomeId);
|
|
1003
|
-
this.books.delete(outcomeId);
|
|
1004
|
-
}
|
|
1005
|
-
this.resyncing.delete(outcomeId);
|
|
1006
|
-
this.bookCheckedAt.delete(outcomeId);
|
|
1007
|
-
this.watchdogResnapshotted.delete(outcomeId);
|
|
1008
|
-
if (this._connected) {
|
|
1009
|
-
if (this.pendingFlushSubs.has(outcomeId)) {
|
|
1010
|
-
this.pendingFlushSubs.delete(outcomeId);
|
|
1011
|
-
} else {
|
|
1012
|
-
this.pendingFlushUnsubs.add(outcomeId);
|
|
1013
|
-
this.scheduleFlush();
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
this.pendingSubs.delete(outcomeId);
|
|
1017
|
-
this.pendingResnapshots.delete(outcomeId);
|
|
1018
|
-
}
|
|
1019
|
-
};
|
|
1020
|
-
}
|
|
1021
|
-
/**
|
|
1022
|
-
* Subscribe to an outcome's trade feed.
|
|
1023
|
-
* @deprecated Use `subscribe(outcomeId, "trades")` instead.
|
|
1024
|
-
* Returns an unsubscribe function.
|
|
1025
|
-
*/
|
|
1026
|
-
subscribeTrades(outcomeId) {
|
|
1027
|
-
return this._subscribeTrades(outcomeId);
|
|
1028
|
-
}
|
|
1029
|
-
_subscribeTrades(outcomeId) {
|
|
1030
|
-
let sub = this.subs.get(outcomeId);
|
|
1031
|
-
if (!sub) {
|
|
1032
|
-
sub = { refCount: 0, tradeRefs: 0 };
|
|
1033
|
-
this.subs.set(outcomeId, sub);
|
|
1034
|
-
}
|
|
1035
|
-
if (sub.tradeRefs === 0) {
|
|
1036
|
-
this.pendingTradeSubs.add(outcomeId);
|
|
1037
|
-
this.ensureConnected();
|
|
1038
|
-
if (this._connected) {
|
|
1039
|
-
this.pendingFlushTradeUnsubs.delete(outcomeId);
|
|
1040
|
-
this.pendingFlushTradeSubs.add(outcomeId);
|
|
1041
|
-
this.pendingTradeSubs.delete(outcomeId);
|
|
1042
|
-
this.scheduleFlush();
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
sub.tradeRefs++;
|
|
1046
|
-
let released = false;
|
|
1047
|
-
return () => {
|
|
1048
|
-
if (released) return;
|
|
1049
|
-
released = true;
|
|
1050
|
-
const s = this.subs.get(outcomeId);
|
|
1051
|
-
if (!s) return;
|
|
1052
|
-
s.tradeRefs--;
|
|
1053
|
-
if (s.tradeRefs <= 0) {
|
|
1054
|
-
s.tradeRefs = 0;
|
|
1055
|
-
if (this._connected) {
|
|
1056
|
-
if (this.pendingFlushTradeSubs.has(outcomeId)) {
|
|
1057
|
-
this.pendingFlushTradeSubs.delete(outcomeId);
|
|
1058
|
-
} else {
|
|
1059
|
-
this.pendingFlushTradeUnsubs.add(outcomeId);
|
|
1060
|
-
this.scheduleFlush();
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
this.pendingTradeSubs.delete(outcomeId);
|
|
1064
|
-
this.pendingResnapshots.delete(outcomeId);
|
|
1065
|
-
if (s.refCount <= 0) {
|
|
1066
|
-
this.subs.delete(outcomeId);
|
|
1067
|
-
this.books.delete(outcomeId);
|
|
1068
|
-
this.resyncing.delete(outcomeId);
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
};
|
|
1072
|
-
}
|
|
1073
|
-
/** Send a JWT to authenticate (or re-authenticate) the connection. */
|
|
1074
|
-
authenticate(token) {
|
|
1075
|
-
this.initialToken = token;
|
|
1076
|
-
if (this._connected) {
|
|
1077
|
-
this.send({ action: "authenticate", token });
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
/** Request a fresh snapshot for one or more subscribed outcomes. */
|
|
1081
|
-
resnapshot(outcomeIdOrIds) {
|
|
1082
|
-
const outcomeIds = Array.isArray(outcomeIdOrIds) ? outcomeIdOrIds : [outcomeIdOrIds];
|
|
1083
|
-
outcomeIds.forEach((outcomeId) => {
|
|
1084
|
-
this.requestResnapshot(outcomeId, true);
|
|
1085
|
-
});
|
|
1086
|
-
}
|
|
1087
|
-
/** Connect (idempotent). Called automatically on first subscribe. */
|
|
1088
|
-
connect() {
|
|
1089
|
-
this.ensureConnected();
|
|
1090
|
-
}
|
|
1091
|
-
/** Disconnect and clean up. Reusable — call connect() to reconnect. */
|
|
1092
|
-
disconnect() {
|
|
1093
|
-
var _a, _b;
|
|
1094
|
-
this.cancelReconnect();
|
|
1095
|
-
this.cancelStaleTimer();
|
|
1096
|
-
this._connected = false;
|
|
1097
|
-
this.connecting = false;
|
|
1098
|
-
if (this.ws) {
|
|
1099
|
-
this.ws.onclose = null;
|
|
1100
|
-
this.ws.close();
|
|
1101
|
-
this.ws = null;
|
|
1102
|
-
}
|
|
1103
|
-
(_b = (_a = this.callbacks).onConnectionStateChange) == null ? void 0 : _b.call(_a, false);
|
|
1104
|
-
}
|
|
1105
|
-
/** Permanently destroy. Cannot reconnect after this. */
|
|
1106
|
-
destroy() {
|
|
1107
|
-
var _a;
|
|
1108
|
-
this.destroyed = true;
|
|
1109
|
-
for (const controller of this.historyControllers)
|
|
1110
|
-
controller.abort(new Error("Market-data client disposed"));
|
|
1111
|
-
this.historyControllers.clear();
|
|
1112
|
-
this.disconnect();
|
|
1113
|
-
this.hostDiagnostics = void 0;
|
|
1114
|
-
this.callbacks = {};
|
|
1115
|
-
this.subs.clear();
|
|
1116
|
-
this.books.clear();
|
|
1117
|
-
this.resyncing.clear();
|
|
1118
|
-
if (this.watchdogTimer) clearInterval(this.watchdogTimer);
|
|
1119
|
-
this.watchdogTimer = null;
|
|
1120
|
-
(_a = this.watchdogAbort) == null ? void 0 : _a.abort();
|
|
1121
|
-
this.watchdogAbort = null;
|
|
1122
|
-
this.bookCheckedAt.clear();
|
|
1123
|
-
this.watchdogResnapshotted.clear();
|
|
1124
|
-
this.pendingSubs.clear();
|
|
1125
|
-
this.pendingTradeSubs.clear();
|
|
1126
|
-
this.pendingResnapshots.clear();
|
|
1127
|
-
this.pendingFlushSubs.clear();
|
|
1128
|
-
this.pendingFlushUnsubs.clear();
|
|
1129
|
-
this.pendingFlushTradeSubs.clear();
|
|
1130
|
-
this.pendingFlushTradeUnsubs.clear();
|
|
1131
|
-
this.arbSubs.clear();
|
|
1132
|
-
this.arbFeedCbs.clear();
|
|
1133
|
-
this.latestArb.clear();
|
|
1134
|
-
this.pendingFlushArbSubs.clear();
|
|
1135
|
-
this.pendingFlushArbUnsubs.clear();
|
|
1136
|
-
this.flushScheduled = false;
|
|
1137
|
-
}
|
|
1138
|
-
/** Update callbacks (e.g., after React re-render). */
|
|
1139
|
-
setCallbacks(callbacks) {
|
|
1140
|
-
this.callbacks = callbacks;
|
|
1141
|
-
}
|
|
1142
|
-
// ── Connection management ──
|
|
1143
|
-
ensureConnected() {
|
|
1144
|
-
var _a;
|
|
1145
|
-
if (this.destroyed) return;
|
|
1146
|
-
if (((_a = this.ws) == null ? void 0 : _a.readyState) === WebSocket.OPEN || this.connecting) return;
|
|
1147
|
-
this.doConnect();
|
|
1148
|
-
}
|
|
1149
|
-
doConnect() {
|
|
1150
|
-
if (this.destroyed) return;
|
|
1151
|
-
this.connecting = true;
|
|
1152
|
-
const ws = new WebSocket(this.url);
|
|
1153
|
-
this.ws = ws;
|
|
1154
|
-
ws.onopen = () => {
|
|
1155
|
-
if (this.destroyed || this.ws !== ws) return;
|
|
1156
|
-
this.connecting = false;
|
|
1157
|
-
this.reconnectAttempts = 0;
|
|
1158
|
-
this.resetStaleTimer();
|
|
1159
|
-
if (this.initialToken) {
|
|
1160
|
-
this.send({ action: "authenticate", token: this.initialToken });
|
|
1161
|
-
}
|
|
1162
|
-
};
|
|
1163
|
-
ws.onmessage = (event) => {
|
|
1164
|
-
var _a, _b;
|
|
1165
|
-
if (this.destroyed || this.ws !== ws) return;
|
|
1166
|
-
this.lastMessageTime = Date.now();
|
|
1167
|
-
(_b = (_a = this.callbacks).onFrameReceived) == null ? void 0 : _b.call(_a, this.lastMessageTime);
|
|
1168
|
-
this.resetStaleTimer();
|
|
1169
|
-
try {
|
|
1170
|
-
const raw = JSON.parse(event.data);
|
|
1171
|
-
this.handleMessage(raw);
|
|
1172
|
-
} catch (e) {
|
|
1173
|
-
}
|
|
1174
|
-
};
|
|
1175
|
-
ws.onclose = () => {
|
|
1176
|
-
var _a, _b;
|
|
1177
|
-
this.ws = null;
|
|
1178
|
-
this.connecting = false;
|
|
1179
|
-
const wasConnected = this._connected;
|
|
1180
|
-
this._connected = false;
|
|
1181
|
-
this.cancelStaleTimer();
|
|
1182
|
-
if (wasConnected) {
|
|
1183
|
-
(_b = (_a = this.callbacks).onConnectionStateChange) == null ? void 0 : _b.call(_a, false);
|
|
1184
|
-
}
|
|
1185
|
-
if (!this.destroyed && (this.subs.size > 0 || this.arbSubs.size > 0 || this.arbFeedCbs.size > 0)) {
|
|
1186
|
-
this.scheduleReconnect();
|
|
1187
|
-
}
|
|
1188
|
-
};
|
|
1189
|
-
ws.onerror = () => {
|
|
1190
|
-
};
|
|
1191
|
-
}
|
|
1192
|
-
scheduleReconnect() {
|
|
1193
|
-
this.cancelReconnect();
|
|
1194
|
-
const delay = Math.min(
|
|
1195
|
-
RECONNECT_BASE_MS * Math.pow(2, this.reconnectAttempts),
|
|
1196
|
-
RECONNECT_MAX_MS
|
|
1197
|
-
);
|
|
1198
|
-
this.reconnectAttempts++;
|
|
1199
|
-
this.emitDiagnostic({ type: "reconnect", attempt: this.reconnectAttempts, delayMs: delay });
|
|
1200
|
-
this.reconnectTimer = setTimeout(() => {
|
|
1201
|
-
this.reconnectTimer = null;
|
|
1202
|
-
this.doConnect();
|
|
1203
|
-
}, delay);
|
|
1204
|
-
}
|
|
1205
|
-
cancelReconnect() {
|
|
1206
|
-
if (this.reconnectTimer) {
|
|
1207
|
-
clearTimeout(this.reconnectTimer);
|
|
1208
|
-
this.reconnectTimer = null;
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
// ── Staleness detection ──
|
|
1212
|
-
resetStaleTimer() {
|
|
1213
|
-
this.cancelStaleTimer();
|
|
1214
|
-
this.staleTimer = setTimeout(() => {
|
|
1215
|
-
const age = Date.now() - this.lastMessageTime;
|
|
1216
|
-
this.emitDiagnostic({ type: "stale_connection", lastMessageAge: age });
|
|
1217
|
-
if (this.ws) {
|
|
1218
|
-
this.ws.close();
|
|
1219
|
-
}
|
|
1220
|
-
}, STALE_TIMEOUT_MS);
|
|
1221
|
-
}
|
|
1222
|
-
cancelStaleTimer() {
|
|
1223
|
-
if (this.staleTimer) {
|
|
1224
|
-
clearTimeout(this.staleTimer);
|
|
1225
|
-
this.staleTimer = null;
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
// ── Message handling ──
|
|
1229
|
-
handleMessage(raw) {
|
|
1230
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
|
|
1231
|
-
const type = raw.type;
|
|
1232
|
-
if (["orderbook_snapshot", "orderbook_delta", "trade"].includes(type) && !validMarketFrame(raw)) {
|
|
1233
|
-
(_b = (_a = this.callbacks).onError) == null ? void 0 : _b.call(_a, { type: "error", message: "Invalid market-data frame" });
|
|
1234
|
-
if (typeof raw.outcomeId === "string" && this.subs.has(raw.outcomeId))
|
|
1235
|
-
this.requestResnapshot(raw.outcomeId);
|
|
1236
|
-
return;
|
|
1237
|
-
}
|
|
1238
|
-
switch (type) {
|
|
1239
|
-
case "orderbook_snapshot":
|
|
1240
|
-
this.handleSnapshot(raw);
|
|
1241
|
-
break;
|
|
1242
|
-
case "orderbook_delta":
|
|
1243
|
-
this.handleDelta(raw);
|
|
1244
|
-
break;
|
|
1245
|
-
case "trade":
|
|
1246
|
-
this.handleTrade(raw);
|
|
1247
|
-
break;
|
|
1248
|
-
case "heartbeat":
|
|
1249
|
-
this.handleHeartbeat(raw);
|
|
1250
|
-
break;
|
|
1251
|
-
case "subscribed":
|
|
1252
|
-
(_d = (_c = this.callbacks).onSubscribed) == null ? void 0 : _d.call(_c, raw);
|
|
1253
|
-
break;
|
|
1254
|
-
case "unsubscribed":
|
|
1255
|
-
(_f = (_e = this.callbacks).onUnsubscribed) == null ? void 0 : _f.call(_e, raw);
|
|
1256
|
-
break;
|
|
1257
|
-
case "connected":
|
|
1258
|
-
this.handleConnected(raw);
|
|
1259
|
-
break;
|
|
1260
|
-
case "authenticated":
|
|
1261
|
-
(_h = (_g = this.callbacks).onAuthenticated) == null ? void 0 : _h.call(_g, raw);
|
|
1262
|
-
break;
|
|
1263
|
-
case "market_resolved":
|
|
1264
|
-
this.handleMarketResolved(raw);
|
|
1265
|
-
break;
|
|
1266
|
-
case "error":
|
|
1267
|
-
(_j = (_i = this.callbacks).onError) == null ? void 0 : _j.call(_i, raw);
|
|
1268
|
-
break;
|
|
1269
|
-
case "order_submitted":
|
|
1270
|
-
this.handleOrderSubmitted(raw);
|
|
1271
|
-
break;
|
|
1272
|
-
case "balance_update":
|
|
1273
|
-
this.handleBalanceUpdate(raw);
|
|
1274
|
-
break;
|
|
1275
|
-
case "order_event":
|
|
1276
|
-
(_l = (_k = this.callbacks).onOrderEvent) == null ? void 0 : _l.call(_k, raw);
|
|
1277
|
-
break;
|
|
1278
|
-
case "redeem_event":
|
|
1279
|
-
this.handleRedeemEvent(raw);
|
|
1280
|
-
break;
|
|
1281
|
-
case "withdrawal_lifecycle":
|
|
1282
|
-
(_n = (_m = this.callbacks).onWithdrawalLifecycle) == null ? void 0 : _n.call(_m, raw);
|
|
1283
|
-
break;
|
|
1284
|
-
case "arb_market_update": {
|
|
1285
|
-
const arbMsg = raw;
|
|
1286
|
-
this.latestArb.set(arbMsg.marketId, arbMsg);
|
|
1287
|
-
const arbEntry = this.arbSubs.get(arbMsg.marketId);
|
|
1288
|
-
if (arbEntry) {
|
|
1289
|
-
for (const cb of arbEntry.cbs) cb(arbMsg);
|
|
1290
|
-
}
|
|
1291
|
-
(_p = (_o = this.callbacks).onArbMarket) == null ? void 0 : _p.call(_o, arbMsg);
|
|
1292
|
-
break;
|
|
1293
|
-
}
|
|
1294
|
-
case "arb_feed_batch": {
|
|
1295
|
-
const feedMsg = raw;
|
|
1296
|
-
for (const cb of this.arbFeedCbs) cb(feedMsg);
|
|
1297
|
-
(_r = (_q = this.callbacks).onArbFeed) == null ? void 0 : _r.call(_q, feedMsg);
|
|
1298
|
-
break;
|
|
1299
|
-
}
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
/**
|
|
1303
|
-
* Server confirmed the connection — gateway has validated our appId and is
|
|
1304
|
-
* ready to accept subscriptions. Now flush all pending subs.
|
|
1305
|
-
*/
|
|
1306
|
-
handleConnected(msg) {
|
|
1307
|
-
var _a, _b, _c, _d, _e;
|
|
1308
|
-
this._connected = true;
|
|
1309
|
-
if (this.bookWatchdog && !this.watchdogTimer && !this.destroyed) {
|
|
1310
|
-
this.watchdogTimer = setInterval(
|
|
1311
|
-
() => void this.checkSilentBooks(),
|
|
1312
|
-
(_a = this.bookWatchdog.checkIntervalMs) != null ? _a : WATCHDOG_CHECK_INTERVAL_MS
|
|
1313
|
-
);
|
|
1314
|
-
}
|
|
1315
|
-
(_c = (_b = this.callbacks).onConnectionStateChange) == null ? void 0 : _c.call(_b, true);
|
|
1316
|
-
(_e = (_d = this.callbacks).onConnected) == null ? void 0 : _e.call(_d, msg);
|
|
1317
|
-
const orderbookSet = new Set(this.activeOrderbookMarkets());
|
|
1318
|
-
const reconnectedAt = Date.now();
|
|
1319
|
-
for (const id of orderbookSet) {
|
|
1320
|
-
if (this.bookCheckedAt.has(id)) this.bookCheckedAt.set(id, reconnectedAt);
|
|
1321
|
-
}
|
|
1322
|
-
this.pendingSubs.forEach((id) => orderbookSet.add(id));
|
|
1323
|
-
this.pendingFlushSubs.forEach((id) => orderbookSet.add(id));
|
|
1324
|
-
const orderbookIds = Array.from(orderbookSet);
|
|
1325
|
-
if (orderbookIds.length > 0) {
|
|
1326
|
-
this.sendSubscribe(orderbookIds);
|
|
1327
|
-
}
|
|
1328
|
-
this.pendingSubs.clear();
|
|
1329
|
-
this.pendingFlushSubs.clear();
|
|
1330
|
-
this.pendingFlushUnsubs.clear();
|
|
1331
|
-
const tradeSet = new Set(this.activeTradeMarkets());
|
|
1332
|
-
this.pendingTradeSubs.forEach((id) => tradeSet.add(id));
|
|
1333
|
-
this.pendingFlushTradeSubs.forEach((id) => tradeSet.add(id));
|
|
1334
|
-
const tradeIds = Array.from(tradeSet);
|
|
1335
|
-
if (tradeIds.length > 0) {
|
|
1336
|
-
this.send({ action: "subscribe", channel: "trades", outcomeIds: tradeIds });
|
|
1337
|
-
}
|
|
1338
|
-
this.pendingTradeSubs.clear();
|
|
1339
|
-
this.pendingFlushTradeSubs.clear();
|
|
1340
|
-
this.pendingFlushTradeUnsubs.clear();
|
|
1341
|
-
const resnapshotIds = Array.from(this.pendingResnapshots);
|
|
1342
|
-
if (resnapshotIds.length > 0) {
|
|
1343
|
-
this.send({ action: "resnapshot", channel: "orderbook", outcomeIds: resnapshotIds });
|
|
1344
|
-
}
|
|
1345
|
-
this.pendingResnapshots.clear();
|
|
1346
|
-
const arbSet = new Set(this.activeArbMarkets());
|
|
1347
|
-
this.pendingFlushArbSubs.forEach((id) => arbSet.add(id));
|
|
1348
|
-
const arbIds = Array.from(arbSet);
|
|
1349
|
-
if (arbIds.length > 0) {
|
|
1350
|
-
this.send({ action: "subscribe", channel: "arb", marketIds: arbIds });
|
|
1351
|
-
}
|
|
1352
|
-
this.pendingFlushArbSubs.clear();
|
|
1353
|
-
this.pendingFlushArbUnsubs.clear();
|
|
1354
|
-
if (this.arbFeedCbs.size > 0) {
|
|
1355
|
-
this.send({ action: "subscribe", channel: "arb-feed" });
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
handleSnapshot(raw) {
|
|
1359
|
-
var _a, _b, _c, _d;
|
|
1360
|
-
if (!this.subs.has(raw.outcomeId)) return;
|
|
1361
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1362
|
-
const book = snapshotToOrderbook(msg);
|
|
1363
|
-
this.books.set(msg.outcomeId, new IndexedOrderbook(book));
|
|
1364
|
-
this.bookCheckedAt.set(msg.outcomeId, Date.now());
|
|
1365
|
-
this.resyncing.delete(msg.outcomeId);
|
|
1366
|
-
this.pendingResnapshots.delete(msg.outcomeId);
|
|
1367
|
-
this.debugOrderbook("snapshot_applied", {
|
|
1368
|
-
outcomeId: msg.outcomeId,
|
|
1369
|
-
seq: msg.seq,
|
|
1370
|
-
checksum: msg.checksum,
|
|
1371
|
-
bidsTop: this.summarizeTopLevels(book.bids),
|
|
1372
|
-
asksTop: this.summarizeTopLevels(book.asks)
|
|
1373
|
-
});
|
|
1374
|
-
(_b = (_a = this.callbacks).onBookTick) == null ? void 0 : _b.call(_a, msg.outcomeId, {
|
|
1375
|
-
midpoint: msg.midpoint,
|
|
1376
|
-
timestamp: msg.timestamp,
|
|
1377
|
-
source: "snapshot"
|
|
1378
|
-
});
|
|
1379
|
-
if (!this.deferBookViews) (_d = (_c = this.callbacks).onSnapshot) == null ? void 0 : _d.call(_c, msg.outcomeId, book);
|
|
1380
|
-
}
|
|
1381
|
-
handleDelta(raw) {
|
|
1382
|
-
var _a, _b, _c, _d;
|
|
1383
|
-
if (!this.subs.has(raw.outcomeId)) return;
|
|
1384
|
-
const outcomeId = raw.outcomeId;
|
|
1385
|
-
const current = this.books.get(outcomeId);
|
|
1386
|
-
if (!current) {
|
|
1387
|
-
this.debugOrderbook("delta_missing_snapshot", { outcomeId, seq: raw.seq });
|
|
1388
|
-
this.requestResnapshot(outcomeId);
|
|
1389
|
-
return;
|
|
1390
|
-
}
|
|
1391
|
-
if (raw.seq <= current.seq) {
|
|
1392
|
-
this.debugOrderbook("delta_stale_ignored", {
|
|
1393
|
-
outcomeId,
|
|
1394
|
-
currentSeq: current.seq,
|
|
1395
|
-
receivedSeq: raw.seq
|
|
1396
|
-
});
|
|
1397
|
-
return;
|
|
1398
|
-
}
|
|
1399
|
-
if (raw.seq > current.seq + 1) {
|
|
1400
|
-
this.debugOrderbook("delta_seq_gap", {
|
|
1401
|
-
outcomeId,
|
|
1402
|
-
expectedSeq: current.seq + 1,
|
|
1403
|
-
receivedSeq: raw.seq
|
|
1404
|
-
});
|
|
1405
|
-
this.emitDiagnostic({
|
|
1406
|
-
type: "seq_gap",
|
|
1407
|
-
marketId: outcomeId,
|
|
1408
|
-
outcomeId,
|
|
1409
|
-
expected: current.seq + 1,
|
|
1410
|
-
received: raw.seq
|
|
1411
|
-
});
|
|
1412
|
-
this.requestResnapshot(outcomeId);
|
|
1413
|
-
return;
|
|
1414
|
-
}
|
|
1415
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1416
|
-
const computed = current.apply(msg);
|
|
1417
|
-
if (computed !== msg.checksum) {
|
|
1418
|
-
this.debugOrderbook("delta_checksum_mismatch", {
|
|
1419
|
-
outcomeId,
|
|
1420
|
-
seq: msg.seq,
|
|
1421
|
-
expected: msg.checksum,
|
|
1422
|
-
computed
|
|
1423
|
-
});
|
|
1424
|
-
this.emitDiagnostic({
|
|
1425
|
-
type: "checksum_mismatch",
|
|
1426
|
-
marketId: outcomeId,
|
|
1427
|
-
outcomeId,
|
|
1428
|
-
expected: msg.checksum,
|
|
1429
|
-
computed
|
|
1430
|
-
});
|
|
1431
|
-
this.requestResnapshot(outcomeId);
|
|
1432
|
-
return;
|
|
1433
|
-
}
|
|
1434
|
-
this.bookCheckedAt.set(outcomeId, Date.now());
|
|
1435
|
-
this.watchdogResnapshotted.delete(outcomeId);
|
|
1436
|
-
(_b = (_a = this.callbacks).onBookTick) == null ? void 0 : _b.call(_a, outcomeId, {
|
|
1437
|
-
midpoint: msg.midpoint,
|
|
1438
|
-
timestamp: msg.timestamp,
|
|
1439
|
-
source: "delta"
|
|
1440
|
-
});
|
|
1441
|
-
if (!this.deferBookViews) (_d = (_c = this.callbacks).onDelta) == null ? void 0 : _d.call(_c, outcomeId, current.view());
|
|
1442
|
-
}
|
|
1443
|
-
handleTrade(raw) {
|
|
1444
|
-
var _a, _b;
|
|
1445
|
-
if (!this.subs.has(raw.outcomeId)) return;
|
|
1446
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1447
|
-
(_b = (_a = this.callbacks).onTrade) == null ? void 0 : _b.call(_a, msg);
|
|
1448
|
-
}
|
|
1449
|
-
handleHeartbeat(raw) {
|
|
1450
|
-
var _a, _b;
|
|
1451
|
-
const msg = __spreadProps(__spreadValues({}, raw), { ts: raw.ts / 1e3 });
|
|
1452
|
-
(_b = (_a = this.callbacks).onHeartbeat) == null ? void 0 : _b.call(_a, msg);
|
|
1453
|
-
}
|
|
1454
|
-
handleMarketResolved(raw) {
|
|
1455
|
-
var _a, _b;
|
|
1456
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1457
|
-
this.books.delete(msg.outcomeId);
|
|
1458
|
-
this.bookCheckedAt.delete(msg.outcomeId);
|
|
1459
|
-
this.watchdogResnapshotted.delete(msg.outcomeId);
|
|
1460
|
-
this.pendingResnapshots.delete(msg.outcomeId);
|
|
1461
|
-
this.resyncing.delete(msg.outcomeId);
|
|
1462
|
-
(_b = (_a = this.callbacks).onMarketResolved) == null ? void 0 : _b.call(_a, msg);
|
|
1463
|
-
}
|
|
1464
|
-
handleOrderSubmitted(raw) {
|
|
1465
|
-
var _a, _b;
|
|
1466
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1467
|
-
(_b = (_a = this.callbacks).onOrderSubmitted) == null ? void 0 : _b.call(_a, msg);
|
|
1468
|
-
}
|
|
1469
|
-
handleBalanceUpdate(raw) {
|
|
1470
|
-
var _a, _b;
|
|
1471
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1472
|
-
(_b = (_a = this.callbacks).onBalanceUpdate) == null ? void 0 : _b.call(_a, msg);
|
|
1473
|
-
}
|
|
1474
|
-
handleRedeemEvent(raw) {
|
|
1475
|
-
var _a, _b;
|
|
1476
|
-
const msg = __spreadProps(__spreadValues({}, raw), { timestamp: raw.timestamp / 1e3 });
|
|
1477
|
-
(_b = (_a = this.callbacks).onRedeemEvent) == null ? void 0 : _b.call(_a, msg);
|
|
1478
|
-
}
|
|
1479
|
-
// ── Book watchdog ──
|
|
1480
|
-
/**
|
|
1481
|
-
* Heartbeats prove the socket, not each stream. Every subscribed outcome
|
|
1482
|
-
* with no progress for `silenceMs` is checked against the REST `seq`:
|
|
1483
|
-
*
|
|
1484
|
-
* - book present, not resyncing, same `seq` → the market is just quiet;
|
|
1485
|
-
* - different `seq`, no book (snapshot never arrived, or a resubscribe's
|
|
1486
|
-
* snapshot was lost), or stuck resyncing (any recovery whose snapshot
|
|
1487
|
-
* was lost) → resnapshot, then resubscribe on the next overdue check;
|
|
1488
|
-
* - REST can't serve it (`null`) → counted as an attempt, so the next
|
|
1489
|
-
* batch moves on to other outcomes instead of retrying the same 100.
|
|
1490
|
-
*/
|
|
1491
|
-
checkSilentBooks() {
|
|
1492
|
-
return __async(this, null, function* () {
|
|
1493
|
-
var _a;
|
|
1494
|
-
const opts = this.bookWatchdog;
|
|
1495
|
-
if (!opts || !this._connected || this.watchdogAbort) return;
|
|
1496
|
-
const now = Date.now();
|
|
1497
|
-
if (now < this.watchdogPausedUntil) return;
|
|
1498
|
-
const silenceMs = (_a = opts.silenceMs) != null ? _a : WATCHDOG_SILENCE_MS;
|
|
1499
|
-
const silent = this.activeOrderbookMarkets().filter((id) => this.bookCheckedAt.has(id)).filter((id) => now - this.bookCheckedAt.get(id) >= silenceMs).sort((a, b) => this.bookCheckedAt.get(a) - this.bookCheckedAt.get(b)).slice(0, WATCHDOG_BATCH_MAX);
|
|
1500
|
-
if (silent.length === 0) return;
|
|
1501
|
-
const checkedAt = new Map(silent.map((id) => [id, this.bookCheckedAt.get(id)]));
|
|
1502
|
-
const abort = new AbortController();
|
|
1503
|
-
this.watchdogAbort = abort;
|
|
1504
|
-
const timeout = setTimeout(() => abort.abort(), WATCHDOG_REQUEST_TIMEOUT_MS);
|
|
1505
|
-
try {
|
|
1506
|
-
const url = new URL(`${opts.baseUrl.replace(/\/$/, "")}/orderbooks/outcomes`);
|
|
1507
|
-
url.searchParams.set("venueMarketOutcomeIds", silent.join(","));
|
|
1508
|
-
url.searchParams.set("depth", "1");
|
|
1509
|
-
const response = yield fetch(url, { headers: opts.headers, signal: abort.signal });
|
|
1510
|
-
if (!response.ok) {
|
|
1511
|
-
const retryAfterS = Number(response.headers.get("retry-after"));
|
|
1512
|
-
if (response.status === 429 && retryAfterS > 0) {
|
|
1513
|
-
this.watchdogPausedUntil = Date.now() + retryAfterS * 1e3;
|
|
1514
|
-
}
|
|
1515
|
-
this.emitDiagnostic({ type: "book_watchdog_error", status: response.status });
|
|
1516
|
-
return;
|
|
1517
|
-
}
|
|
1518
|
-
const body = yield response.json();
|
|
1519
|
-
if (this.destroyed) return;
|
|
1520
|
-
silent.forEach((outcomeId, i) => {
|
|
1521
|
-
var _a2, _b;
|
|
1522
|
-
if (this.bookCheckedAt.get(outcomeId) !== checkedAt.get(outcomeId)) return;
|
|
1523
|
-
const server = (_a2 = body.data) == null ? void 0 : _a2[i];
|
|
1524
|
-
if (!server) {
|
|
1525
|
-
this.bookCheckedAt.set(outcomeId, Date.now());
|
|
1526
|
-
return;
|
|
1527
|
-
}
|
|
1528
|
-
const book = this.books.get(outcomeId);
|
|
1529
|
-
if (book && !this.resyncing.has(outcomeId) && server.seq === book.seq) {
|
|
1530
|
-
this.bookCheckedAt.set(outcomeId, Date.now());
|
|
1531
|
-
this.watchdogResnapshotted.delete(outcomeId);
|
|
1532
|
-
return;
|
|
1533
|
-
}
|
|
1534
|
-
const action = this.watchdogResnapshotted.has(outcomeId) ? "resubscribe" : "resnapshot";
|
|
1535
|
-
this.emitDiagnostic({
|
|
1536
|
-
type: "book_watchdog_resync",
|
|
1537
|
-
outcomeId,
|
|
1538
|
-
localSeq: (_b = book == null ? void 0 : book.seq) != null ? _b : null,
|
|
1539
|
-
serverSeq: server.seq,
|
|
1540
|
-
action
|
|
1541
|
-
});
|
|
1542
|
-
this.bookCheckedAt.set(outcomeId, Date.now());
|
|
1543
|
-
if (action === "resubscribe") {
|
|
1544
|
-
this.watchdogResnapshotted.delete(outcomeId);
|
|
1545
|
-
this.books.delete(outcomeId);
|
|
1546
|
-
this.resyncing.add(outcomeId);
|
|
1547
|
-
this.send({ action: "unsubscribe", channel: "orderbook", outcomeIds: [outcomeId] });
|
|
1548
|
-
this.sendSubscribe([outcomeId]);
|
|
1549
|
-
} else {
|
|
1550
|
-
this.watchdogResnapshotted.add(outcomeId);
|
|
1551
|
-
this.requestResnapshot(outcomeId, true);
|
|
1552
|
-
}
|
|
1553
|
-
});
|
|
1554
|
-
} catch (e) {
|
|
1555
|
-
if (!this.destroyed) this.emitDiagnostic({ type: "book_watchdog_error", status: null });
|
|
1556
|
-
} finally {
|
|
1557
|
-
clearTimeout(timeout);
|
|
1558
|
-
if (this.watchdogAbort === abort) this.watchdogAbort = null;
|
|
1559
|
-
}
|
|
1560
|
-
});
|
|
1561
|
-
}
|
|
1562
|
-
// ── Resnapshot ──
|
|
1563
|
-
requestResnapshot(outcomeId, force = false) {
|
|
1564
|
-
if (this.resyncing.has(outcomeId) && !force) return;
|
|
1565
|
-
this.resyncing.add(outcomeId);
|
|
1566
|
-
if (this._connected) {
|
|
1567
|
-
this.send({ action: "resnapshot", channel: "orderbook", outcomeIds: [outcomeId] });
|
|
1568
|
-
this.pendingResnapshots.delete(outcomeId);
|
|
1569
|
-
return;
|
|
1570
|
-
}
|
|
1571
|
-
this.pendingResnapshots.add(outcomeId);
|
|
1572
|
-
this.ensureConnected();
|
|
1573
|
-
}
|
|
1574
|
-
// ── Helpers ──
|
|
1575
|
-
/**
|
|
1576
|
-
* Schedule a microtask that flushes queued subscribe/unsubscribe frames.
|
|
1577
|
-
* Coalesces multiple same-tick sub/unsub calls into at most one frame per
|
|
1578
|
-
* channel+action pair.
|
|
1579
|
-
*/
|
|
1580
|
-
scheduleFlush() {
|
|
1581
|
-
if (this.flushScheduled) return;
|
|
1582
|
-
this.flushScheduled = true;
|
|
1583
|
-
queueMicrotask(() => {
|
|
1584
|
-
this.flushScheduled = false;
|
|
1585
|
-
if (!this._connected) {
|
|
1586
|
-
this.pendingFlushSubs.clear();
|
|
1587
|
-
this.pendingFlushUnsubs.clear();
|
|
1588
|
-
this.pendingFlushTradeSubs.clear();
|
|
1589
|
-
this.pendingFlushTradeUnsubs.clear();
|
|
1590
|
-
this.pendingFlushArbSubs.clear();
|
|
1591
|
-
this.pendingFlushArbUnsubs.clear();
|
|
1592
|
-
return;
|
|
1593
|
-
}
|
|
1594
|
-
this.flushPending();
|
|
1595
|
-
});
|
|
1596
|
-
}
|
|
1597
|
-
flushPending() {
|
|
1598
|
-
for (const id of [...this.pendingFlushSubs]) {
|
|
1599
|
-
if (this.pendingFlushUnsubs.has(id)) {
|
|
1600
|
-
this.pendingFlushSubs.delete(id);
|
|
1601
|
-
this.pendingFlushUnsubs.delete(id);
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
if (this.pendingFlushSubs.size > 0) {
|
|
1605
|
-
this.sendSubscribe(Array.from(this.pendingFlushSubs));
|
|
1606
|
-
this.pendingFlushSubs.clear();
|
|
1607
|
-
}
|
|
1608
|
-
if (this.pendingFlushUnsubs.size > 0) {
|
|
1609
|
-
this.send({
|
|
1610
|
-
action: "unsubscribe",
|
|
1611
|
-
channel: "orderbook",
|
|
1612
|
-
outcomeIds: Array.from(this.pendingFlushUnsubs)
|
|
1613
|
-
});
|
|
1614
|
-
this.pendingFlushUnsubs.clear();
|
|
1615
|
-
}
|
|
1616
|
-
for (const id of [...this.pendingFlushTradeSubs]) {
|
|
1617
|
-
if (this.pendingFlushTradeUnsubs.has(id)) {
|
|
1618
|
-
this.pendingFlushTradeSubs.delete(id);
|
|
1619
|
-
this.pendingFlushTradeUnsubs.delete(id);
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
|
-
if (this.pendingFlushTradeSubs.size > 0) {
|
|
1623
|
-
this.send({
|
|
1624
|
-
action: "subscribe",
|
|
1625
|
-
channel: "trades",
|
|
1626
|
-
outcomeIds: Array.from(this.pendingFlushTradeSubs)
|
|
1627
|
-
});
|
|
1628
|
-
this.pendingFlushTradeSubs.clear();
|
|
1629
|
-
}
|
|
1630
|
-
if (this.pendingFlushTradeUnsubs.size > 0) {
|
|
1631
|
-
this.send({
|
|
1632
|
-
action: "unsubscribe",
|
|
1633
|
-
channel: "trades",
|
|
1634
|
-
outcomeIds: Array.from(this.pendingFlushTradeUnsubs)
|
|
1635
|
-
});
|
|
1636
|
-
this.pendingFlushTradeUnsubs.clear();
|
|
1637
|
-
}
|
|
1638
|
-
for (const id of [...this.pendingFlushArbSubs]) {
|
|
1639
|
-
if (this.pendingFlushArbUnsubs.has(id)) {
|
|
1640
|
-
this.pendingFlushArbSubs.delete(id);
|
|
1641
|
-
this.pendingFlushArbUnsubs.delete(id);
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
if (this.pendingFlushArbSubs.size > 0) {
|
|
1645
|
-
this.send({
|
|
1646
|
-
action: "subscribe",
|
|
1647
|
-
channel: "arb",
|
|
1648
|
-
marketIds: Array.from(this.pendingFlushArbSubs)
|
|
1649
|
-
});
|
|
1650
|
-
this.pendingFlushArbSubs.clear();
|
|
1651
|
-
}
|
|
1652
|
-
if (this.pendingFlushArbUnsubs.size > 0) {
|
|
1653
|
-
this.send({
|
|
1654
|
-
action: "unsubscribe",
|
|
1655
|
-
channel: "arb",
|
|
1656
|
-
marketIds: Array.from(this.pendingFlushArbUnsubs)
|
|
1657
|
-
});
|
|
1658
|
-
this.pendingFlushArbUnsubs.clear();
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1661
|
-
sendSubscribe(outcomeIds) {
|
|
1662
|
-
this.send({ action: "subscribe", channel: "orderbook", outcomeIds });
|
|
1663
|
-
}
|
|
1664
|
-
send(msg) {
|
|
1665
|
-
var _a;
|
|
1666
|
-
if (((_a = this.ws) == null ? void 0 : _a.readyState) === WebSocket.OPEN) {
|
|
1667
|
-
this.ws.send(JSON.stringify(msg));
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1670
|
-
activeOrderbookMarkets() {
|
|
1671
|
-
const markets = [];
|
|
1672
|
-
this.subs.forEach((sub, id) => {
|
|
1673
|
-
if (sub.refCount > 0) markets.push(id);
|
|
1674
|
-
});
|
|
1675
|
-
return markets;
|
|
1676
|
-
}
|
|
1677
|
-
activeTradeMarkets() {
|
|
1678
|
-
const markets = [];
|
|
1679
|
-
this.subs.forEach((sub, id) => {
|
|
1680
|
-
if (sub.tradeRefs > 0) markets.push(id);
|
|
1681
|
-
});
|
|
1682
|
-
return markets;
|
|
1683
|
-
}
|
|
1684
|
-
activeArbMarkets() {
|
|
1685
|
-
return Array.from(this.arbSubs.keys());
|
|
1686
|
-
}
|
|
1687
|
-
emitDiagnostic(event) {
|
|
1688
|
-
var _a, _b;
|
|
1689
|
-
(_b = (_a = this.callbacks).onDiagnostics) == null ? void 0 : _b.call(_a, event);
|
|
1690
|
-
}
|
|
1691
|
-
summarizeTopLevels(levels2) {
|
|
1692
|
-
return levels2.slice(0, ORDERBOOK_DEBUG_TOP_LEVELS).map((level) => ({ price: level.price, size: level.size }));
|
|
1693
|
-
}
|
|
1694
|
-
debugOrderbook(event, payload) {
|
|
1695
|
-
if (!this.isOrderbookDebugEnabled()) return;
|
|
1696
|
-
console.debug(`[AggWebSocket][orderbook] ${event}`, payload);
|
|
1697
|
-
}
|
|
1698
|
-
isOrderbookDebugEnabled() {
|
|
1699
|
-
return this.enableLogs;
|
|
1700
|
-
}
|
|
1701
|
-
};
|
|
1702
|
-
|
|
1703
|
-
// src/market-data/worker-adapter.ts
|
|
1704
|
-
var WorkerAggWebSocket = class extends AggWebSocket {
|
|
1705
|
-
constructor(config, factory) {
|
|
1706
|
-
var _a, _b;
|
|
1707
|
-
super(config);
|
|
1708
|
-
this.config = config;
|
|
1709
|
-
this.endpointListeners = /* @__PURE__ */ new Map();
|
|
1710
|
-
this.historyOperations = 0;
|
|
1711
|
-
this.currentBooks = /* @__PURE__ */ new Map();
|
|
1712
|
-
this.recovering = /* @__PURE__ */ new Set();
|
|
1713
|
-
this.diagnosticRevisions = /* @__PURE__ */ new Map();
|
|
1714
|
-
this.deliveredRevisions = /* @__PURE__ */ new Map();
|
|
1715
|
-
this.resolvedRevisions = /* @__PURE__ */ new Map();
|
|
1716
|
-
this.refs = /* @__PURE__ */ new Map();
|
|
1717
|
-
this.arbListeners = /* @__PURE__ */ new Map();
|
|
1718
|
-
this.feedListeners = /* @__PURE__ */ new Set();
|
|
1719
|
-
this.latest = /* @__PURE__ */ new Map();
|
|
1720
|
-
this.generation = 0;
|
|
1721
|
-
this.online = false;
|
|
1722
|
-
this.stopped = false;
|
|
1723
|
-
this.queued = false;
|
|
1724
|
-
this.historyFailures = /* @__PURE__ */ new Set();
|
|
1725
|
-
this.fallback = null;
|
|
1726
|
-
this.fallbackUnsubs = /* @__PURE__ */ new Map();
|
|
1727
|
-
this.historyGeneration = 0;
|
|
1728
|
-
this.visibility = () => {
|
|
1729
|
-
if (document.visibilityState === "visible")
|
|
1730
|
-
this.resnapshot(
|
|
1731
|
-
[...this.refs.values()].filter((entry) => entry.sub.channel === "orderbook").map((entry) => entry.sub.id)
|
|
1732
|
-
);
|
|
1733
|
-
};
|
|
1734
|
-
this.fail = () => {
|
|
1735
|
-
var _a, _b, _c;
|
|
1736
|
-
if (this.stopped || this.fallback) return;
|
|
1737
|
-
this.releaseWorker();
|
|
1738
|
-
this.currentBooks.clear();
|
|
1739
|
-
this.latest.clear();
|
|
1740
|
-
this.recovering.clear();
|
|
1741
|
-
this.diagnosticRevisions.clear();
|
|
1742
|
-
this.deliveredRevisions.clear();
|
|
1743
|
-
this.resolvedRevisions.clear();
|
|
1744
|
-
this.online = false;
|
|
1745
|
-
(_b = (_a = this.handlers).onConnectionStateChange) == null ? void 0 : _b.call(_a, false);
|
|
1746
|
-
this.fallback = new AggWebSocket(__spreadProps(__spreadValues({}, this.config), { callbacks: this.fallbackCallbacks() }));
|
|
1747
|
-
for (const reject of this.historyFailures) reject(new Error("Market-data worker failed"));
|
|
1748
|
-
this.historyFailures.clear();
|
|
1749
|
-
(_c = this.resolveFailure) == null ? void 0 : _c.call(this);
|
|
1750
|
-
this.syncFallback();
|
|
1751
|
-
};
|
|
1752
|
-
if (((_a = config.callbacks) == null ? void 0 : _a.onTrade) && !config.callbacks.onMarketView)
|
|
1753
|
-
throw new Error(
|
|
1754
|
-
"Raw trade callbacks require AggWebSocket; Worker views require onMarketView opt-in"
|
|
1755
|
-
);
|
|
1756
|
-
this.handlers = (_b = config.callbacks) != null ? _b : {};
|
|
1757
|
-
this.worker = factory();
|
|
1758
|
-
const worker = this.worker;
|
|
1759
|
-
const endpoint = {
|
|
1760
|
-
postMessage: worker.postMessage.bind(worker),
|
|
1761
|
-
addEventListener: (type, listener) => {
|
|
1762
|
-
this.endpointListeners.set(listener, type);
|
|
1763
|
-
worker.addEventListener(type, listener);
|
|
1764
|
-
},
|
|
1765
|
-
removeEventListener: (type, listener) => {
|
|
1766
|
-
this.endpointListeners.delete(listener);
|
|
1767
|
-
worker.removeEventListener(type, listener);
|
|
1768
|
-
}
|
|
1769
|
-
};
|
|
1770
|
-
this.remote = wrap(endpoint);
|
|
1771
|
-
this.worker.addEventListener("error", this.fail);
|
|
1772
|
-
this.worker.addEventListener("messageerror", this.fail);
|
|
1773
|
-
const _c = config, { callbacks: _callbacks } = _c, options = __objRest(_c, ["callbacks"]);
|
|
1774
|
-
const startup = this.remote.start(
|
|
1775
|
-
options,
|
|
1776
|
-
proxy((event) => {
|
|
1777
|
-
if (!this.fallback) this.event(event.name, event.args, event.revision);
|
|
1778
|
-
})
|
|
1779
|
-
).then(() => {
|
|
1780
|
-
if (this.stopped || this.fallback || !this.remote) return;
|
|
1781
|
-
return this.remote.observeViews(
|
|
1782
|
-
proxy((batch) => {
|
|
1783
|
-
var _a2, _b2, _c2, _d, _e, _f, _g, _h, _i, _j;
|
|
1784
|
-
if (batch.generation < this.generation || this.stopped || this.fallback) return;
|
|
1785
|
-
for (const view of batch.views) {
|
|
1786
|
-
if (!this.refs.has(`orderbook:${view.outcomeId}`) && !this.refs.has(`trades:${view.outcomeId}`))
|
|
1787
|
-
continue;
|
|
1788
|
-
if (((_a2 = this.resolvedRevisions.get(view.outcomeId)) != null ? _a2 : -1) >= view.revision) continue;
|
|
1789
|
-
const integrity = ((_b2 = this.diagnosticRevisions.get(view.outcomeId)) != null ? _b2 : -1) > view.revision ? "resyncing" : view.integrity;
|
|
1790
|
-
this.deliveredRevisions.set(view.outcomeId, view.revision);
|
|
1791
|
-
(_d = (_c2 = this.handlers).onMarketView) == null ? void 0 : _d.call(_c2, __spreadProps(__spreadValues({}, view), { integrity }));
|
|
1792
|
-
if (view.book) {
|
|
1793
|
-
this.currentBooks.set(view.outcomeId, view.book);
|
|
1794
|
-
if (integrity === "ok") {
|
|
1795
|
-
this.recovering.delete(view.outcomeId);
|
|
1796
|
-
this.diagnosticRevisions.delete(view.outcomeId);
|
|
1797
|
-
} else this.recovering.add(view.outcomeId);
|
|
1798
|
-
if (view.snapshot) (_f = (_e = this.handlers).onSnapshot) == null ? void 0 : _f.call(_e, view.outcomeId, view.book);
|
|
1799
|
-
else (_h = (_g = this.handlers).onDelta) == null ? void 0 : _h.call(_g, view.outcomeId, view.book);
|
|
1800
|
-
}
|
|
1801
|
-
for (const trade of [...view.trades].reverse()) (_j = (_i = this.handlers).onTrade) == null ? void 0 : _j.call(_i, trade);
|
|
1802
|
-
}
|
|
1803
|
-
})
|
|
1804
|
-
);
|
|
1805
|
-
}).catch(this.fail);
|
|
1806
|
-
const failed = new Promise((resolve) => {
|
|
1807
|
-
this.resolveFailure = resolve;
|
|
1808
|
-
});
|
|
1809
|
-
this.ready = Promise.race([startup, failed]);
|
|
1810
|
-
const startupTimeout = setTimeout(this.fail, 3e3);
|
|
1811
|
-
void this.ready.then(() => clearTimeout(startupTimeout));
|
|
1812
|
-
if (typeof document !== "undefined")
|
|
1813
|
-
document.addEventListener("visibilitychange", this.visibility);
|
|
1814
|
-
}
|
|
1815
|
-
get processesCandles() {
|
|
1816
|
-
return !this.fallback;
|
|
1817
|
-
}
|
|
1818
|
-
decodeHistory(payload) {
|
|
1819
|
-
return __async(this, null, function* () {
|
|
1820
|
-
this.historyOperations++;
|
|
1821
|
-
try {
|
|
1822
|
-
return yield this.decodeHistoryRequest(payload);
|
|
1823
|
-
} finally {
|
|
1824
|
-
this.historyOperations--;
|
|
1825
|
-
}
|
|
1826
|
-
});
|
|
1827
|
-
}
|
|
1828
|
-
decodeHistoryRequest(payload) {
|
|
1829
|
-
return __async(this, null, function* () {
|
|
1830
|
-
if (this.stopped) throw new Error("Market-data worker disposed");
|
|
1831
|
-
yield this.ready;
|
|
1832
|
-
if (this.stopped) throw new Error("Market-data worker disposed");
|
|
1833
|
-
if (this.fallback) return this.fallback.decodeHistory(payload);
|
|
1834
|
-
const remote = this.remote;
|
|
1835
|
-
if (!remote) throw new Error("Market-data worker unavailable");
|
|
1836
|
-
let rejectFailure;
|
|
1837
|
-
const failed = new Promise((_resolve, reject) => {
|
|
1838
|
-
rejectFailure = reject;
|
|
1839
|
-
this.historyFailures.add(reject);
|
|
1840
|
-
});
|
|
1841
|
-
try {
|
|
1842
|
-
return yield Promise.race([remote.decodeHistory(payload), failed]);
|
|
1843
|
-
} finally {
|
|
1844
|
-
this.historyFailures.delete(rejectFailure);
|
|
1845
|
-
}
|
|
1846
|
-
});
|
|
1847
|
-
}
|
|
1848
|
-
loadHistory(manifest, options) {
|
|
1849
|
-
return __async(this, null, function* () {
|
|
1850
|
-
this.historyOperations++;
|
|
1851
|
-
try {
|
|
1852
|
-
return yield this.loadHistoryRequest(manifest, options);
|
|
1853
|
-
} finally {
|
|
1854
|
-
this.historyOperations--;
|
|
1855
|
-
}
|
|
1856
|
-
});
|
|
1857
|
-
}
|
|
1858
|
-
loadHistoryRequest(manifest, options) {
|
|
1859
|
-
return __async(this, null, function* () {
|
|
1860
|
-
var _a, _b, _c, _d, _e;
|
|
1861
|
-
if (this.stopped) throw new Error("Market-data worker disposed");
|
|
1862
|
-
if (this.fallback) return this.fallback.loadHistory(manifest, options);
|
|
1863
|
-
const generation = ++this.historyGeneration;
|
|
1864
|
-
const key = `${manifest.venueMarketOutcomeId}:${manifest.resolution}:${manifest.from}:${manifest.to}`;
|
|
1865
|
-
(_a = options == null ? void 0 : options.signal) == null ? void 0 : _a.throwIfAborted();
|
|
1866
|
-
yield this.ready;
|
|
1867
|
-
if (this.stopped) throw new Error("Market-data worker disposed");
|
|
1868
|
-
(_b = options == null ? void 0 : options.signal) == null ? void 0 : _b.throwIfAborted();
|
|
1869
|
-
const fallbackAfterStartup = this.fallback;
|
|
1870
|
-
if (fallbackAfterStartup) return fallbackAfterStartup.loadHistory(manifest, options);
|
|
1871
|
-
const remote = this.remote;
|
|
1872
|
-
if (!remote) throw new Error("Market-data worker unavailable");
|
|
1873
|
-
let rejectFailure;
|
|
1874
|
-
const failed = new Promise((_resolve, reject) => {
|
|
1875
|
-
rejectFailure = reject;
|
|
1876
|
-
this.historyFailures.add(reject);
|
|
1877
|
-
});
|
|
1878
|
-
const abort = () => {
|
|
1879
|
-
var _a2;
|
|
1880
|
-
void ((_a2 = this.remote) == null ? void 0 : _a2.cancelHistoryRange(key, generation));
|
|
1881
|
-
};
|
|
1882
|
-
(_c = options == null ? void 0 : options.signal) == null ? void 0 : _c.addEventListener("abort", abort, { once: true });
|
|
1883
|
-
try {
|
|
1884
|
-
const result = yield Promise.race([
|
|
1885
|
-
remote.loadImmutableRange(key, generation, manifest),
|
|
1886
|
-
failed
|
|
1887
|
-
]);
|
|
1888
|
-
(_d = options == null ? void 0 : options.signal) == null ? void 0 : _d.throwIfAborted();
|
|
1889
|
-
return result;
|
|
1890
|
-
} finally {
|
|
1891
|
-
(_e = options == null ? void 0 : options.signal) == null ? void 0 : _e.removeEventListener("abort", abort);
|
|
1892
|
-
this.historyFailures.delete(rejectFailure);
|
|
1893
|
-
}
|
|
1894
|
-
});
|
|
1895
|
-
}
|
|
1896
|
-
setHostDiagnostics(provider) {
|
|
1897
|
-
this.hostProvider = provider;
|
|
1898
|
-
}
|
|
1899
|
-
getDiagnostics() {
|
|
1900
|
-
var _a, _b;
|
|
1901
|
-
const subscriptions = [...this.refs.values()].map((entry) => entry.sub);
|
|
1902
|
-
return this.fallback ? __spreadProps(__spreadValues({}, this.fallback.getDiagnostics()), {
|
|
1903
|
-
host: (_a = this.hostProvider) == null ? void 0 : _a.call(this),
|
|
1904
|
-
pendingHistoryRequests: this.historyOperations,
|
|
1905
|
-
workerAttached: false,
|
|
1906
|
-
bridgeListeners: this.endpointListeners.size
|
|
1907
|
-
}) : {
|
|
1908
|
-
connected: this.connected,
|
|
1909
|
-
host: (_b = this.hostProvider) == null ? void 0 : _b.call(this),
|
|
1910
|
-
transport: this.stopped ? "disposed" : "worker",
|
|
1911
|
-
orderbookOutcomeIds: subscriptions.filter((sub) => sub.channel === "orderbook").map((sub) => sub.id),
|
|
1912
|
-
tradeOutcomeIds: subscriptions.filter((sub) => sub.channel === "trades").map((sub) => sub.id),
|
|
1913
|
-
arbMarketIds: [...this.arbListeners.keys()],
|
|
1914
|
-
arbFeedSubscribers: this.feedListeners.size,
|
|
1915
|
-
cachedBooks: this.currentBooks.size,
|
|
1916
|
-
cachedArb: this.latest.size,
|
|
1917
|
-
resyncingBooks: this.recovering.size,
|
|
1918
|
-
pendingResnapshots: 0,
|
|
1919
|
-
pendingHistoryRequests: this.historyOperations,
|
|
1920
|
-
workerAttached: this.worker !== null,
|
|
1921
|
-
bridgeListeners: this.endpointListeners.size
|
|
1922
|
-
};
|
|
1923
|
-
}
|
|
1924
|
-
getWorkerDiagnostics() {
|
|
1925
|
-
return __async(this, null, function* () {
|
|
1926
|
-
yield this.ready;
|
|
1927
|
-
const remote = this.remote;
|
|
1928
|
-
if (this.stopped || !remote || this.fallback) return null;
|
|
1929
|
-
let rejectFailure;
|
|
1930
|
-
const failed = new Promise((_resolve, reject) => {
|
|
1931
|
-
rejectFailure = reject;
|
|
1932
|
-
this.historyFailures.add(reject);
|
|
1933
|
-
});
|
|
1934
|
-
try {
|
|
1935
|
-
return yield Promise.race([remote.getMeasurements(), failed]);
|
|
1936
|
-
} catch (e) {
|
|
1937
|
-
return null;
|
|
1938
|
-
} finally {
|
|
1939
|
-
this.historyFailures.delete(rejectFailure);
|
|
1940
|
-
}
|
|
1941
|
-
});
|
|
1942
|
-
}
|
|
1943
|
-
get connected() {
|
|
1944
|
-
var _a, _b;
|
|
1945
|
-
return !this.stopped && ((_b = (_a = this.fallback) == null ? void 0 : _a.connected) != null ? _b : this.online);
|
|
1946
|
-
}
|
|
1947
|
-
getBook(id) {
|
|
1948
|
-
var _a, _b, _c;
|
|
1949
|
-
return (_c = (_b = (_a = this.fallback) == null ? void 0 : _a.getBook(id)) != null ? _b : this.currentBooks.get(id)) != null ? _c : null;
|
|
1950
|
-
}
|
|
1951
|
-
isResyncing(id) {
|
|
1952
|
-
var _a, _b;
|
|
1953
|
-
return (_b = (_a = this.fallback) == null ? void 0 : _a.isResyncing(id)) != null ? _b : this.recovering.has(id);
|
|
1954
|
-
}
|
|
1955
|
-
getArb(id) {
|
|
1956
|
-
var _a, _b, _c;
|
|
1957
|
-
return (_c = (_b = (_a = this.fallback) == null ? void 0 : _a.getArb(id)) != null ? _b : this.latest.get(id)) != null ? _c : null;
|
|
1958
|
-
}
|
|
1959
|
-
subscribe(id, channel = "orderbook") {
|
|
1960
|
-
return this.ref({ id, channel });
|
|
1961
|
-
}
|
|
1962
|
-
subscribeTrades(id) {
|
|
1963
|
-
return this.subscribe(id, "trades");
|
|
1964
|
-
}
|
|
1965
|
-
subscribeArb(id, cb) {
|
|
1966
|
-
var _a;
|
|
1967
|
-
const listeners = (_a = this.arbListeners.get(id)) != null ? _a : /* @__PURE__ */ new Set();
|
|
1968
|
-
listeners.add(cb);
|
|
1969
|
-
this.arbListeners.set(id, listeners);
|
|
1970
|
-
const unsubscribe = this.ref({ id, channel: "arb" });
|
|
1971
|
-
return () => {
|
|
1972
|
-
unsubscribe();
|
|
1973
|
-
listeners.delete(cb);
|
|
1974
|
-
if (!listeners.size) this.arbListeners.delete(id);
|
|
1975
|
-
};
|
|
1976
|
-
}
|
|
1977
|
-
subscribeArbFeed(cb) {
|
|
1978
|
-
this.feedListeners.add(cb);
|
|
1979
|
-
const unsubscribe = this.ref({ id: "*", channel: "arb-feed" });
|
|
1980
|
-
return () => {
|
|
1981
|
-
unsubscribe();
|
|
1982
|
-
this.feedListeners.delete(cb);
|
|
1983
|
-
};
|
|
1984
|
-
}
|
|
1985
|
-
setCallbacks(callbacks) {
|
|
1986
|
-
var _a;
|
|
1987
|
-
this.handlers = callbacks;
|
|
1988
|
-
if (callbacks.onTrade && !callbacks.onMarketView && !this.fallback) this.fail();
|
|
1989
|
-
(_a = this.fallback) == null ? void 0 : _a.setCallbacks(this.fallbackCallbacks());
|
|
1990
|
-
}
|
|
1991
|
-
authenticate(token) {
|
|
1992
|
-
this.config.initialToken = token;
|
|
1993
|
-
this.run((engine) => engine.authenticate(token));
|
|
1994
|
-
}
|
|
1995
|
-
connect() {
|
|
1996
|
-
this.run((engine) => engine.connect());
|
|
1997
|
-
}
|
|
1998
|
-
disconnect() {
|
|
1999
|
-
this.run((engine) => engine.disconnect());
|
|
2000
|
-
}
|
|
2001
|
-
resnapshot(id) {
|
|
2002
|
-
const ids = Array.isArray(id) ? id : [id];
|
|
2003
|
-
this.run((engine) => engine.resnapshot(ids));
|
|
2004
|
-
}
|
|
2005
|
-
destroy() {
|
|
2006
|
-
var _a, _b;
|
|
2007
|
-
if (this.stopped) return;
|
|
2008
|
-
this.stopped = true;
|
|
2009
|
-
this.online = false;
|
|
2010
|
-
(_a = this.resolveFailure) == null ? void 0 : _a.call(this);
|
|
2011
|
-
for (const reject of this.historyFailures) reject(new Error("Market-data worker disposed"));
|
|
2012
|
-
this.historyFailures.clear();
|
|
2013
|
-
this.refs.clear();
|
|
2014
|
-
this.currentBooks.clear();
|
|
2015
|
-
this.latest.clear();
|
|
2016
|
-
this.arbListeners.clear();
|
|
2017
|
-
this.feedListeners.clear();
|
|
2018
|
-
this.recovering.clear();
|
|
2019
|
-
this.diagnosticRevisions.clear();
|
|
2020
|
-
this.deliveredRevisions.clear();
|
|
2021
|
-
this.resolvedRevisions.clear();
|
|
2022
|
-
(_b = this.fallback) == null ? void 0 : _b.destroy();
|
|
2023
|
-
this.fallbackUnsubs.clear();
|
|
2024
|
-
this.hostProvider = void 0;
|
|
2025
|
-
this.handlers = {};
|
|
2026
|
-
if (typeof document !== "undefined")
|
|
2027
|
-
document.removeEventListener("visibilitychange", this.visibility);
|
|
2028
|
-
this.releaseWorker();
|
|
2029
|
-
}
|
|
2030
|
-
releaseWorker() {
|
|
2031
|
-
const worker = this.worker;
|
|
2032
|
-
const remote = this.remote;
|
|
2033
|
-
this.remote = null;
|
|
2034
|
-
this.worker = null;
|
|
2035
|
-
if (remote) remote[releaseProxy]();
|
|
2036
|
-
if (!worker) return;
|
|
2037
|
-
for (const [listener, type] of this.endpointListeners)
|
|
2038
|
-
worker.removeEventListener(type, listener);
|
|
2039
|
-
this.endpointListeners.clear();
|
|
2040
|
-
worker.removeEventListener("error", this.fail);
|
|
2041
|
-
worker.removeEventListener("messageerror", this.fail);
|
|
2042
|
-
worker.terminate();
|
|
2043
|
-
}
|
|
2044
|
-
event(name, args, revision = 0) {
|
|
2045
|
-
var _a, _b, _c, _d;
|
|
2046
|
-
if (this.stopped) return;
|
|
2047
|
-
if (name === "onConnectionStateChange") this.online = args[0];
|
|
2048
|
-
if (name === "onDiagnostics") {
|
|
2049
|
-
const diagnostic = args[0];
|
|
2050
|
-
if (diagnostic.outcomeId && revision < ((_a = this.deliveredRevisions.get(diagnostic.outcomeId)) != null ? _a : -1))
|
|
2051
|
-
return;
|
|
2052
|
-
if (diagnostic.outcomeId && (this.refs.has(`orderbook:${diagnostic.outcomeId}`) || this.refs.has(`trades:${diagnostic.outcomeId}`)) && ["seq_gap", "checksum_mismatch"].includes(diagnostic.type)) {
|
|
2053
|
-
this.recovering.add(diagnostic.outcomeId);
|
|
2054
|
-
this.diagnosticRevisions.set(diagnostic.outcomeId, revision);
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
|
-
if (name === "onMarketResolved") {
|
|
2058
|
-
const id = args[0].outcomeId;
|
|
2059
|
-
if (this.refs.has(`orderbook:${id}`) || this.refs.has(`trades:${id}`))
|
|
2060
|
-
this.resolvedRevisions.set(id, revision);
|
|
2061
|
-
this.currentBooks.delete(id);
|
|
2062
|
-
}
|
|
2063
|
-
if (name === "onArbMarket") {
|
|
2064
|
-
const msg = args[0];
|
|
2065
|
-
this.latest.set(msg.marketId, msg);
|
|
2066
|
-
for (const cb of (_b = this.arbListeners.get(msg.marketId)) != null ? _b : []) cb(msg);
|
|
2067
|
-
}
|
|
2068
|
-
if (name === "onArbFeed") for (const cb of this.feedListeners) cb(args[0]);
|
|
2069
|
-
(_d = (_c = this.handlers)[name]) == null ? void 0 : _d.call(_c, ...args);
|
|
2070
|
-
}
|
|
2071
|
-
ref(sub) {
|
|
2072
|
-
var _a;
|
|
2073
|
-
const key = `${sub.channel}:${sub.id}`;
|
|
2074
|
-
const entry = (_a = this.refs.get(key)) != null ? _a : { sub, count: 0 };
|
|
2075
|
-
entry.count++;
|
|
2076
|
-
this.refs.set(key, entry);
|
|
2077
|
-
this.sync();
|
|
2078
|
-
let released = false;
|
|
2079
|
-
return () => {
|
|
2080
|
-
if (released) return;
|
|
2081
|
-
released = true;
|
|
2082
|
-
if (--entry.count === 0) {
|
|
2083
|
-
this.refs.delete(key);
|
|
2084
|
-
if (sub.channel === "orderbook") this.recovering.delete(sub.id);
|
|
2085
|
-
if (!this.refs.has(`orderbook:${sub.id}`) && !this.refs.has(`trades:${sub.id}`)) {
|
|
2086
|
-
this.currentBooks.delete(sub.id);
|
|
2087
|
-
this.recovering.delete(sub.id);
|
|
2088
|
-
this.diagnosticRevisions.delete(sub.id);
|
|
2089
|
-
this.deliveredRevisions.delete(sub.id);
|
|
2090
|
-
this.resolvedRevisions.delete(sub.id);
|
|
2091
|
-
}
|
|
2092
|
-
}
|
|
2093
|
-
this.sync();
|
|
2094
|
-
};
|
|
2095
|
-
}
|
|
2096
|
-
sync() {
|
|
2097
|
-
if (this.queued || this.stopped) return;
|
|
2098
|
-
this.queued = true;
|
|
2099
|
-
queueMicrotask(() => {
|
|
2100
|
-
this.queued = false;
|
|
2101
|
-
if (this.stopped) return;
|
|
2102
|
-
if (this.fallback) {
|
|
2103
|
-
this.syncFallback();
|
|
2104
|
-
return;
|
|
2105
|
-
}
|
|
2106
|
-
const generation = ++this.generation;
|
|
2107
|
-
const subscriptions = [...this.refs.values()].map((entry) => entry.sub);
|
|
2108
|
-
void this.ready.then(() => {
|
|
2109
|
-
var _a;
|
|
2110
|
-
if (!this.stopped && !this.fallback)
|
|
2111
|
-
return (_a = this.remote) == null ? void 0 : _a.setSubscriptions(subscriptions, generation);
|
|
2112
|
-
}).catch(this.fail);
|
|
2113
|
-
});
|
|
2114
|
-
}
|
|
2115
|
-
run(action) {
|
|
2116
|
-
if (this.stopped) return;
|
|
2117
|
-
if (this.fallback) {
|
|
2118
|
-
action(this.fallback);
|
|
2119
|
-
return;
|
|
2120
|
-
}
|
|
2121
|
-
void this.ready.then(() => {
|
|
2122
|
-
var _a;
|
|
2123
|
-
if (this.stopped) return;
|
|
2124
|
-
const engine = (_a = this.fallback) != null ? _a : this.remote;
|
|
2125
|
-
if (engine) return action(engine);
|
|
2126
|
-
}).catch(this.fail);
|
|
2127
|
-
}
|
|
2128
|
-
fallbackCallbacks() {
|
|
2129
|
-
return __spreadProps(__spreadValues({}, this.handlers), {
|
|
2130
|
-
onArbMarket: (msg) => this.event("onArbMarket", [msg]),
|
|
2131
|
-
onArbFeed: (msg) => this.event("onArbFeed", [msg])
|
|
2132
|
-
});
|
|
2133
|
-
}
|
|
2134
|
-
syncFallback() {
|
|
2135
|
-
for (const [key, unsubscribe] of this.fallbackUnsubs) {
|
|
2136
|
-
if (!this.refs.has(key)) {
|
|
2137
|
-
unsubscribe();
|
|
2138
|
-
this.fallbackUnsubs.delete(key);
|
|
2139
|
-
}
|
|
2140
|
-
}
|
|
2141
|
-
for (const [key, { sub }] of this.refs) {
|
|
2142
|
-
if (this.fallbackUnsubs.has(key)) continue;
|
|
2143
|
-
this.fallbackUnsubs.set(
|
|
2144
|
-
key,
|
|
2145
|
-
sub.channel === "arb" ? this.fallback.subscribeArb(sub.id, () => {
|
|
2146
|
-
}) : sub.channel === "arb-feed" ? this.fallback.subscribeArbFeed(() => {
|
|
2147
|
-
}) : this.fallback.subscribe(sub.id, sub.channel)
|
|
2148
|
-
);
|
|
2149
|
-
}
|
|
2150
|
-
}
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
4
|
+
//#endregion
|
|
5
|
+
const require_agg_websocket = require("./agg-websocket-DJbIfxKb.js");
|
|
6
|
+
/**
|
|
7
|
+
* @license
|
|
8
|
+
* Copyright 2019 Google LLC
|
|
9
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
10
|
+
*/
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/market-data/worker-adapter.ts
|
|
13
|
+
var import_comlink = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
14
|
+
(function(global, factory) {
|
|
15
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.Comlink = {}));
|
|
16
|
+
})(exports, (function(exports$1) {
|
|
17
|
+
"use strict";
|
|
18
|
+
const proxyMarker = Symbol("Comlink.proxy");
|
|
19
|
+
const createEndpoint = Symbol("Comlink.endpoint");
|
|
20
|
+
const releaseProxy = Symbol("Comlink.releaseProxy");
|
|
21
|
+
const finalizer = Symbol("Comlink.finalizer");
|
|
22
|
+
const throwMarker = Symbol("Comlink.thrown");
|
|
23
|
+
const isObject = (val) => typeof val === "object" && val !== null || typeof val === "function";
|
|
24
|
+
/**
|
|
25
|
+
* Allows customizing the serialization of certain values.
|
|
26
|
+
*/
|
|
27
|
+
const transferHandlers = /* @__PURE__ */ new Map([["proxy", {
|
|
28
|
+
canHandle: (val) => isObject(val) && val[proxyMarker],
|
|
29
|
+
serialize(obj) {
|
|
30
|
+
const { port1, port2 } = new MessageChannel();
|
|
31
|
+
expose(obj, port1);
|
|
32
|
+
return [port2, [port2]];
|
|
33
|
+
},
|
|
34
|
+
deserialize(port) {
|
|
35
|
+
port.start();
|
|
36
|
+
return wrap(port);
|
|
37
|
+
}
|
|
38
|
+
}], ["throw", {
|
|
39
|
+
canHandle: (value) => isObject(value) && throwMarker in value,
|
|
40
|
+
serialize({ value }) {
|
|
41
|
+
let serialized;
|
|
42
|
+
if (value instanceof Error) serialized = {
|
|
43
|
+
isError: true,
|
|
44
|
+
value: {
|
|
45
|
+
message: value.message,
|
|
46
|
+
name: value.name,
|
|
47
|
+
stack: value.stack
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
else serialized = {
|
|
51
|
+
isError: false,
|
|
52
|
+
value
|
|
53
|
+
};
|
|
54
|
+
return [serialized, []];
|
|
55
|
+
},
|
|
56
|
+
deserialize(serialized) {
|
|
57
|
+
if (serialized.isError) throw Object.assign(new Error(serialized.value.message), serialized.value);
|
|
58
|
+
throw serialized.value;
|
|
59
|
+
}
|
|
60
|
+
}]]);
|
|
61
|
+
function isAllowedOrigin(allowedOrigins, origin) {
|
|
62
|
+
for (const allowedOrigin of allowedOrigins) {
|
|
63
|
+
if (origin === allowedOrigin || allowedOrigin === "*") return true;
|
|
64
|
+
if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
function expose(obj, ep = globalThis, allowedOrigins = ["*"]) {
|
|
69
|
+
ep.addEventListener("message", function callback(ev) {
|
|
70
|
+
if (!ev || !ev.data) return;
|
|
71
|
+
if (!isAllowedOrigin(allowedOrigins, ev.origin)) {
|
|
72
|
+
console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const { id, type, path } = Object.assign({ path: [] }, ev.data);
|
|
76
|
+
const argumentList = (ev.data.argumentList || []).map(fromWireValue);
|
|
77
|
+
let returnValue;
|
|
78
|
+
try {
|
|
79
|
+
const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);
|
|
80
|
+
const rawValue = path.reduce((obj, prop) => obj[prop], obj);
|
|
81
|
+
switch (type) {
|
|
82
|
+
case "GET":
|
|
83
|
+
returnValue = rawValue;
|
|
84
|
+
break;
|
|
85
|
+
case "SET":
|
|
86
|
+
parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);
|
|
87
|
+
returnValue = true;
|
|
88
|
+
break;
|
|
89
|
+
case "APPLY":
|
|
90
|
+
returnValue = rawValue.apply(parent, argumentList);
|
|
91
|
+
break;
|
|
92
|
+
case "CONSTRUCT":
|
|
93
|
+
returnValue = proxy(new rawValue(...argumentList));
|
|
94
|
+
break;
|
|
95
|
+
case "ENDPOINT":
|
|
96
|
+
{
|
|
97
|
+
const { port1, port2 } = new MessageChannel();
|
|
98
|
+
expose(obj, port2);
|
|
99
|
+
returnValue = transfer(port1, [port1]);
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
case "RELEASE":
|
|
103
|
+
returnValue = void 0;
|
|
104
|
+
break;
|
|
105
|
+
default: return;
|
|
106
|
+
}
|
|
107
|
+
} catch (value) {
|
|
108
|
+
returnValue = {
|
|
109
|
+
value,
|
|
110
|
+
[throwMarker]: 0
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
Promise.resolve(returnValue).catch((value) => {
|
|
114
|
+
return {
|
|
115
|
+
value,
|
|
116
|
+
[throwMarker]: 0
|
|
117
|
+
};
|
|
118
|
+
}).then((returnValue) => {
|
|
119
|
+
const [wireValue, transferables] = toWireValue(returnValue);
|
|
120
|
+
ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);
|
|
121
|
+
if (type === "RELEASE") {
|
|
122
|
+
ep.removeEventListener("message", callback);
|
|
123
|
+
closeEndPoint(ep);
|
|
124
|
+
if (finalizer in obj && typeof obj[finalizer] === "function") obj[finalizer]();
|
|
125
|
+
}
|
|
126
|
+
}).catch((error) => {
|
|
127
|
+
const [wireValue, transferables] = toWireValue({
|
|
128
|
+
value: /* @__PURE__ */ new TypeError("Unserializable return value"),
|
|
129
|
+
[throwMarker]: 0
|
|
130
|
+
});
|
|
131
|
+
ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
if (ep.start) ep.start();
|
|
135
|
+
}
|
|
136
|
+
function isMessagePort(endpoint) {
|
|
137
|
+
return endpoint.constructor.name === "MessagePort";
|
|
138
|
+
}
|
|
139
|
+
function closeEndPoint(endpoint) {
|
|
140
|
+
if (isMessagePort(endpoint)) endpoint.close();
|
|
141
|
+
}
|
|
142
|
+
function wrap(ep, target) {
|
|
143
|
+
const pendingListeners = /* @__PURE__ */ new Map();
|
|
144
|
+
ep.addEventListener("message", function handleMessage(ev) {
|
|
145
|
+
const { data } = ev;
|
|
146
|
+
if (!data || !data.id) return;
|
|
147
|
+
const resolver = pendingListeners.get(data.id);
|
|
148
|
+
if (!resolver) return;
|
|
149
|
+
try {
|
|
150
|
+
resolver(data);
|
|
151
|
+
} finally {
|
|
152
|
+
pendingListeners.delete(data.id);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
return createProxy(ep, pendingListeners, [], target);
|
|
156
|
+
}
|
|
157
|
+
function throwIfProxyReleased(isReleased) {
|
|
158
|
+
if (isReleased) throw new Error("Proxy has been released and is not useable");
|
|
159
|
+
}
|
|
160
|
+
function releaseEndpoint(ep) {
|
|
161
|
+
return requestResponseMessage(ep, /* @__PURE__ */ new Map(), { type: "RELEASE" }).then(() => {
|
|
162
|
+
closeEndPoint(ep);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
const proxyCounter = /* @__PURE__ */ new WeakMap();
|
|
166
|
+
const proxyFinalizers = "FinalizationRegistry" in globalThis && new FinalizationRegistry((ep) => {
|
|
167
|
+
const newCount = (proxyCounter.get(ep) || 0) - 1;
|
|
168
|
+
proxyCounter.set(ep, newCount);
|
|
169
|
+
if (newCount === 0) releaseEndpoint(ep);
|
|
170
|
+
});
|
|
171
|
+
function registerProxy(proxy, ep) {
|
|
172
|
+
const newCount = (proxyCounter.get(ep) || 0) + 1;
|
|
173
|
+
proxyCounter.set(ep, newCount);
|
|
174
|
+
if (proxyFinalizers) proxyFinalizers.register(proxy, ep, proxy);
|
|
175
|
+
}
|
|
176
|
+
function unregisterProxy(proxy) {
|
|
177
|
+
if (proxyFinalizers) proxyFinalizers.unregister(proxy);
|
|
178
|
+
}
|
|
179
|
+
function createProxy(ep, pendingListeners, path = [], target = function() {}) {
|
|
180
|
+
let isProxyReleased = false;
|
|
181
|
+
const proxy = new Proxy(target, {
|
|
182
|
+
get(_target, prop) {
|
|
183
|
+
throwIfProxyReleased(isProxyReleased);
|
|
184
|
+
if (prop === releaseProxy) return () => {
|
|
185
|
+
unregisterProxy(proxy);
|
|
186
|
+
releaseEndpoint(ep);
|
|
187
|
+
pendingListeners.clear();
|
|
188
|
+
isProxyReleased = true;
|
|
189
|
+
};
|
|
190
|
+
if (prop === "then") {
|
|
191
|
+
if (path.length === 0) return { then: () => proxy };
|
|
192
|
+
const r = requestResponseMessage(ep, pendingListeners, {
|
|
193
|
+
type: "GET",
|
|
194
|
+
path: path.map((p) => p.toString())
|
|
195
|
+
}).then(fromWireValue);
|
|
196
|
+
return r.then.bind(r);
|
|
197
|
+
}
|
|
198
|
+
return createProxy(ep, pendingListeners, [...path, prop]);
|
|
199
|
+
},
|
|
200
|
+
set(_target, prop, rawValue) {
|
|
201
|
+
throwIfProxyReleased(isProxyReleased);
|
|
202
|
+
const [value, transferables] = toWireValue(rawValue);
|
|
203
|
+
return requestResponseMessage(ep, pendingListeners, {
|
|
204
|
+
type: "SET",
|
|
205
|
+
path: [...path, prop].map((p) => p.toString()),
|
|
206
|
+
value
|
|
207
|
+
}, transferables).then(fromWireValue);
|
|
208
|
+
},
|
|
209
|
+
apply(_target, _thisArg, rawArgumentList) {
|
|
210
|
+
throwIfProxyReleased(isProxyReleased);
|
|
211
|
+
const last = path[path.length - 1];
|
|
212
|
+
if (last === createEndpoint) return requestResponseMessage(ep, pendingListeners, { type: "ENDPOINT" }).then(fromWireValue);
|
|
213
|
+
if (last === "bind") return createProxy(ep, pendingListeners, path.slice(0, -1));
|
|
214
|
+
const [argumentList, transferables] = processArguments(rawArgumentList);
|
|
215
|
+
return requestResponseMessage(ep, pendingListeners, {
|
|
216
|
+
type: "APPLY",
|
|
217
|
+
path: path.map((p) => p.toString()),
|
|
218
|
+
argumentList
|
|
219
|
+
}, transferables).then(fromWireValue);
|
|
220
|
+
},
|
|
221
|
+
construct(_target, rawArgumentList) {
|
|
222
|
+
throwIfProxyReleased(isProxyReleased);
|
|
223
|
+
const [argumentList, transferables] = processArguments(rawArgumentList);
|
|
224
|
+
return requestResponseMessage(ep, pendingListeners, {
|
|
225
|
+
type: "CONSTRUCT",
|
|
226
|
+
path: path.map((p) => p.toString()),
|
|
227
|
+
argumentList
|
|
228
|
+
}, transferables).then(fromWireValue);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
registerProxy(proxy, ep);
|
|
232
|
+
return proxy;
|
|
233
|
+
}
|
|
234
|
+
function myFlat(arr) {
|
|
235
|
+
return Array.prototype.concat.apply([], arr);
|
|
236
|
+
}
|
|
237
|
+
function processArguments(argumentList) {
|
|
238
|
+
const processed = argumentList.map(toWireValue);
|
|
239
|
+
return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];
|
|
240
|
+
}
|
|
241
|
+
const transferCache = /* @__PURE__ */ new WeakMap();
|
|
242
|
+
function transfer(obj, transfers) {
|
|
243
|
+
transferCache.set(obj, transfers);
|
|
244
|
+
return obj;
|
|
245
|
+
}
|
|
246
|
+
function proxy(obj) {
|
|
247
|
+
return Object.assign(obj, { [proxyMarker]: true });
|
|
248
|
+
}
|
|
249
|
+
function windowEndpoint(w, context = globalThis, targetOrigin = "*") {
|
|
250
|
+
return {
|
|
251
|
+
postMessage: (msg, transferables) => w.postMessage(msg, targetOrigin, transferables),
|
|
252
|
+
addEventListener: context.addEventListener.bind(context),
|
|
253
|
+
removeEventListener: context.removeEventListener.bind(context)
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function toWireValue(value) {
|
|
257
|
+
for (const [name, handler] of transferHandlers) if (handler.canHandle(value)) {
|
|
258
|
+
const [serializedValue, transferables] = handler.serialize(value);
|
|
259
|
+
return [{
|
|
260
|
+
type: "HANDLER",
|
|
261
|
+
name,
|
|
262
|
+
value: serializedValue
|
|
263
|
+
}, transferables];
|
|
264
|
+
}
|
|
265
|
+
return [{
|
|
266
|
+
type: "RAW",
|
|
267
|
+
value
|
|
268
|
+
}, transferCache.get(value) || []];
|
|
269
|
+
}
|
|
270
|
+
function fromWireValue(value) {
|
|
271
|
+
switch (value.type) {
|
|
272
|
+
case "HANDLER": return transferHandlers.get(value.name).deserialize(value.value);
|
|
273
|
+
case "RAW": return value.value;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function requestResponseMessage(ep, pendingListeners, msg, transfers) {
|
|
277
|
+
return new Promise((resolve) => {
|
|
278
|
+
const id = generateUUID();
|
|
279
|
+
pendingListeners.set(id, resolve);
|
|
280
|
+
if (ep.start) ep.start();
|
|
281
|
+
ep.postMessage(Object.assign({ id }, msg), transfers);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
function generateUUID() {
|
|
285
|
+
return new Array(4).fill(0).map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16)).join("-");
|
|
286
|
+
}
|
|
287
|
+
exports$1.createEndpoint = createEndpoint;
|
|
288
|
+
exports$1.expose = expose;
|
|
289
|
+
exports$1.finalizer = finalizer;
|
|
290
|
+
exports$1.proxy = proxy;
|
|
291
|
+
exports$1.proxyMarker = proxyMarker;
|
|
292
|
+
exports$1.releaseProxy = releaseProxy;
|
|
293
|
+
exports$1.transfer = transfer;
|
|
294
|
+
exports$1.transferHandlers = transferHandlers;
|
|
295
|
+
exports$1.windowEndpoint = windowEndpoint;
|
|
296
|
+
exports$1.wrap = wrap;
|
|
297
|
+
}));
|
|
298
|
+
})))();
|
|
299
|
+
var WorkerAggWebSocket = class extends require_agg_websocket.AggWebSocket {
|
|
300
|
+
get processesCandles() {
|
|
301
|
+
return !this.fallback;
|
|
302
|
+
}
|
|
303
|
+
constructor(config, factory) {
|
|
304
|
+
super(config);
|
|
305
|
+
this.config = config;
|
|
306
|
+
this.endpointListeners = /* @__PURE__ */ new Map();
|
|
307
|
+
this.historyOperations = 0;
|
|
308
|
+
this.currentBooks = /* @__PURE__ */ new Map();
|
|
309
|
+
this.recovering = /* @__PURE__ */ new Set();
|
|
310
|
+
this.diagnosticRevisions = /* @__PURE__ */ new Map();
|
|
311
|
+
this.deliveredRevisions = /* @__PURE__ */ new Map();
|
|
312
|
+
this.resolvedRevisions = /* @__PURE__ */ new Map();
|
|
313
|
+
this.refs = /* @__PURE__ */ new Map();
|
|
314
|
+
this.arbListeners = /* @__PURE__ */ new Map();
|
|
315
|
+
this.feedListeners = /* @__PURE__ */ new Set();
|
|
316
|
+
this.latest = /* @__PURE__ */ new Map();
|
|
317
|
+
this.generation = 0;
|
|
318
|
+
this.online = false;
|
|
319
|
+
this.stopped = false;
|
|
320
|
+
this.queued = false;
|
|
321
|
+
this.historyFailures = /* @__PURE__ */ new Set();
|
|
322
|
+
this.fallback = null;
|
|
323
|
+
this.fallbackUnsubs = /* @__PURE__ */ new Map();
|
|
324
|
+
this.historyGeneration = 0;
|
|
325
|
+
this.visibility = () => {
|
|
326
|
+
if (document.visibilityState === "visible") this.resnapshot([...this.refs.values()].filter((entry) => entry.sub.channel === "orderbook").map((entry) => entry.sub.id));
|
|
327
|
+
};
|
|
328
|
+
this.fail = () => {
|
|
329
|
+
if (this.stopped || this.fallback) return;
|
|
330
|
+
this.releaseWorker();
|
|
331
|
+
this.currentBooks.clear();
|
|
332
|
+
this.latest.clear();
|
|
333
|
+
this.recovering.clear();
|
|
334
|
+
this.diagnosticRevisions.clear();
|
|
335
|
+
this.deliveredRevisions.clear();
|
|
336
|
+
this.resolvedRevisions.clear();
|
|
337
|
+
this.online = false;
|
|
338
|
+
this.handlers.onConnectionStateChange?.(false);
|
|
339
|
+
this.fallback = new require_agg_websocket.AggWebSocket({
|
|
340
|
+
...this.config,
|
|
341
|
+
callbacks: this.fallbackCallbacks()
|
|
342
|
+
});
|
|
343
|
+
for (const reject of this.historyFailures) reject(/* @__PURE__ */ new Error("Market-data worker failed"));
|
|
344
|
+
this.historyFailures.clear();
|
|
345
|
+
this.resolveFailure?.();
|
|
346
|
+
this.syncFallback();
|
|
347
|
+
};
|
|
348
|
+
if (config.callbacks?.onTrade && !config.callbacks.onMarketView) throw new Error("Raw trade callbacks require AggWebSocket; Worker views require onMarketView opt-in");
|
|
349
|
+
this.handlers = config.callbacks ?? {};
|
|
350
|
+
this.worker = factory();
|
|
351
|
+
const worker = this.worker;
|
|
352
|
+
const endpoint = {
|
|
353
|
+
postMessage: worker.postMessage.bind(worker),
|
|
354
|
+
addEventListener: (type, listener) => {
|
|
355
|
+
this.endpointListeners.set(listener, type);
|
|
356
|
+
worker.addEventListener(type, listener);
|
|
357
|
+
},
|
|
358
|
+
removeEventListener: (type, listener) => {
|
|
359
|
+
this.endpointListeners.delete(listener);
|
|
360
|
+
worker.removeEventListener(type, listener);
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
this.remote = (0, import_comlink.wrap)(endpoint);
|
|
364
|
+
this.worker.addEventListener("error", this.fail);
|
|
365
|
+
this.worker.addEventListener("messageerror", this.fail);
|
|
366
|
+
const { callbacks: _callbacks, ...options } = config;
|
|
367
|
+
const startup = this.remote.start(options, (0, import_comlink.proxy)((event) => {
|
|
368
|
+
if (!this.fallback) this.event(event.name, event.args, event.revision);
|
|
369
|
+
})).then(() => {
|
|
370
|
+
if (this.stopped || this.fallback || !this.remote) return;
|
|
371
|
+
return this.remote.observeViews((0, import_comlink.proxy)((batch) => {
|
|
372
|
+
if (batch.generation < this.generation || this.stopped || this.fallback) return;
|
|
373
|
+
for (const view of batch.views) {
|
|
374
|
+
if (!this.refs.has(`orderbook:${view.outcomeId}`) && !this.refs.has(`trades:${view.outcomeId}`)) continue;
|
|
375
|
+
if ((this.resolvedRevisions.get(view.outcomeId) ?? -1) >= view.revision) continue;
|
|
376
|
+
const integrity = (this.diagnosticRevisions.get(view.outcomeId) ?? -1) > view.revision ? "resyncing" : view.integrity;
|
|
377
|
+
this.deliveredRevisions.set(view.outcomeId, view.revision);
|
|
378
|
+
this.handlers.onMarketView?.({
|
|
379
|
+
...view,
|
|
380
|
+
integrity
|
|
381
|
+
});
|
|
382
|
+
if (view.book) {
|
|
383
|
+
this.currentBooks.set(view.outcomeId, view.book);
|
|
384
|
+
if (integrity === "ok") {
|
|
385
|
+
this.recovering.delete(view.outcomeId);
|
|
386
|
+
this.diagnosticRevisions.delete(view.outcomeId);
|
|
387
|
+
} else this.recovering.add(view.outcomeId);
|
|
388
|
+
if (view.snapshot) this.handlers.onSnapshot?.(view.outcomeId, view.book);
|
|
389
|
+
else this.handlers.onDelta?.(view.outcomeId, view.book);
|
|
390
|
+
}
|
|
391
|
+
for (const trade of [...view.trades].reverse()) this.handlers.onTrade?.(trade);
|
|
392
|
+
}
|
|
393
|
+
}));
|
|
394
|
+
}).catch(this.fail);
|
|
395
|
+
const failed = new Promise((resolve) => {
|
|
396
|
+
this.resolveFailure = resolve;
|
|
397
|
+
});
|
|
398
|
+
this.ready = Promise.race([startup, failed]);
|
|
399
|
+
const startupTimeout = setTimeout(this.fail, 3e3);
|
|
400
|
+
this.ready.then(() => clearTimeout(startupTimeout));
|
|
401
|
+
if (typeof document !== "undefined") document.addEventListener("visibilitychange", this.visibility);
|
|
402
|
+
}
|
|
403
|
+
async decodeHistory(payload) {
|
|
404
|
+
this.historyOperations++;
|
|
405
|
+
try {
|
|
406
|
+
return await this.decodeHistoryRequest(payload);
|
|
407
|
+
} finally {
|
|
408
|
+
this.historyOperations--;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
async decodeHistoryRequest(payload) {
|
|
412
|
+
if (this.stopped) throw new Error("Market-data worker disposed");
|
|
413
|
+
await this.ready;
|
|
414
|
+
if (this.stopped) throw new Error("Market-data worker disposed");
|
|
415
|
+
if (this.fallback) return this.fallback.decodeHistory(payload);
|
|
416
|
+
const remote = this.remote;
|
|
417
|
+
if (!remote) throw new Error("Market-data worker unavailable");
|
|
418
|
+
let rejectFailure;
|
|
419
|
+
const failed = new Promise((_resolve, reject) => {
|
|
420
|
+
rejectFailure = reject;
|
|
421
|
+
this.historyFailures.add(reject);
|
|
422
|
+
});
|
|
423
|
+
try {
|
|
424
|
+
return await Promise.race([remote.decodeHistory(payload), failed]);
|
|
425
|
+
} finally {
|
|
426
|
+
this.historyFailures.delete(rejectFailure);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
async loadHistory(manifest, options) {
|
|
430
|
+
this.historyOperations++;
|
|
431
|
+
try {
|
|
432
|
+
return await this.loadHistoryRequest(manifest, options);
|
|
433
|
+
} finally {
|
|
434
|
+
this.historyOperations--;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
async loadHistoryRequest(manifest, options) {
|
|
438
|
+
if (this.stopped) throw new Error("Market-data worker disposed");
|
|
439
|
+
if (this.fallback) return this.fallback.loadHistory(manifest, options);
|
|
440
|
+
const generation = ++this.historyGeneration;
|
|
441
|
+
const key = `${manifest.venueMarketOutcomeId}:${manifest.resolution}:${manifest.from}:${manifest.to}`;
|
|
442
|
+
options?.signal?.throwIfAborted();
|
|
443
|
+
await this.ready;
|
|
444
|
+
if (this.stopped) throw new Error("Market-data worker disposed");
|
|
445
|
+
options?.signal?.throwIfAborted();
|
|
446
|
+
const fallbackAfterStartup = this.fallback;
|
|
447
|
+
if (fallbackAfterStartup) return fallbackAfterStartup.loadHistory(manifest, options);
|
|
448
|
+
const remote = this.remote;
|
|
449
|
+
if (!remote) throw new Error("Market-data worker unavailable");
|
|
450
|
+
let rejectFailure;
|
|
451
|
+
const failed = new Promise((_resolve, reject) => {
|
|
452
|
+
rejectFailure = reject;
|
|
453
|
+
this.historyFailures.add(reject);
|
|
454
|
+
});
|
|
455
|
+
const abort = () => {
|
|
456
|
+
this.remote?.cancelHistoryRange(key, generation);
|
|
457
|
+
};
|
|
458
|
+
options?.signal?.addEventListener("abort", abort, { once: true });
|
|
459
|
+
try {
|
|
460
|
+
const result = await Promise.race([remote.loadImmutableRange(key, generation, manifest), failed]);
|
|
461
|
+
options?.signal?.throwIfAborted();
|
|
462
|
+
return result;
|
|
463
|
+
} finally {
|
|
464
|
+
options?.signal?.removeEventListener("abort", abort);
|
|
465
|
+
this.historyFailures.delete(rejectFailure);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
setHostDiagnostics(provider) {
|
|
469
|
+
this.hostProvider = provider;
|
|
470
|
+
}
|
|
471
|
+
getDiagnostics() {
|
|
472
|
+
const subscriptions = [...this.refs.values()].map((entry) => entry.sub);
|
|
473
|
+
return this.fallback ? {
|
|
474
|
+
...this.fallback.getDiagnostics(),
|
|
475
|
+
host: this.hostProvider?.(),
|
|
476
|
+
pendingHistoryRequests: this.historyOperations,
|
|
477
|
+
workerAttached: false,
|
|
478
|
+
bridgeListeners: this.endpointListeners.size
|
|
479
|
+
} : {
|
|
480
|
+
connected: this.connected,
|
|
481
|
+
host: this.hostProvider?.(),
|
|
482
|
+
transport: this.stopped ? "disposed" : "worker",
|
|
483
|
+
orderbookOutcomeIds: subscriptions.filter((sub) => sub.channel === "orderbook").map((sub) => sub.id),
|
|
484
|
+
tradeOutcomeIds: subscriptions.filter((sub) => sub.channel === "trades").map((sub) => sub.id),
|
|
485
|
+
arbMarketIds: [...this.arbListeners.keys()],
|
|
486
|
+
arbFeedSubscribers: this.feedListeners.size,
|
|
487
|
+
cachedBooks: this.currentBooks.size,
|
|
488
|
+
cachedArb: this.latest.size,
|
|
489
|
+
resyncingBooks: this.recovering.size,
|
|
490
|
+
pendingResnapshots: 0,
|
|
491
|
+
pendingHistoryRequests: this.historyOperations,
|
|
492
|
+
workerAttached: this.worker !== null,
|
|
493
|
+
bridgeListeners: this.endpointListeners.size
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
async getWorkerDiagnostics() {
|
|
497
|
+
await this.ready;
|
|
498
|
+
const remote = this.remote;
|
|
499
|
+
if (this.stopped || !remote || this.fallback) return null;
|
|
500
|
+
let rejectFailure;
|
|
501
|
+
const failed = new Promise((_resolve, reject) => {
|
|
502
|
+
rejectFailure = reject;
|
|
503
|
+
this.historyFailures.add(reject);
|
|
504
|
+
});
|
|
505
|
+
try {
|
|
506
|
+
return await Promise.race([remote.getMeasurements(), failed]);
|
|
507
|
+
} catch {
|
|
508
|
+
return null;
|
|
509
|
+
} finally {
|
|
510
|
+
this.historyFailures.delete(rejectFailure);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
get connected() {
|
|
514
|
+
return !this.stopped && (this.fallback?.connected ?? this.online);
|
|
515
|
+
}
|
|
516
|
+
getBook(id) {
|
|
517
|
+
return this.fallback?.getBook(id) ?? this.currentBooks.get(id) ?? null;
|
|
518
|
+
}
|
|
519
|
+
isResyncing(id) {
|
|
520
|
+
return this.fallback?.isResyncing(id) ?? this.recovering.has(id);
|
|
521
|
+
}
|
|
522
|
+
getArb(id) {
|
|
523
|
+
return this.fallback?.getArb(id) ?? this.latest.get(id) ?? null;
|
|
524
|
+
}
|
|
525
|
+
subscribe(id, channel = "orderbook") {
|
|
526
|
+
return this.ref({
|
|
527
|
+
id,
|
|
528
|
+
channel
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
subscribeTrades(id) {
|
|
532
|
+
return this.subscribe(id, "trades");
|
|
533
|
+
}
|
|
534
|
+
subscribeArb(id, cb) {
|
|
535
|
+
const listeners = this.arbListeners.get(id) ?? /* @__PURE__ */ new Set();
|
|
536
|
+
listeners.add(cb);
|
|
537
|
+
this.arbListeners.set(id, listeners);
|
|
538
|
+
const unsubscribe = this.ref({
|
|
539
|
+
id,
|
|
540
|
+
channel: "arb"
|
|
541
|
+
});
|
|
542
|
+
return () => {
|
|
543
|
+
unsubscribe();
|
|
544
|
+
listeners.delete(cb);
|
|
545
|
+
if (!listeners.size) this.arbListeners.delete(id);
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
subscribeArbFeed(cb) {
|
|
549
|
+
this.feedListeners.add(cb);
|
|
550
|
+
const unsubscribe = this.ref({
|
|
551
|
+
id: "*",
|
|
552
|
+
channel: "arb-feed"
|
|
553
|
+
});
|
|
554
|
+
return () => {
|
|
555
|
+
unsubscribe();
|
|
556
|
+
this.feedListeners.delete(cb);
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
setCallbacks(callbacks) {
|
|
560
|
+
this.handlers = callbacks;
|
|
561
|
+
if (callbacks.onTrade && !callbacks.onMarketView && !this.fallback) this.fail();
|
|
562
|
+
this.fallback?.setCallbacks(this.fallbackCallbacks());
|
|
563
|
+
}
|
|
564
|
+
authenticate(token) {
|
|
565
|
+
this.config.initialToken = token;
|
|
566
|
+
this.run((engine) => engine.authenticate(token));
|
|
567
|
+
}
|
|
568
|
+
connect() {
|
|
569
|
+
this.run((engine) => engine.connect());
|
|
570
|
+
}
|
|
571
|
+
disconnect() {
|
|
572
|
+
this.run((engine) => engine.disconnect());
|
|
573
|
+
}
|
|
574
|
+
resnapshot(id) {
|
|
575
|
+
const ids = Array.isArray(id) ? id : [id];
|
|
576
|
+
this.run((engine) => engine.resnapshot(ids));
|
|
577
|
+
}
|
|
578
|
+
destroy() {
|
|
579
|
+
if (this.stopped) return;
|
|
580
|
+
this.stopped = true;
|
|
581
|
+
this.online = false;
|
|
582
|
+
this.resolveFailure?.();
|
|
583
|
+
for (const reject of this.historyFailures) reject(/* @__PURE__ */ new Error("Market-data worker disposed"));
|
|
584
|
+
this.historyFailures.clear();
|
|
585
|
+
this.refs.clear();
|
|
586
|
+
this.currentBooks.clear();
|
|
587
|
+
this.latest.clear();
|
|
588
|
+
this.arbListeners.clear();
|
|
589
|
+
this.feedListeners.clear();
|
|
590
|
+
this.recovering.clear();
|
|
591
|
+
this.diagnosticRevisions.clear();
|
|
592
|
+
this.deliveredRevisions.clear();
|
|
593
|
+
this.resolvedRevisions.clear();
|
|
594
|
+
this.fallback?.destroy();
|
|
595
|
+
this.fallbackUnsubs.clear();
|
|
596
|
+
this.hostProvider = void 0;
|
|
597
|
+
this.handlers = {};
|
|
598
|
+
if (typeof document !== "undefined") document.removeEventListener("visibilitychange", this.visibility);
|
|
599
|
+
this.releaseWorker();
|
|
600
|
+
}
|
|
601
|
+
releaseWorker() {
|
|
602
|
+
const worker = this.worker;
|
|
603
|
+
const remote = this.remote;
|
|
604
|
+
this.remote = null;
|
|
605
|
+
this.worker = null;
|
|
606
|
+
if (remote) remote[import_comlink.releaseProxy]();
|
|
607
|
+
if (!worker) return;
|
|
608
|
+
for (const [listener, type] of this.endpointListeners) worker.removeEventListener(type, listener);
|
|
609
|
+
this.endpointListeners.clear();
|
|
610
|
+
worker.removeEventListener("error", this.fail);
|
|
611
|
+
worker.removeEventListener("messageerror", this.fail);
|
|
612
|
+
worker.terminate();
|
|
613
|
+
}
|
|
614
|
+
event(name, args, revision = 0) {
|
|
615
|
+
if (this.stopped) return;
|
|
616
|
+
if (name === "onConnectionStateChange") this.online = args[0];
|
|
617
|
+
if (name === "onDiagnostics") {
|
|
618
|
+
const diagnostic = args[0];
|
|
619
|
+
if (diagnostic.outcomeId && revision < (this.deliveredRevisions.get(diagnostic.outcomeId) ?? -1)) return;
|
|
620
|
+
if (diagnostic.outcomeId && (this.refs.has(`orderbook:${diagnostic.outcomeId}`) || this.refs.has(`trades:${diagnostic.outcomeId}`)) && ["seq_gap", "checksum_mismatch"].includes(diagnostic.type)) {
|
|
621
|
+
this.recovering.add(diagnostic.outcomeId);
|
|
622
|
+
this.diagnosticRevisions.set(diagnostic.outcomeId, revision);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
if (name === "onMarketResolved") {
|
|
626
|
+
const id = args[0].outcomeId;
|
|
627
|
+
if (this.refs.has(`orderbook:${id}`) || this.refs.has(`trades:${id}`)) this.resolvedRevisions.set(id, revision);
|
|
628
|
+
this.currentBooks.delete(id);
|
|
629
|
+
}
|
|
630
|
+
if (name === "onArbMarket") {
|
|
631
|
+
const msg = args[0];
|
|
632
|
+
this.latest.set(msg.marketId, msg);
|
|
633
|
+
for (const cb of this.arbListeners.get(msg.marketId) ?? []) cb(msg);
|
|
634
|
+
}
|
|
635
|
+
if (name === "onArbFeed") for (const cb of this.feedListeners) cb(args[0]);
|
|
636
|
+
this.handlers[name]?.(...args);
|
|
637
|
+
}
|
|
638
|
+
ref(sub) {
|
|
639
|
+
const key = `${sub.channel}:${sub.id}`;
|
|
640
|
+
const entry = this.refs.get(key) ?? {
|
|
641
|
+
sub,
|
|
642
|
+
count: 0
|
|
643
|
+
};
|
|
644
|
+
entry.count++;
|
|
645
|
+
this.refs.set(key, entry);
|
|
646
|
+
this.sync();
|
|
647
|
+
let released = false;
|
|
648
|
+
return () => {
|
|
649
|
+
if (released) return;
|
|
650
|
+
released = true;
|
|
651
|
+
if (--entry.count === 0) {
|
|
652
|
+
this.refs.delete(key);
|
|
653
|
+
if (sub.channel === "orderbook") this.recovering.delete(sub.id);
|
|
654
|
+
if (!this.refs.has(`orderbook:${sub.id}`) && !this.refs.has(`trades:${sub.id}`)) {
|
|
655
|
+
this.currentBooks.delete(sub.id);
|
|
656
|
+
this.recovering.delete(sub.id);
|
|
657
|
+
this.diagnosticRevisions.delete(sub.id);
|
|
658
|
+
this.deliveredRevisions.delete(sub.id);
|
|
659
|
+
this.resolvedRevisions.delete(sub.id);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
this.sync();
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
sync() {
|
|
666
|
+
if (this.queued || this.stopped) return;
|
|
667
|
+
this.queued = true;
|
|
668
|
+
queueMicrotask(() => {
|
|
669
|
+
this.queued = false;
|
|
670
|
+
if (this.stopped) return;
|
|
671
|
+
if (this.fallback) {
|
|
672
|
+
this.syncFallback();
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
const generation = ++this.generation;
|
|
676
|
+
const subscriptions = [...this.refs.values()].map((entry) => entry.sub);
|
|
677
|
+
this.ready.then(() => {
|
|
678
|
+
if (!this.stopped && !this.fallback) return this.remote?.setSubscriptions(subscriptions, generation);
|
|
679
|
+
}).catch(this.fail);
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
run(action) {
|
|
683
|
+
if (this.stopped) return;
|
|
684
|
+
if (this.fallback) {
|
|
685
|
+
action(this.fallback);
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
this.ready.then(() => {
|
|
689
|
+
if (this.stopped) return;
|
|
690
|
+
const engine = this.fallback ?? this.remote;
|
|
691
|
+
if (engine) return action(engine);
|
|
692
|
+
}).catch(this.fail);
|
|
693
|
+
}
|
|
694
|
+
fallbackCallbacks() {
|
|
695
|
+
return {
|
|
696
|
+
...this.handlers,
|
|
697
|
+
onArbMarket: (msg) => this.event("onArbMarket", [msg]),
|
|
698
|
+
onArbFeed: (msg) => this.event("onArbFeed", [msg])
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
syncFallback() {
|
|
702
|
+
for (const [key, unsubscribe] of this.fallbackUnsubs) if (!this.refs.has(key)) {
|
|
703
|
+
unsubscribe();
|
|
704
|
+
this.fallbackUnsubs.delete(key);
|
|
705
|
+
}
|
|
706
|
+
for (const [key, { sub }] of this.refs) {
|
|
707
|
+
if (this.fallbackUnsubs.has(key)) continue;
|
|
708
|
+
this.fallbackUnsubs.set(key, sub.channel === "arb" ? this.fallback.subscribeArb(sub.id, () => {}) : sub.channel === "arb-feed" ? this.fallback.subscribeArbFeed(() => {}) : this.fallback.subscribe(sub.id, sub.channel));
|
|
709
|
+
}
|
|
710
|
+
}
|
|
2151
711
|
};
|
|
2152
712
|
function createWorkerWebSocket(options, factory) {
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
0 && (module.exports = {
|
|
2164
|
-
WorkerAggWebSocket,
|
|
2165
|
-
createWorkerWebSocket
|
|
2166
|
-
});
|
|
2167
|
-
/*! Bundled license information:
|
|
2168
|
-
|
|
2169
|
-
comlink/dist/esm/comlink.mjs:
|
|
2170
|
-
(**
|
|
2171
|
-
* @license
|
|
2172
|
-
* Copyright 2019 Google LLC
|
|
2173
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
2174
|
-
*)
|
|
2175
|
-
*/
|
|
713
|
+
if (options.callbacks?.onTrade && !options.callbacks.onMarketView) return new require_agg_websocket.AggWebSocket(options);
|
|
714
|
+
try {
|
|
715
|
+
return new WorkerAggWebSocket(options, factory);
|
|
716
|
+
} catch {
|
|
717
|
+
return new require_agg_websocket.AggWebSocket(options);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
//#endregion
|
|
721
|
+
exports.WorkerAggWebSocket = WorkerAggWebSocket;
|
|
722
|
+
exports.createWorkerWebSocket = createWorkerWebSocket;
|