@bluebottle_gg/league-broadcast-client 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +275 -78
- package/dist/index.d.ts +1126 -88
- package/dist/index.js +1046 -111
- package/dist/index.js.map +1 -1
- package/package.json +8 -6
package/dist/index.js
CHANGED
|
@@ -326,6 +326,134 @@ function shallowEqual(a, b) {
|
|
|
326
326
|
return true;
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
+
// src/reactivity/ChampSelectStateStore.ts
|
|
330
|
+
var ChampSelectStateStore = class {
|
|
331
|
+
constructor(initialState) {
|
|
332
|
+
/** Global listeners — called on every state change regardless of selector. */
|
|
333
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
334
|
+
/** Monotonically increasing version — used for cheap stale checks. */
|
|
335
|
+
this.version = 0;
|
|
336
|
+
this.snapshot = Object.freeze({
|
|
337
|
+
champSelectData: initialState,
|
|
338
|
+
isActive: initialState.isActive,
|
|
339
|
+
version: this.version
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
// ---------------------------------------------------------------------------
|
|
343
|
+
// Core API
|
|
344
|
+
// ---------------------------------------------------------------------------
|
|
345
|
+
/** Return the current full snapshot. */
|
|
346
|
+
getSnapshot() {
|
|
347
|
+
return this.snapshot;
|
|
348
|
+
}
|
|
349
|
+
/** Return the current version number. */
|
|
350
|
+
getVersion() {
|
|
351
|
+
return this.version;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Subscribe to **all** state changes (unfiltered).
|
|
355
|
+
* Returns an unsubscribe function.
|
|
356
|
+
*/
|
|
357
|
+
subscribe(listener) {
|
|
358
|
+
this.listeners.add(listener);
|
|
359
|
+
return () => {
|
|
360
|
+
this.listeners.delete(listener);
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
// ---------------------------------------------------------------------------
|
|
364
|
+
// Selectors
|
|
365
|
+
// ---------------------------------------------------------------------------
|
|
366
|
+
/**
|
|
367
|
+
* Create a **subscribable slice** that only triggers when the selected
|
|
368
|
+
* value changes according to `equalityFn` (defaults to `===`).
|
|
369
|
+
*/
|
|
370
|
+
select(selector, equalityFn = Object.is) {
|
|
371
|
+
let currentValue = selector(this.snapshot);
|
|
372
|
+
let lastVersion = this.version;
|
|
373
|
+
const sliceListeners = /* @__PURE__ */ new Set();
|
|
374
|
+
const getSnapshot = () => {
|
|
375
|
+
if (lastVersion !== this.version) {
|
|
376
|
+
const next = selector(this.snapshot);
|
|
377
|
+
if (!equalityFn(currentValue, next)) {
|
|
378
|
+
currentValue = next;
|
|
379
|
+
}
|
|
380
|
+
lastVersion = this.version;
|
|
381
|
+
}
|
|
382
|
+
return currentValue;
|
|
383
|
+
};
|
|
384
|
+
const subscribe = (listener) => {
|
|
385
|
+
sliceListeners.add(listener);
|
|
386
|
+
const unsub = this.subscribe(() => {
|
|
387
|
+
const prev = currentValue;
|
|
388
|
+
const next = selector(this.snapshot);
|
|
389
|
+
lastVersion = this.version;
|
|
390
|
+
if (!equalityFn(prev, next)) {
|
|
391
|
+
currentValue = next;
|
|
392
|
+
listener();
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
return () => {
|
|
396
|
+
sliceListeners.delete(listener);
|
|
397
|
+
unsub();
|
|
398
|
+
};
|
|
399
|
+
};
|
|
400
|
+
return { subscribe, getSnapshot };
|
|
401
|
+
}
|
|
402
|
+
// ---------------------------------------------------------------------------
|
|
403
|
+
// Convenience helpers
|
|
404
|
+
// ---------------------------------------------------------------------------
|
|
405
|
+
/**
|
|
406
|
+
* Watch a derived value and invoke `callback` whenever it changes.
|
|
407
|
+
* Returns an unsubscribe function.
|
|
408
|
+
*/
|
|
409
|
+
watch(selector, callback, equalityFn = Object.is) {
|
|
410
|
+
let prev = selector(this.snapshot);
|
|
411
|
+
return this.subscribe(() => {
|
|
412
|
+
const next = selector(this.snapshot);
|
|
413
|
+
if (!equalityFn(prev, next)) {
|
|
414
|
+
const old = prev;
|
|
415
|
+
prev = next;
|
|
416
|
+
callback(next, old);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Watch a derived value and invoke `callback` whenever it changes,
|
|
422
|
+
* **and** invoke it immediately with the current value.
|
|
423
|
+
*/
|
|
424
|
+
watchImmediate(selector, callback, equalityFn = Object.is) {
|
|
425
|
+
const current = selector(this.snapshot);
|
|
426
|
+
callback(current, void 0);
|
|
427
|
+
return this.watch(selector, callback, equalityFn);
|
|
428
|
+
}
|
|
429
|
+
// ---------------------------------------------------------------------------
|
|
430
|
+
// Internal — called by LeagueBroadcastClient
|
|
431
|
+
// ---------------------------------------------------------------------------
|
|
432
|
+
/** @internal Replace champ-select data snapshot and notify listeners. */
|
|
433
|
+
_setChampSelectData(data) {
|
|
434
|
+
this.version++;
|
|
435
|
+
this.snapshot = Object.freeze({
|
|
436
|
+
champSelectData: data,
|
|
437
|
+
isActive: data.isActive,
|
|
438
|
+
version: this.version
|
|
439
|
+
});
|
|
440
|
+
this.emit();
|
|
441
|
+
}
|
|
442
|
+
/** @internal Replace entire snapshot (used on champ select end / reset). */
|
|
443
|
+
_reset(data) {
|
|
444
|
+
this.version++;
|
|
445
|
+
this.snapshot = Object.freeze({
|
|
446
|
+
champSelectData: data,
|
|
447
|
+
isActive: data.isActive,
|
|
448
|
+
version: this.version
|
|
449
|
+
});
|
|
450
|
+
this.emit();
|
|
451
|
+
}
|
|
452
|
+
emit() {
|
|
453
|
+
this.listeners.forEach((l) => l());
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
|
|
329
457
|
// src/reactivity/structuralShare.ts
|
|
330
458
|
function structuralShare(prev, next) {
|
|
331
459
|
if (Object.is(prev, next)) {
|
|
@@ -358,6 +486,14 @@ function structuralShare(prev, next) {
|
|
|
358
486
|
const nextKeys = Object.keys(nextObj);
|
|
359
487
|
const prevKeys = Object.keys(prevObj);
|
|
360
488
|
let changed = nextKeys.length !== prevKeys.length;
|
|
489
|
+
if (!changed) {
|
|
490
|
+
for (const key of prevKeys) {
|
|
491
|
+
if (!Object.prototype.hasOwnProperty.call(nextObj, key)) {
|
|
492
|
+
changed = true;
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
361
497
|
const result = Object.create(
|
|
362
498
|
Object.getPrototypeOf(next)
|
|
363
499
|
);
|
|
@@ -398,156 +534,829 @@ var ingameFrontendData = class {
|
|
|
398
534
|
}
|
|
399
535
|
};
|
|
400
536
|
|
|
537
|
+
// types/pregame/champselectstatedata.ts
|
|
538
|
+
var champSelectStateData = class {
|
|
539
|
+
constructor() {
|
|
540
|
+
this.isActive = false;
|
|
541
|
+
this.isConnected = false;
|
|
542
|
+
this.isTestingEnvironment = false;
|
|
543
|
+
this.blueTeam = {};
|
|
544
|
+
this.redTeam = {};
|
|
545
|
+
this.metaData = {};
|
|
546
|
+
this.timer = {};
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
// src/api/ApiClient.ts
|
|
551
|
+
var ApiClient = class {
|
|
552
|
+
constructor(baseUrl) {
|
|
553
|
+
this.baseUrl = baseUrl;
|
|
554
|
+
}
|
|
555
|
+
/** Update the base URL (e.g. after reconnecting to a different host/port). */
|
|
556
|
+
updateBaseUrl(baseUrl) {
|
|
557
|
+
this.baseUrl = baseUrl;
|
|
558
|
+
}
|
|
559
|
+
/** Current base URL. */
|
|
560
|
+
getBaseUrl() {
|
|
561
|
+
return this.baseUrl;
|
|
562
|
+
}
|
|
563
|
+
// ── HTTP verbs ──────────────────────────────────────────────────────────
|
|
564
|
+
async get(path) {
|
|
565
|
+
return this.request("GET", path);
|
|
566
|
+
}
|
|
567
|
+
async post(path, body) {
|
|
568
|
+
return this.request("POST", path, body);
|
|
569
|
+
}
|
|
570
|
+
async put(path, body) {
|
|
571
|
+
return this.request("PUT", path, body);
|
|
572
|
+
}
|
|
573
|
+
async patch(path, body) {
|
|
574
|
+
return this.request("PATCH", path, body);
|
|
575
|
+
}
|
|
576
|
+
async delete(path) {
|
|
577
|
+
return this.request("DELETE", path);
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* POST with a raw string body (e.g. base64 image data).
|
|
581
|
+
* Sets Content-Type to text/plain instead of application/json.
|
|
582
|
+
*/
|
|
583
|
+
async postRaw(path, rawBody) {
|
|
584
|
+
return this.request("POST", path, rawBody, "text/plain");
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* PUT with a raw string body (e.g. base64 image data).
|
|
588
|
+
* Sets Content-Type to text/plain instead of application/json.
|
|
589
|
+
*/
|
|
590
|
+
async putRaw(path, rawBody) {
|
|
591
|
+
return this.request("PUT", path, rawBody, "text/plain");
|
|
592
|
+
}
|
|
593
|
+
// ── Internal ────────────────────────────────────────────────────────────
|
|
594
|
+
buildUrl(path) {
|
|
595
|
+
const base = this.baseUrl.endsWith("/") ? this.baseUrl.slice(0, -1) : this.baseUrl;
|
|
596
|
+
const cleanPath = path.startsWith("/") ? path.slice(1) : path;
|
|
597
|
+
return `${base}/${cleanPath}`;
|
|
598
|
+
}
|
|
599
|
+
async request(method, path, body, contentType) {
|
|
600
|
+
const url = this.buildUrl(path);
|
|
601
|
+
const headers = {};
|
|
602
|
+
let bodyStr;
|
|
603
|
+
if (body !== void 0) {
|
|
604
|
+
if (contentType === "text/plain") {
|
|
605
|
+
headers["Content-Type"] = "text/plain";
|
|
606
|
+
bodyStr = String(body);
|
|
607
|
+
} else {
|
|
608
|
+
headers["Content-Type"] = "application/json";
|
|
609
|
+
bodyStr = JSON.stringify(body);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
const res = await fetch(url, {
|
|
613
|
+
method,
|
|
614
|
+
headers,
|
|
615
|
+
body: bodyStr
|
|
616
|
+
});
|
|
617
|
+
if (!res.ok) {
|
|
618
|
+
const errorBody = await res.text().catch(() => "");
|
|
619
|
+
throw new ApiError(res.status, res.statusText, errorBody, url);
|
|
620
|
+
}
|
|
621
|
+
return this.parseResponse(res);
|
|
622
|
+
}
|
|
623
|
+
async parseResponse(res) {
|
|
624
|
+
const text = await res.text();
|
|
625
|
+
if (!text || text.length === 0) return void 0;
|
|
626
|
+
try {
|
|
627
|
+
return JSON.parse(text);
|
|
628
|
+
} catch {
|
|
629
|
+
return text;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
var ApiError = class extends Error {
|
|
634
|
+
constructor(status, statusText, body, url) {
|
|
635
|
+
super(`API Error ${status} (${statusText}) at ${url}`);
|
|
636
|
+
this.status = status;
|
|
637
|
+
this.statusText = statusText;
|
|
638
|
+
this.body = body;
|
|
639
|
+
this.url = url;
|
|
640
|
+
this.name = "ApiError";
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
// src/api/generated/PreGameApi.ts
|
|
645
|
+
var PreGameApi = class {
|
|
646
|
+
constructor(client) {
|
|
647
|
+
this.client = client;
|
|
648
|
+
}
|
|
649
|
+
/** `POST championselect/mock/{doMocking}` */
|
|
650
|
+
async mockChampionSelect(doMocking, randomizationinterval) {
|
|
651
|
+
return this.client.post(`championselect/mock/${doMocking}${randomizationinterval !== void 0 ? `?randomizationinterval=${encodeURIComponent(String(randomizationinterval))}` : ""}`);
|
|
652
|
+
}
|
|
653
|
+
/** `GET championselect/mock` */
|
|
654
|
+
async getMockingStatus() {
|
|
655
|
+
return this.client.get("championselect/mock");
|
|
656
|
+
}
|
|
657
|
+
/** `GET championselect/bans` */
|
|
658
|
+
async getBans() {
|
|
659
|
+
return this.client.get("championselect/bans");
|
|
660
|
+
}
|
|
661
|
+
/** `GET championselect/frontend` */
|
|
662
|
+
async getFrontendUrl() {
|
|
663
|
+
return this.client.get("championselect/frontend");
|
|
664
|
+
}
|
|
665
|
+
/** `GET championselect/stage/{stageSide}/teamid` */
|
|
666
|
+
async getTeamIdOnSide(stageSide) {
|
|
667
|
+
return this.client.get(`championselect/stage/${stageSide}/teamid`);
|
|
668
|
+
}
|
|
669
|
+
/** `POST championselect/frontend` */
|
|
670
|
+
async changeRouting(uri) {
|
|
671
|
+
return this.client.post(`championselect/frontend?uri=${encodeURIComponent(String(uri))}`);
|
|
672
|
+
}
|
|
673
|
+
/** `GET championselect/stage/{stageside}/{slotid}` */
|
|
674
|
+
async getPlayerPUUIDInSlot(stageside, slotid) {
|
|
675
|
+
return this.client.get(`championselect/stage/${stageside}/${slotid}`);
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
// src/api/generated/GameApi.ts
|
|
680
|
+
var GameApi = class {
|
|
681
|
+
constructor(client) {
|
|
682
|
+
this.client = client;
|
|
683
|
+
}
|
|
684
|
+
/** `GET game/current` */
|
|
685
|
+
async getCurrentGame() {
|
|
686
|
+
return this.client.get("game/current");
|
|
687
|
+
}
|
|
688
|
+
/** `GET game/previous` */
|
|
689
|
+
async getPreviousGame() {
|
|
690
|
+
return this.client.get("game/previous");
|
|
691
|
+
}
|
|
692
|
+
/** `GET game/{gameid}` */
|
|
693
|
+
async getGame(gameid) {
|
|
694
|
+
return this.client.get(`game/${gameid}`);
|
|
695
|
+
}
|
|
696
|
+
/** `PATCH game/{gameid}` */
|
|
697
|
+
async updateGame(gameid, game) {
|
|
698
|
+
return this.client.patch(`game/${gameid}`, game);
|
|
699
|
+
}
|
|
700
|
+
/** `PUT game/{gameid}/teams` */
|
|
701
|
+
async setSideSelection(gameid, teams) {
|
|
702
|
+
return this.client.put(`game/${gameid}/teams`, teams);
|
|
703
|
+
}
|
|
704
|
+
/** `GET game/{gameid}/teams` */
|
|
705
|
+
async getTeamsInGame(gameid) {
|
|
706
|
+
return this.client.get(`game/${gameid}/teams`);
|
|
707
|
+
}
|
|
708
|
+
/** `DELETE game/{gameid}/winner` */
|
|
709
|
+
async removeGameWinner(gameid) {
|
|
710
|
+
return this.client.delete(`game/${gameid}/winner`);
|
|
711
|
+
}
|
|
712
|
+
/** `PUT game/{gameid}/winner/{teamid}` */
|
|
713
|
+
async setGameWinner(gameid, teamid) {
|
|
714
|
+
return this.client.put(`game/${gameid}/winner/${teamid}`);
|
|
715
|
+
}
|
|
716
|
+
/** `GET game/{gameid}/bans` */
|
|
717
|
+
async getBans(gameid) {
|
|
718
|
+
return this.client.get(`game/${gameid}/bans`);
|
|
719
|
+
}
|
|
720
|
+
/** `GET game/{gameid}/bans/{teamid}` */
|
|
721
|
+
async getBansForTeam(gameid, teamid) {
|
|
722
|
+
return this.client.get(`game/${gameid}/bans/${teamid}`);
|
|
723
|
+
}
|
|
724
|
+
/** `PUT game/{gameid}/bans` */
|
|
725
|
+
async setBans(gameid, bans) {
|
|
726
|
+
return this.client.put(`game/${gameid}/bans`, bans);
|
|
727
|
+
}
|
|
728
|
+
/** `PUT game/{gameid}/bans/{teamid}` */
|
|
729
|
+
async setBansForTeam(gameid, teamid, bans) {
|
|
730
|
+
return this.client.put(`game/${gameid}/bans/${teamid}`, bans);
|
|
731
|
+
}
|
|
732
|
+
/** `GET game/{gameid}/picks` */
|
|
733
|
+
async getPicks(gameid) {
|
|
734
|
+
return this.client.get(`game/${gameid}/picks`);
|
|
735
|
+
}
|
|
736
|
+
/** `GET game/{gameid}/picks/{teamid}` */
|
|
737
|
+
async getPicksForTeam(gameid, teamid) {
|
|
738
|
+
return this.client.get(`game/${gameid}/picks/${teamid}`);
|
|
739
|
+
}
|
|
740
|
+
/** `PUT game/{gameid}/picks` */
|
|
741
|
+
async setPicks(gameid, picks) {
|
|
742
|
+
return this.client.put(`game/${gameid}/picks`, picks);
|
|
743
|
+
}
|
|
744
|
+
/** `PUT game/{gameid}/picks/{teamid}` */
|
|
745
|
+
async setPicksForTeam(gameid, teamid, picks) {
|
|
746
|
+
return this.client.put(`game/${gameid}/picks/${teamid}`, picks);
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
// src/api/generated/GameStateApi.ts
|
|
751
|
+
var GameStateApi = class {
|
|
752
|
+
constructor(client) {
|
|
753
|
+
this.client = client;
|
|
754
|
+
}
|
|
755
|
+
/** `GET game/state/time` */
|
|
756
|
+
async getGameTime() {
|
|
757
|
+
return this.client.get("game/state/time");
|
|
758
|
+
}
|
|
759
|
+
/** `GET game/state/team/{teamId}/dragons` */
|
|
760
|
+
async getTeamDragons(teamId) {
|
|
761
|
+
return this.client.get(`game/state/team/${teamId}/dragons`);
|
|
762
|
+
}
|
|
763
|
+
/** `PATCH game/state/team/{teamId}/dragons` */
|
|
764
|
+
async updateTeamDragons(teamId, dragons) {
|
|
765
|
+
return this.client.patch(`game/state/team/${teamId}/dragons`, dragons);
|
|
766
|
+
}
|
|
767
|
+
/** `GET game/state/team/all/index` */
|
|
768
|
+
async getActiveTeams() {
|
|
769
|
+
return this.client.get("game/state/team/all/index");
|
|
770
|
+
}
|
|
771
|
+
/** `GET game/state/team/all/participant` */
|
|
772
|
+
async getAllTeamParticipants() {
|
|
773
|
+
return this.client.get("game/state/team/all/participant");
|
|
774
|
+
}
|
|
775
|
+
/** `GET game/state/team/{teamId}/participant` */
|
|
776
|
+
async getTeamParticipants(teamId) {
|
|
777
|
+
return this.client.get(`game/state/team/${teamId}/participant`);
|
|
778
|
+
}
|
|
779
|
+
/** `GET game/state/team/all/participant/order` */
|
|
780
|
+
async getTeamParticipantOrder() {
|
|
781
|
+
return this.client.get("game/state/team/all/participant/order");
|
|
782
|
+
}
|
|
783
|
+
/** `PUT game/state/team/all/participant/order` */
|
|
784
|
+
async updateTeamParticipantOrder(orderedNames) {
|
|
785
|
+
return this.client.put("game/state/team/all/participant/order", orderedNames);
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
|
|
789
|
+
// src/api/generated/MatchApi.ts
|
|
790
|
+
var MatchApi = class {
|
|
791
|
+
constructor(client) {
|
|
792
|
+
this.client = client;
|
|
793
|
+
}
|
|
794
|
+
/** `GET match/season/{seasonId}/simple` */
|
|
795
|
+
async getSimpleMatches(seasonId) {
|
|
796
|
+
return this.client.get(`match/season/${seasonId}/simple`);
|
|
797
|
+
}
|
|
798
|
+
/** `GET match/season/{seasonId}` */
|
|
799
|
+
async getMatches(seasonId) {
|
|
800
|
+
return this.client.get(`match/season/${seasonId}`);
|
|
801
|
+
}
|
|
802
|
+
/** `GET match/simple` */
|
|
803
|
+
async getAllSimpleMatches() {
|
|
804
|
+
return this.client.get("match/simple");
|
|
805
|
+
}
|
|
806
|
+
/** `GET match` */
|
|
807
|
+
async getAllMatches() {
|
|
808
|
+
return this.client.get("match");
|
|
809
|
+
}
|
|
810
|
+
/** `GET match/current` */
|
|
811
|
+
async getCurrentMatch() {
|
|
812
|
+
return this.client.get("match/current");
|
|
813
|
+
}
|
|
814
|
+
/** `POST match/current` */
|
|
815
|
+
async completeCurrentMatch() {
|
|
816
|
+
return this.client.post("match/current");
|
|
817
|
+
}
|
|
818
|
+
/** `GET match/current/id` */
|
|
819
|
+
async getCurrentMatchId() {
|
|
820
|
+
return this.client.get("match/current/id");
|
|
821
|
+
}
|
|
822
|
+
/** `GET match/previous/id` */
|
|
823
|
+
async getPreviousMatchId() {
|
|
824
|
+
return this.client.get("match/previous/id");
|
|
825
|
+
}
|
|
826
|
+
/** `POST match/current/{seriesid}` */
|
|
827
|
+
async setCurrentMatch(seriesid) {
|
|
828
|
+
return this.client.post(`match/current/${seriesid}`);
|
|
829
|
+
}
|
|
830
|
+
/** `GET match/current/bestof` */
|
|
831
|
+
async getCurrentMatchBestOf() {
|
|
832
|
+
return this.client.get("match/current/bestof");
|
|
833
|
+
}
|
|
834
|
+
/** `PUT match/current/bestof` */
|
|
835
|
+
async setCurrentMatchBestOf(type) {
|
|
836
|
+
return this.client.put("match/current/bestof", type);
|
|
837
|
+
}
|
|
838
|
+
/** `GET match/current/teams` */
|
|
839
|
+
async getCurrentMatchTeams() {
|
|
840
|
+
return this.client.get("match/current/teams");
|
|
841
|
+
}
|
|
842
|
+
/** `PUT match/current/teams` */
|
|
843
|
+
async setCurrentMatchTeams(teamIds) {
|
|
844
|
+
return this.client.put("match/current/teams", teamIds);
|
|
845
|
+
}
|
|
846
|
+
/** `GET match/current/game` */
|
|
847
|
+
async getCurrentGame() {
|
|
848
|
+
return this.client.get("match/current/game");
|
|
849
|
+
}
|
|
850
|
+
/** `GET match/current/ruleset` */
|
|
851
|
+
async getCurrentMatchRuleset() {
|
|
852
|
+
return this.client.get("match/current/ruleset");
|
|
853
|
+
}
|
|
854
|
+
/** `PUT match/current/ruleset/{ruleset}` */
|
|
855
|
+
async setCurrentMatchRuleset(ruleset) {
|
|
856
|
+
return this.client.put(`match/current/ruleset/${ruleset}`);
|
|
857
|
+
}
|
|
858
|
+
/** `GET match/current/fearless/bans` */
|
|
859
|
+
async getBans() {
|
|
860
|
+
return this.client.get("match/current/fearless/bans");
|
|
861
|
+
}
|
|
862
|
+
/** `GET match/current/onstage` */
|
|
863
|
+
async getCurrentMatchOnStage() {
|
|
864
|
+
return this.client.get("match/current/onstage");
|
|
865
|
+
}
|
|
866
|
+
/** `GET match/{matchid}` */
|
|
867
|
+
async getMatch(matchid) {
|
|
868
|
+
return this.client.get(`match/${matchid}`);
|
|
869
|
+
}
|
|
870
|
+
/** `DELETE match/{matchid}` */
|
|
871
|
+
async deleteMatch(matchid) {
|
|
872
|
+
return this.client.delete(`match/${matchid}`);
|
|
873
|
+
}
|
|
874
|
+
/** `GET match/{matchid}/teams` */
|
|
875
|
+
async getMatchTeams(matchid) {
|
|
876
|
+
return this.client.get(`match/${matchid}/teams`);
|
|
877
|
+
}
|
|
878
|
+
/** `PUT match/{matchid}/teams` */
|
|
879
|
+
async setMatchTeams(matchid, teamIds) {
|
|
880
|
+
return this.client.put(`match/${matchid}/teams`, teamIds);
|
|
881
|
+
}
|
|
882
|
+
/** `GET match/{matchid}/games` */
|
|
883
|
+
async getMatchGames(matchid) {
|
|
884
|
+
return this.client.get(`match/${matchid}/games`);
|
|
885
|
+
}
|
|
886
|
+
/** `GET match/{matchid}/winner` */
|
|
887
|
+
async getMatchWinner(matchid) {
|
|
888
|
+
return this.client.get(`match/${matchid}/winner`);
|
|
889
|
+
}
|
|
890
|
+
/** `PUT match/{matchid}/winner/{teamid}` */
|
|
891
|
+
async setMatchWinner(matchid, teamid) {
|
|
892
|
+
return this.client.put(`match/${matchid}/winner/${teamid}`);
|
|
893
|
+
}
|
|
894
|
+
/** `DELETE match/{matchid}/winner` */
|
|
895
|
+
async removeMatchWinner(matchid) {
|
|
896
|
+
return this.client.delete(`match/${matchid}/winner`);
|
|
897
|
+
}
|
|
898
|
+
/** `GET match/{matchid}/bestof` */
|
|
899
|
+
async getMatchBestOf(matchid) {
|
|
900
|
+
return this.client.get(`match/${matchid}/bestof`);
|
|
901
|
+
}
|
|
902
|
+
/** `PUT match/{matchid}/bestof/{type}` */
|
|
903
|
+
async setMatchBestOf(matchid, type) {
|
|
904
|
+
return this.client.put(`match/${matchid}/bestof/${type}`);
|
|
905
|
+
}
|
|
906
|
+
/** `GET match/{matchid}/ruleset` */
|
|
907
|
+
async getMatchRuleset(matchid) {
|
|
908
|
+
return this.client.get(`match/${matchid}/ruleset`);
|
|
909
|
+
}
|
|
910
|
+
/** `PUT match/{matchid}/ruleset/{ruleset}` */
|
|
911
|
+
async setMatchRuleset(matchid, ruleset) {
|
|
912
|
+
return this.client.put(`match/${matchid}/ruleset/${ruleset}`);
|
|
913
|
+
}
|
|
914
|
+
/** `GET match/{matchid}/name` */
|
|
915
|
+
async getMatchName(matchid) {
|
|
916
|
+
return this.client.get(`match/${matchid}/name`);
|
|
917
|
+
}
|
|
918
|
+
/** `PATCH match/{matchid}/name/{matchName}` */
|
|
919
|
+
async setMatchName(matchid, matchName) {
|
|
920
|
+
return this.client.patch(`match/${matchid}/name/${matchName}`);
|
|
921
|
+
}
|
|
922
|
+
/** `PATCH match/{matchid}` */
|
|
923
|
+
async updateMatch(matchid, matchUpdate) {
|
|
924
|
+
return this.client.patch(`match/${matchid}`, matchUpdate);
|
|
925
|
+
}
|
|
926
|
+
/** `GET match/{matchid}/fearless/bans` */
|
|
927
|
+
async getMatchBans(matchid) {
|
|
928
|
+
return this.client.get(`match/${matchid}/fearless/bans`);
|
|
929
|
+
}
|
|
930
|
+
/** `GET match/{seriesid}/onstage` */
|
|
931
|
+
async getMatchOnStage(seriesid) {
|
|
932
|
+
return this.client.get(`match/${seriesid}/onstage`);
|
|
933
|
+
}
|
|
934
|
+
/** `PUT match` */
|
|
935
|
+
async addMatch(match) {
|
|
936
|
+
return this.client.put("match", match);
|
|
937
|
+
}
|
|
938
|
+
/** `GET match/{matchId}/stage/team/{stageSide}` */
|
|
939
|
+
async getTeamOnStageSide(matchId, stageSide) {
|
|
940
|
+
return this.client.get(`match/${matchId}/stage/team/${stageSide}`);
|
|
941
|
+
}
|
|
942
|
+
/** `GET match/current/stage/team/{stageSide}` */
|
|
943
|
+
async getTeamOnStageSideCurrent(stageSide) {
|
|
944
|
+
return this.client.get(`match/current/stage/team/${stageSide}`);
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
// src/api/generated/SeasonApi.ts
|
|
949
|
+
var SeasonApi = class {
|
|
950
|
+
constructor(client) {
|
|
951
|
+
this.client = client;
|
|
952
|
+
}
|
|
953
|
+
/** `GET season/current` */
|
|
954
|
+
async getCurrentSeason() {
|
|
955
|
+
return this.client.get("season/current");
|
|
956
|
+
}
|
|
957
|
+
/** `GET season/current/match` */
|
|
958
|
+
async getCurrentSeasonScheduledMatch() {
|
|
959
|
+
return this.client.get("season/current/match");
|
|
960
|
+
}
|
|
961
|
+
/** `GET season/current/id` */
|
|
962
|
+
async getCurrentSeasonId() {
|
|
963
|
+
return this.client.get("season/current/id");
|
|
964
|
+
}
|
|
965
|
+
/** `POST season/current` */
|
|
966
|
+
async setCurrentSeason(newCurrentSeasonId) {
|
|
967
|
+
return this.client.post("season/current", newCurrentSeasonId);
|
|
968
|
+
}
|
|
969
|
+
/** `GET season/current/teams` */
|
|
970
|
+
async getCurrentSeasonTeams() {
|
|
971
|
+
return this.client.get("season/current/teams");
|
|
972
|
+
}
|
|
973
|
+
/** `GET season/current/teamswithmembers` */
|
|
974
|
+
async getCurrentSeasonTeamsWithMembers() {
|
|
975
|
+
return this.client.get("season/current/teamswithmembers");
|
|
976
|
+
}
|
|
977
|
+
/** `GET season/current/icon` */
|
|
978
|
+
async getCurrentSeasonIcon() {
|
|
979
|
+
return this.client.get("season/current/icon");
|
|
980
|
+
}
|
|
981
|
+
/** `PUT season/current/icon` */
|
|
982
|
+
async setCurrentSeasonIcon() {
|
|
983
|
+
return this.client.put("season/current/icon");
|
|
984
|
+
}
|
|
985
|
+
/** `GET season` */
|
|
986
|
+
async getAllSeasons() {
|
|
987
|
+
return this.client.get("season");
|
|
988
|
+
}
|
|
989
|
+
/** `GET season/{seasonId}` */
|
|
990
|
+
async getSeasonById(seasonId) {
|
|
991
|
+
return this.client.get(`season/${seasonId}`);
|
|
992
|
+
}
|
|
993
|
+
/** `GET season/{seasonId}/matches` */
|
|
994
|
+
async getMatchesInSeason(seasonId) {
|
|
995
|
+
return this.client.get(`season/${seasonId}/matches`);
|
|
996
|
+
}
|
|
997
|
+
/** `GET season/{seasonId}/matches/count` */
|
|
998
|
+
async getMatchesInSeasonCount(seasonId) {
|
|
999
|
+
return this.client.get(`season/${seasonId}/matches/count`);
|
|
1000
|
+
}
|
|
1001
|
+
/** `GET season/{seasonId}/matches/day/{day}` */
|
|
1002
|
+
async getMatchesInSeasonOnDay(seasonId, day) {
|
|
1003
|
+
return this.client.get(`season/${seasonId}/matches/day/${day}`);
|
|
1004
|
+
}
|
|
1005
|
+
/** `GET season/{seasonId}/teams` */
|
|
1006
|
+
async getTeamsInSeason(seasonId) {
|
|
1007
|
+
return this.client.get(`season/${seasonId}/teams`);
|
|
1008
|
+
}
|
|
1009
|
+
/** `GET season/{seasonId}/teamswithmembers` */
|
|
1010
|
+
async getTeamsWithMembersInSeason(seasonId) {
|
|
1011
|
+
return this.client.get(`season/${seasonId}/teamswithmembers`);
|
|
1012
|
+
}
|
|
1013
|
+
/** `POST season` */
|
|
1014
|
+
async createOrUpdateSeason(seasonData) {
|
|
1015
|
+
return this.client.post("season", seasonData);
|
|
1016
|
+
}
|
|
1017
|
+
/** `GET season/{seasonId}/icon` */
|
|
1018
|
+
async getSeasonIcon(seasonId) {
|
|
1019
|
+
return this.client.get(`season/${seasonId}/icon`);
|
|
1020
|
+
}
|
|
1021
|
+
/** `PUT season/{seasonId}/icon` */
|
|
1022
|
+
async setSeasonIcon(seasonId) {
|
|
1023
|
+
return this.client.put(`season/${seasonId}/icon`);
|
|
1024
|
+
}
|
|
1025
|
+
/** `DELETE season/{seasonId}` */
|
|
1026
|
+
async deleteSeason(seasonId) {
|
|
1027
|
+
return this.client.delete(`season/${seasonId}`);
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
|
|
1031
|
+
// src/api/generated/IngameApi.ts
|
|
1032
|
+
var IngameApi = class {
|
|
1033
|
+
constructor(client) {
|
|
1034
|
+
this.client = client;
|
|
1035
|
+
}
|
|
1036
|
+
/** `GET ingame/status` */
|
|
1037
|
+
async getGameState() {
|
|
1038
|
+
return this.client.get("ingame/status");
|
|
1039
|
+
}
|
|
1040
|
+
/** `POST ingame/enable` */
|
|
1041
|
+
async enableComponent() {
|
|
1042
|
+
return this.client.post("ingame/enable");
|
|
1043
|
+
}
|
|
1044
|
+
/** `POST ingame/disable` */
|
|
1045
|
+
async disableComponent() {
|
|
1046
|
+
return this.client.post("ingame/disable");
|
|
1047
|
+
}
|
|
1048
|
+
/** `POST ingame/mock/{doMocking}` */
|
|
1049
|
+
async mockIngame(doMocking) {
|
|
1050
|
+
return this.client.post(`ingame/mock/${doMocking}`);
|
|
1051
|
+
}
|
|
1052
|
+
/** `GET ingame/mock` */
|
|
1053
|
+
async getMockingStatus() {
|
|
1054
|
+
return this.client.get("ingame/mock");
|
|
1055
|
+
}
|
|
1056
|
+
/** `GET ingame/frontend` */
|
|
1057
|
+
async getFrontendUrl() {
|
|
1058
|
+
return this.client.get("ingame/frontend");
|
|
1059
|
+
}
|
|
1060
|
+
/** `GET ingame/showing` */
|
|
1061
|
+
async getCurrentCommonSerializationOptions() {
|
|
1062
|
+
return this.client.get("ingame/showing");
|
|
1063
|
+
}
|
|
1064
|
+
/** `POST ingame/showing` */
|
|
1065
|
+
async setCurrentCommonSerializationOptions(data) {
|
|
1066
|
+
return this.client.post("ingame/showing", data);
|
|
1067
|
+
}
|
|
1068
|
+
/** `GET ingame/showing/{socketid}` */
|
|
1069
|
+
async getCurrentFrontendSerializationOptions(socketid) {
|
|
1070
|
+
return this.client.get(`ingame/showing/${socketid}`);
|
|
1071
|
+
}
|
|
1072
|
+
/** `POST ingame/showing/{socketid}` */
|
|
1073
|
+
async setCurrentFrontendSerializationOptions(socketid, data) {
|
|
1074
|
+
return this.client.post(`ingame/showing/${socketid}`, data);
|
|
1075
|
+
}
|
|
1076
|
+
/** `GET ingame/stage/{stageSide}/{playerSlot}/networkId` */
|
|
1077
|
+
async getPlayerPUUIDInSlot(stageSide, playerSlot) {
|
|
1078
|
+
return this.client.get(`ingame/stage/${stageSide}/${playerSlot}/networkId`);
|
|
1079
|
+
}
|
|
1080
|
+
/** `GET ingame/stage/{stageSide}/ingameteamid` */
|
|
1081
|
+
async getIngameTeamOnStageSide(stageSide) {
|
|
1082
|
+
return this.client.get(`ingame/stage/${stageSide}/ingameteamid`);
|
|
1083
|
+
}
|
|
1084
|
+
/** `GET ingame/state/activeOverlays` */
|
|
1085
|
+
async getActiveOverlays() {
|
|
1086
|
+
return this.client.get("ingame/state/activeOverlays");
|
|
1087
|
+
}
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
// src/api/RestApi.ts
|
|
1091
|
+
var RestApi = class {
|
|
1092
|
+
constructor(baseUrl) {
|
|
1093
|
+
this.client = new ApiClient(baseUrl);
|
|
1094
|
+
this.ingame = new IngameApi(this.client);
|
|
1095
|
+
this.game = new GameApi(this.client);
|
|
1096
|
+
this.match = new MatchApi(this.client);
|
|
1097
|
+
this.season = new SeasonApi(this.client);
|
|
1098
|
+
this.preGame = new PreGameApi(this.client);
|
|
1099
|
+
this.gameState = new GameStateApi(this.client);
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Update the base URL for all API modules (e.g. after changing host/port).
|
|
1103
|
+
*/
|
|
1104
|
+
updateBaseUrl(baseUrl) {
|
|
1105
|
+
this.client.updateBaseUrl(baseUrl);
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Get direct access to the underlying HTTP client for custom requests.
|
|
1109
|
+
*/
|
|
1110
|
+
getHttpClient() {
|
|
1111
|
+
return this.client;
|
|
1112
|
+
}
|
|
1113
|
+
};
|
|
1114
|
+
|
|
401
1115
|
// src/LeagueBroadcastClient.ts
|
|
402
1116
|
var LeagueBroadcastClient = class {
|
|
403
1117
|
constructor(config) {
|
|
404
1118
|
this.gameState = 0 /* OutOfGame */;
|
|
405
|
-
this.
|
|
406
|
-
|
|
1119
|
+
this._isTestingEnvironment = false;
|
|
1120
|
+
this.champSelectWasActive = false;
|
|
1121
|
+
// -- In-game event handlers -------------------------------------------------
|
|
407
1122
|
this.stateUpdateHandlers = /* @__PURE__ */ new Set();
|
|
408
1123
|
this.gameStatusHandlers = /* @__PURE__ */ new Set();
|
|
409
|
-
this.
|
|
1124
|
+
this.ingameEventHandlers = {};
|
|
1125
|
+
// -- Pre-game event handlers ------------------------------------------------
|
|
1126
|
+
this.champSelectUpdateHandlers = /* @__PURE__ */ new Set();
|
|
1127
|
+
this.champSelectEventHandlers = {};
|
|
410
1128
|
this.config = {
|
|
411
1129
|
host: config.host,
|
|
412
1130
|
port: config.port ?? 58869,
|
|
413
|
-
|
|
1131
|
+
ingameWsRoute: config.ingameWsRoute ?? "/ws/in",
|
|
1132
|
+
preGameWsRoute: config.preGameWsRoute ?? "/ws/pre",
|
|
414
1133
|
apiRoute: config.apiRoute ?? "/api",
|
|
415
1134
|
cacheRoute: config.cacheRoute ?? "/cache",
|
|
416
1135
|
useHttps: config.useHttps ?? false,
|
|
417
1136
|
autoConnect: config.autoConnect ?? true
|
|
418
1137
|
};
|
|
419
|
-
this.
|
|
1138
|
+
const httpProtocol = this.config.useHttps ? "https" : "http";
|
|
1139
|
+
const apiBaseUrl = `${httpProtocol}://${this.config.host}:${this.config.port}${this.config.apiRoute}`;
|
|
1140
|
+
this.api = new RestApi(apiBaseUrl);
|
|
1141
|
+
this.ingameWs = new WebSocketManager();
|
|
420
1142
|
this.gameData = new ingameFrontendData();
|
|
421
|
-
this.
|
|
422
|
-
this.
|
|
1143
|
+
this.ingameStore = new GameStateStore(this.gameData, this.gameState);
|
|
1144
|
+
this.setupIngameMessageHandler();
|
|
1145
|
+
this.preGameWs = new WebSocketManager();
|
|
1146
|
+
this.champSelectData = new champSelectStateData();
|
|
1147
|
+
this.preGameStore = new ChampSelectStateStore(this.champSelectData);
|
|
1148
|
+
this.setupPreGameMessageHandler();
|
|
423
1149
|
if (this.config.autoConnect) {
|
|
424
1150
|
this.connect();
|
|
425
1151
|
}
|
|
426
1152
|
}
|
|
1153
|
+
// ===========================================================================
|
|
1154
|
+
// Connection management
|
|
1155
|
+
// ===========================================================================
|
|
427
1156
|
/**
|
|
428
|
-
* Connect to
|
|
1157
|
+
* Connect to both in-game and pre-game WebSocket endpoints.
|
|
1158
|
+
*
|
|
1159
|
+
* Both connections are attempted in parallel. If either fails the returned
|
|
1160
|
+
* promise rejects, but the other connection may still succeed.
|
|
429
1161
|
*/
|
|
430
1162
|
async connect() {
|
|
431
1163
|
const protocol = this.config.useHttps ? "wss" : "ws";
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
1164
|
+
const base = `${protocol}://${this.config.host}:${this.config.port}`;
|
|
1165
|
+
const ingameUrl = `${base}${this.config.ingameWsRoute}`;
|
|
1166
|
+
const preGameUrl = `${base}${this.config.preGameWsRoute}`;
|
|
1167
|
+
const results = await Promise.allSettled([
|
|
1168
|
+
this.ingameWs.connect(ingameUrl),
|
|
1169
|
+
this.preGameWs.connect(preGameUrl)
|
|
1170
|
+
]);
|
|
1171
|
+
const failures = results.filter((r) => r.status === "rejected");
|
|
1172
|
+
if (failures.length > 0) {
|
|
1173
|
+
const reasons = failures.map(
|
|
1174
|
+
(r) => r.reason
|
|
1175
|
+
);
|
|
1176
|
+
console.error(
|
|
1177
|
+
"[LeagueBroadcastClient] One or more connections failed:",
|
|
1178
|
+
reasons
|
|
1179
|
+
);
|
|
1180
|
+
throw reasons[0];
|
|
438
1181
|
}
|
|
439
1182
|
}
|
|
440
1183
|
/**
|
|
441
|
-
* Disconnect from
|
|
1184
|
+
* Disconnect from both WebSocket endpoints.
|
|
442
1185
|
*/
|
|
443
1186
|
disconnect() {
|
|
444
|
-
this.
|
|
1187
|
+
this.ingameWs.disconnect();
|
|
1188
|
+
this.preGameWs.disconnect();
|
|
445
1189
|
}
|
|
446
1190
|
/**
|
|
447
|
-
*
|
|
1191
|
+
* Whether the in-game WebSocket is connected.
|
|
448
1192
|
*/
|
|
449
|
-
|
|
450
|
-
return this.
|
|
1193
|
+
isIngameConnected() {
|
|
1194
|
+
return this.ingameWs.isConnected();
|
|
451
1195
|
}
|
|
452
1196
|
/**
|
|
453
|
-
*
|
|
1197
|
+
* Whether the pre-game WebSocket is connected.
|
|
454
1198
|
*/
|
|
455
|
-
|
|
1199
|
+
isPreGameConnected() {
|
|
1200
|
+
return this.preGameWs.isConnected();
|
|
1201
|
+
}
|
|
1202
|
+
// ===========================================================================
|
|
1203
|
+
// In-game data access
|
|
1204
|
+
// ===========================================================================
|
|
1205
|
+
/** Get the current in-game data. */
|
|
1206
|
+
getIngameData() {
|
|
456
1207
|
return this.gameData;
|
|
457
1208
|
}
|
|
458
|
-
/**
|
|
459
|
-
|
|
460
|
-
*/
|
|
461
|
-
getGameState() {
|
|
1209
|
+
/** Get the current game state. */
|
|
1210
|
+
getIngameState() {
|
|
462
1211
|
return this.gameState;
|
|
463
1212
|
}
|
|
464
|
-
/**
|
|
465
|
-
* Check if in testing environment
|
|
466
|
-
*/
|
|
1213
|
+
/** Whether the backend is in a testing / replay environment. */
|
|
467
1214
|
isInTestingEnvironment() {
|
|
468
|
-
return this.
|
|
1215
|
+
return this._isTestingEnvironment;
|
|
469
1216
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
1217
|
+
// ===========================================================================
|
|
1218
|
+
// Pre-game data access
|
|
1219
|
+
// ===========================================================================
|
|
1220
|
+
/** Get the current champion-select state. */
|
|
1221
|
+
getChampSelectData() {
|
|
1222
|
+
return this.champSelectData;
|
|
1223
|
+
}
|
|
1224
|
+
/** Whether champion select is currently active. */
|
|
1225
|
+
isChampSelectActive() {
|
|
1226
|
+
return this.champSelectData.isActive;
|
|
1227
|
+
}
|
|
1228
|
+
// ===========================================================================
|
|
1229
|
+
// In-game event handlers
|
|
1230
|
+
// ===========================================================================
|
|
1231
|
+
/** Register a handler for in-game state updates. */
|
|
1232
|
+
onIngameStateUpdate(handler) {
|
|
474
1233
|
this.stateUpdateHandlers.add(handler);
|
|
475
1234
|
return () => this.stateUpdateHandlers.delete(handler);
|
|
476
1235
|
}
|
|
477
|
-
/**
|
|
478
|
-
|
|
479
|
-
*/
|
|
480
|
-
onGameStatusChange(handler) {
|
|
1236
|
+
/** Register a handler for in-game status changes (running, paused, out of game). */
|
|
1237
|
+
onIngameStatusChange(handler) {
|
|
481
1238
|
this.gameStatusHandlers.add(handler);
|
|
482
1239
|
return () => this.gameStatusHandlers.delete(handler);
|
|
483
1240
|
}
|
|
484
|
-
/**
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
onGameEvents(handlers) {
|
|
488
|
-
this.eventHandlers = { ...this.eventHandlers, ...handlers };
|
|
1241
|
+
/** Register handlers for in-game events (kills, objectives, etc.). */
|
|
1242
|
+
onIngameEvents(handlers) {
|
|
1243
|
+
this.ingameEventHandlers = { ...this.ingameEventHandlers, ...handlers };
|
|
489
1244
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
1245
|
+
// ===========================================================================
|
|
1246
|
+
// Pre-game event handlers
|
|
1247
|
+
// ===========================================================================
|
|
1248
|
+
/** Register a handler for champ-select state updates. */
|
|
1249
|
+
onChampSelectUpdate(handler) {
|
|
1250
|
+
this.champSelectUpdateHandlers.add(handler);
|
|
1251
|
+
return () => this.champSelectUpdateHandlers.delete(handler);
|
|
495
1252
|
}
|
|
496
|
-
/**
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
1253
|
+
/** Register handlers for champ-select lifecycle and action events. */
|
|
1254
|
+
onChampSelectEvents(handlers) {
|
|
1255
|
+
this.champSelectEventHandlers = {
|
|
1256
|
+
...this.champSelectEventHandlers,
|
|
1257
|
+
...handlers
|
|
1258
|
+
};
|
|
501
1259
|
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
1260
|
+
// ===========================================================================
|
|
1261
|
+
// Connection event handlers
|
|
1262
|
+
// ===========================================================================
|
|
1263
|
+
/** Register a handler for in-game connection. */
|
|
1264
|
+
onIngameConnect(handler) {
|
|
1265
|
+
return this.ingameWs.onConnect(handler);
|
|
507
1266
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
1267
|
+
/** Register a handler for in-game disconnection. */
|
|
1268
|
+
onIngameDisconnect(handler) {
|
|
1269
|
+
return this.ingameWs.onDisconnect(handler);
|
|
1270
|
+
}
|
|
1271
|
+
/** Register a handler for in-game connection errors. */
|
|
1272
|
+
onIngameError(handler) {
|
|
1273
|
+
return this.ingameWs.onError(handler);
|
|
1274
|
+
}
|
|
1275
|
+
/** Register a handler for pre-game connection. */
|
|
1276
|
+
onPreGameConnect(handler) {
|
|
1277
|
+
return this.preGameWs.onConnect(handler);
|
|
1278
|
+
}
|
|
1279
|
+
/** Register a handler for pre-game disconnection. */
|
|
1280
|
+
onPreGameDisconnect(handler) {
|
|
1281
|
+
return this.preGameWs.onDisconnect(handler);
|
|
1282
|
+
}
|
|
1283
|
+
/** Register a handler for pre-game connection errors. */
|
|
1284
|
+
onPreGameError(handler) {
|
|
1285
|
+
return this.preGameWs.onError(handler);
|
|
1286
|
+
}
|
|
1287
|
+
// ===========================================================================
|
|
1288
|
+
// Reactive API — in-game (convenience wrappers around this.store)
|
|
1289
|
+
// ===========================================================================
|
|
511
1290
|
/**
|
|
512
|
-
* Create a subscribable slice of game state.
|
|
1291
|
+
* Create a subscribable slice of **in-game** state.
|
|
513
1292
|
* The slice only notifies listeners when the selected value actually changes.
|
|
514
1293
|
*
|
|
515
1294
|
* Works directly with React 18+ `useSyncExternalStore`:
|
|
516
1295
|
* ```tsx
|
|
517
|
-
* const kills = client.
|
|
1296
|
+
* const kills = client.selectIngame(s => s.gameData.scoreboard?.teams[0]?.kills);
|
|
518
1297
|
* function Kills() {
|
|
519
1298
|
* const value = useSyncExternalStore(kills.subscribe, kills.getSnapshot);
|
|
520
1299
|
* return <span>{value}</span>;
|
|
521
1300
|
* }
|
|
522
1301
|
* ```
|
|
523
1302
|
*/
|
|
524
|
-
|
|
525
|
-
return this.
|
|
1303
|
+
selectIngame(selector, equalityFn) {
|
|
1304
|
+
return this.ingameStore.select(selector, equalityFn);
|
|
526
1305
|
}
|
|
527
1306
|
/**
|
|
528
|
-
* Watch a derived value and invoke `callback` whenever it changes.
|
|
1307
|
+
* Watch a derived **in-game** value and invoke `callback` whenever it changes.
|
|
529
1308
|
* Returns an unsubscribe function.
|
|
530
1309
|
*
|
|
531
1310
|
* ```ts
|
|
532
|
-
* client.
|
|
1311
|
+
* client.watchIngame(
|
|
533
1312
|
* s => s.gameData.scoreboard?.teams[0]?.kills,
|
|
534
1313
|
* (kills, prev) => console.log(`Kills: ${prev} → ${kills}`),
|
|
535
1314
|
* );
|
|
536
1315
|
* ```
|
|
537
1316
|
*/
|
|
538
|
-
|
|
539
|
-
return this.
|
|
1317
|
+
watchIngame(selector, callback, equalityFn) {
|
|
1318
|
+
return this.ingameStore.watch(selector, callback, equalityFn);
|
|
540
1319
|
}
|
|
1320
|
+
// ===========================================================================
|
|
1321
|
+
// Reactive API — pre-game (convenience wrappers around this.preGameStore)
|
|
1322
|
+
// ===========================================================================
|
|
541
1323
|
/**
|
|
542
|
-
*
|
|
1324
|
+
* Create a subscribable slice of **pre-game** (champion select) state.
|
|
1325
|
+
*
|
|
1326
|
+
* ```tsx
|
|
1327
|
+
* const timer = client.selectChampSelect(s => s.champSelectData.timer);
|
|
1328
|
+
* function DraftTimer() {
|
|
1329
|
+
* const value = useSyncExternalStore(timer.subscribe, timer.getSnapshot);
|
|
1330
|
+
* return <span>{value?.timeRemaining}</span>;
|
|
1331
|
+
* }
|
|
1332
|
+
* ```
|
|
1333
|
+
*/
|
|
1334
|
+
selectChampSelect(selector, equalityFn) {
|
|
1335
|
+
return this.preGameStore.select(selector, equalityFn);
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Watch a derived **pre-game** value and invoke `callback` whenever it
|
|
1339
|
+
* changes. Returns an unsubscribe function.
|
|
1340
|
+
*
|
|
1341
|
+
* ```ts
|
|
1342
|
+
* client.watchChampSelect(
|
|
1343
|
+
* s => s.champSelectData.timer.timeRemaining,
|
|
1344
|
+
* (remaining, prev) => console.log(`Time: ${prev} → ${remaining}`),
|
|
1345
|
+
* );
|
|
1346
|
+
* ```
|
|
543
1347
|
*/
|
|
1348
|
+
watchChampSelect(selector, callback, equalityFn) {
|
|
1349
|
+
return this.preGameStore.watch(selector, callback, equalityFn);
|
|
1350
|
+
}
|
|
1351
|
+
// ===========================================================================
|
|
1352
|
+
// URLs
|
|
1353
|
+
// ===========================================================================
|
|
1354
|
+
/** Get the base HTTP URL for API requests. */
|
|
544
1355
|
getApiUrl() {
|
|
545
1356
|
const protocol = this.config.useHttps ? "https" : "http";
|
|
546
1357
|
return `${protocol}://${this.config.host}:${this.config.port}${this.config.apiRoute}`;
|
|
547
1358
|
}
|
|
548
|
-
/**
|
|
549
|
-
* Get the base URL for cache requests
|
|
550
|
-
*/
|
|
1359
|
+
/** Get the base URL for cache requests (optionally resolve a path). */
|
|
551
1360
|
getCacheUrl(path) {
|
|
552
1361
|
const protocol = this.config.useHttps ? "https" : "http";
|
|
553
1362
|
const baseUrl = `${protocol}://${this.config.host}:${this.config.port}${this.config.cacheRoute}`;
|
|
@@ -569,11 +1378,11 @@ var LeagueBroadcastClient = class {
|
|
|
569
1378
|
}
|
|
570
1379
|
return `${baseUrl}/${cleanPath}`;
|
|
571
1380
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
this.
|
|
1381
|
+
// ===========================================================================
|
|
1382
|
+
// Private — in-game message handling
|
|
1383
|
+
// ===========================================================================
|
|
1384
|
+
setupIngameMessageHandler() {
|
|
1385
|
+
this.ingameWs.onMessage((messageData) => {
|
|
577
1386
|
switch (messageData.type) {
|
|
578
1387
|
case "ingame-state-update":
|
|
579
1388
|
this.handleStateUpdate(messageData.state, messageData.events);
|
|
@@ -587,84 +1396,210 @@ var LeagueBroadcastClient = class {
|
|
|
587
1396
|
}
|
|
588
1397
|
});
|
|
589
1398
|
}
|
|
590
|
-
/**
|
|
591
|
-
* Handle state update from backend
|
|
592
|
-
*/
|
|
593
1399
|
handleStateUpdate(state, events) {
|
|
594
|
-
const nextData =
|
|
1400
|
+
const nextData = {
|
|
1401
|
+
gameTime: 0,
|
|
1402
|
+
playbackSpeed: 0,
|
|
1403
|
+
gameVersion: "",
|
|
1404
|
+
gameStatus: 0 /* OutOfGame */,
|
|
1405
|
+
...state
|
|
1406
|
+
};
|
|
595
1407
|
this.gameData = structuralShare(this.gameData, nextData);
|
|
596
1408
|
if (!state.gameTime || state.gameTime === 0) {
|
|
597
1409
|
this.handleGameStatusUpdate(0 /* OutOfGame */, false);
|
|
598
1410
|
}
|
|
599
|
-
this.
|
|
1411
|
+
this.ingameStore._setGameData(this.gameData);
|
|
600
1412
|
this.stateUpdateHandlers.forEach((handler) => handler(this.gameData));
|
|
601
1413
|
this.handleGameEvents(events);
|
|
602
1414
|
}
|
|
603
|
-
/**
|
|
604
|
-
* Handle game status update
|
|
605
|
-
*/
|
|
606
1415
|
handleGameStatusUpdate(gameStatus, isTestingEnvironment = false) {
|
|
607
|
-
this.
|
|
1416
|
+
this._isTestingEnvironment = isTestingEnvironment;
|
|
608
1417
|
if (gameStatus === 0 /* OutOfGame */ && this.gameState !== 0 /* OutOfGame */) {
|
|
609
1418
|
this.endGame();
|
|
610
1419
|
return;
|
|
611
1420
|
}
|
|
612
1421
|
this.gameState = gameStatus;
|
|
613
|
-
this.
|
|
1422
|
+
this.ingameStore._setGameState(gameStatus);
|
|
614
1423
|
this.gameStatusHandlers.forEach(
|
|
615
1424
|
(handler) => handler(gameStatus, isTestingEnvironment)
|
|
616
1425
|
);
|
|
617
1426
|
}
|
|
618
|
-
/**
|
|
619
|
-
* Handle game events
|
|
620
|
-
*/
|
|
621
1427
|
handleGameEvents(events) {
|
|
622
|
-
if (!events)
|
|
623
|
-
|
|
624
|
-
}
|
|
625
|
-
if (events.player && this.eventHandlers.onPlayerEvent) {
|
|
1428
|
+
if (!events) return;
|
|
1429
|
+
if (events.player && this.ingameEventHandlers.onPlayerEvent) {
|
|
626
1430
|
events.player.forEach(
|
|
627
|
-
(event) => this.
|
|
1431
|
+
(event) => this.ingameEventHandlers.onPlayerEvent(event)
|
|
628
1432
|
);
|
|
629
1433
|
}
|
|
630
|
-
if (events.team && this.
|
|
631
|
-
events.team.forEach(
|
|
1434
|
+
if (events.team && this.ingameEventHandlers.onTeamEvent) {
|
|
1435
|
+
events.team.forEach(
|
|
1436
|
+
(event) => this.ingameEventHandlers.onTeamEvent(event)
|
|
1437
|
+
);
|
|
632
1438
|
}
|
|
633
|
-
if (events.objective && this.
|
|
1439
|
+
if (events.objective && this.ingameEventHandlers.onObjectiveEvent) {
|
|
634
1440
|
events.objective.forEach(
|
|
635
|
-
(event) => this.
|
|
1441
|
+
(event) => this.ingameEventHandlers.onObjectiveEvent(event)
|
|
636
1442
|
);
|
|
637
1443
|
}
|
|
638
|
-
if (events.firstTower !== void 0 && this.
|
|
639
|
-
this.
|
|
1444
|
+
if (events.firstTower !== void 0 && this.ingameEventHandlers.onFirstTowerEvent) {
|
|
1445
|
+
this.ingameEventHandlers.onFirstTowerEvent(events.firstTower);
|
|
640
1446
|
}
|
|
641
|
-
if (events.announcements && this.
|
|
1447
|
+
if (events.announcements && this.ingameEventHandlers.onAnnouncementEvent) {
|
|
642
1448
|
events.announcements.forEach(
|
|
643
|
-
(event) => this.
|
|
1449
|
+
(event) => this.ingameEventHandlers.onAnnouncementEvent(event)
|
|
644
1450
|
);
|
|
645
1451
|
}
|
|
646
|
-
if (events.killFeed && this.
|
|
1452
|
+
if (events.killFeed && this.ingameEventHandlers.onKillFeedEvent) {
|
|
647
1453
|
events.killFeed.forEach(
|
|
648
|
-
(event) => this.
|
|
1454
|
+
(event) => this.ingameEventHandlers.onKillFeedEvent(event)
|
|
649
1455
|
);
|
|
650
1456
|
}
|
|
651
1457
|
}
|
|
652
|
-
/**
|
|
653
|
-
* End the game and reset state
|
|
654
|
-
*/
|
|
655
1458
|
endGame() {
|
|
656
1459
|
console.log("[LeagueBroadcastClient] Game ended, resetting data");
|
|
657
1460
|
this.gameData = new ingameFrontendData();
|
|
658
1461
|
this.gameState = 0 /* OutOfGame */;
|
|
659
|
-
this.
|
|
660
|
-
this.
|
|
1462
|
+
this._isTestingEnvironment = false;
|
|
1463
|
+
this.ingameStore._reset(this.gameData, 0 /* OutOfGame */);
|
|
661
1464
|
this.gameStatusHandlers.forEach(
|
|
662
1465
|
(handler) => handler(0 /* OutOfGame */, false)
|
|
663
1466
|
);
|
|
664
1467
|
this.stateUpdateHandlers.forEach((handler) => handler(this.gameData));
|
|
665
1468
|
}
|
|
1469
|
+
// ===========================================================================
|
|
1470
|
+
// Private — pre-game message handling
|
|
1471
|
+
// ===========================================================================
|
|
1472
|
+
setupPreGameMessageHandler() {
|
|
1473
|
+
this.preGameWs.onMessage((messageData) => {
|
|
1474
|
+
switch (messageData.type) {
|
|
1475
|
+
case "champion-select-state-update":
|
|
1476
|
+
this.handleChampSelectStateUpdate(messageData.state);
|
|
1477
|
+
break;
|
|
1478
|
+
case "champion-select-action":
|
|
1479
|
+
this.handleChampSelectAction(messageData.action);
|
|
1480
|
+
break;
|
|
1481
|
+
case "frontend-route-update":
|
|
1482
|
+
this.handleRouteUpdate(messageData.uri);
|
|
1483
|
+
break;
|
|
1484
|
+
}
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1487
|
+
handleChampSelectStateUpdate(state) {
|
|
1488
|
+
const nextData = {
|
|
1489
|
+
isActive: false,
|
|
1490
|
+
isConnected: false,
|
|
1491
|
+
isTestingEnvironment: false,
|
|
1492
|
+
blueTeam: {},
|
|
1493
|
+
redTeam: {},
|
|
1494
|
+
metaData: {},
|
|
1495
|
+
timer: {},
|
|
1496
|
+
...state
|
|
1497
|
+
};
|
|
1498
|
+
this.champSelectData = structuralShare(this.champSelectData, nextData);
|
|
1499
|
+
if (nextData.isActive && !this.champSelectWasActive) {
|
|
1500
|
+
this.champSelectWasActive = true;
|
|
1501
|
+
this.champSelectEventHandlers.onChampSelectStart?.();
|
|
1502
|
+
} else if (!nextData.isActive && this.champSelectWasActive) {
|
|
1503
|
+
this.champSelectWasActive = false;
|
|
1504
|
+
this.endChampSelect();
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
this.preGameStore._setChampSelectData(this.champSelectData);
|
|
1508
|
+
this.champSelectUpdateHandlers.forEach(
|
|
1509
|
+
(handler) => handler(this.champSelectData)
|
|
1510
|
+
);
|
|
1511
|
+
}
|
|
1512
|
+
handleChampSelectAction(action) {
|
|
1513
|
+
this.champSelectEventHandlers.onAction?.(action);
|
|
1514
|
+
}
|
|
1515
|
+
handleRouteUpdate(uri) {
|
|
1516
|
+
this.champSelectEventHandlers.onRouteUpdate?.(uri);
|
|
1517
|
+
}
|
|
1518
|
+
endChampSelect() {
|
|
1519
|
+
console.log("[LeagueBroadcastClient] Champ select ended, resetting data");
|
|
1520
|
+
this.champSelectData = new champSelectStateData();
|
|
1521
|
+
this.preGameStore._reset(this.champSelectData);
|
|
1522
|
+
this.champSelectEventHandlers.onChampSelectEnd?.();
|
|
1523
|
+
this.champSelectUpdateHandlers.forEach(
|
|
1524
|
+
(handler) => handler(this.champSelectData)
|
|
1525
|
+
);
|
|
1526
|
+
}
|
|
666
1527
|
};
|
|
667
1528
|
|
|
668
|
-
|
|
1529
|
+
// types/pregame/pickbanphase.ts
|
|
1530
|
+
var PickBanPhase = /* @__PURE__ */ ((PickBanPhase2) => {
|
|
1531
|
+
PickBanPhase2[PickBanPhase2["BEGIN"] = 0] = "BEGIN";
|
|
1532
|
+
PickBanPhase2[PickBanPhase2["BAN1"] = 1] = "BAN1";
|
|
1533
|
+
PickBanPhase2[PickBanPhase2["BAN2"] = 2] = "BAN2";
|
|
1534
|
+
PickBanPhase2[PickBanPhase2["PICK1"] = 3] = "PICK1";
|
|
1535
|
+
PickBanPhase2[PickBanPhase2["PICK2"] = 4] = "PICK2";
|
|
1536
|
+
PickBanPhase2[PickBanPhase2["END"] = 5] = "END";
|
|
1537
|
+
PickBanPhase2[PickBanPhase2["WAIT"] = 6] = "WAIT";
|
|
1538
|
+
return PickBanPhase2;
|
|
1539
|
+
})(PickBanPhase || {});
|
|
1540
|
+
|
|
1541
|
+
// types/pregame/actiontype.ts
|
|
1542
|
+
var ActionType = /* @__PURE__ */ ((ActionType2) => {
|
|
1543
|
+
ActionType2[ActionType2["TEN_BANS_REVEAL"] = 0] = "TEN_BANS_REVEAL";
|
|
1544
|
+
ActionType2[ActionType2["PHASE_TRANSITION"] = 1] = "PHASE_TRANSITION";
|
|
1545
|
+
ActionType2[ActionType2["PICK"] = 2] = "PICK";
|
|
1546
|
+
ActionType2[ActionType2["BAN"] = 3] = "BAN";
|
|
1547
|
+
return ActionType2;
|
|
1548
|
+
})(ActionType || {});
|
|
1549
|
+
|
|
1550
|
+
// types/pregame/actionsubtype.ts
|
|
1551
|
+
var ActionSubType = /* @__PURE__ */ ((ActionSubType2) => {
|
|
1552
|
+
ActionSubType2[ActionSubType2["START"] = 0] = "START";
|
|
1553
|
+
ActionSubType2[ActionSubType2["HOVER"] = 1] = "HOVER";
|
|
1554
|
+
ActionSubType2[ActionSubType2["LOCK"] = 2] = "LOCK";
|
|
1555
|
+
return ActionSubType2;
|
|
1556
|
+
})(ActionSubType || {});
|
|
1557
|
+
|
|
1558
|
+
// types/pregame/timelineactiontype.ts
|
|
1559
|
+
var TimeLineActionType = /* @__PURE__ */ ((TimeLineActionType2) => {
|
|
1560
|
+
TimeLineActionType2[TimeLineActionType2["HoverPick"] = 0] = "HoverPick";
|
|
1561
|
+
TimeLineActionType2[TimeLineActionType2["Pick"] = 1] = "Pick";
|
|
1562
|
+
TimeLineActionType2[TimeLineActionType2["Ban"] = 2] = "Ban";
|
|
1563
|
+
return TimeLineActionType2;
|
|
1564
|
+
})(TimeLineActionType || {});
|
|
1565
|
+
|
|
1566
|
+
// types/shared/bestoftype.ts
|
|
1567
|
+
var BestOfType = /* @__PURE__ */ ((BestOfType2) => {
|
|
1568
|
+
BestOfType2[BestOfType2["BestOf1"] = 1] = "BestOf1";
|
|
1569
|
+
BestOfType2[BestOfType2["BestOf2"] = 2] = "BestOf2";
|
|
1570
|
+
BestOfType2[BestOfType2["BestOf3"] = 3] = "BestOf3";
|
|
1571
|
+
BestOfType2[BestOfType2["BestOf5"] = 5] = "BestOf5";
|
|
1572
|
+
BestOfType2[BestOfType2["BestOf7"] = 7] = "BestOf7";
|
|
1573
|
+
return BestOfType2;
|
|
1574
|
+
})(BestOfType || {});
|
|
1575
|
+
|
|
1576
|
+
// types/shared/matchruleset.ts
|
|
1577
|
+
var MatchRuleSet = /* @__PURE__ */ ((MatchRuleSet2) => {
|
|
1578
|
+
MatchRuleSet2[MatchRuleSet2["Standard"] = 0] = "Standard";
|
|
1579
|
+
MatchRuleSet2[MatchRuleSet2["PartialFearless"] = 1] = "PartialFearless";
|
|
1580
|
+
MatchRuleSet2[MatchRuleSet2["Fearless"] = 2] = "Fearless";
|
|
1581
|
+
return MatchRuleSet2;
|
|
1582
|
+
})(MatchRuleSet || {});
|
|
1583
|
+
|
|
1584
|
+
// src/util/ingameScoreboardBottomPlayerDataUtils.ts
|
|
1585
|
+
function getSortedInventory(playerData) {
|
|
1586
|
+
if (!playerData.items) return Array(6).fill({ id: 0 });
|
|
1587
|
+
const items = playerData.items?.filter((item) => item.slot < 6) ?? [];
|
|
1588
|
+
const regularItems = items.sort(
|
|
1589
|
+
(a, b) => (a?.cost ?? 0) - (b?.cost ?? 0)
|
|
1590
|
+
);
|
|
1591
|
+
while (regularItems.length < 6) {
|
|
1592
|
+
regularItems.unshift(void 0);
|
|
1593
|
+
}
|
|
1594
|
+
return regularItems ?? [];
|
|
1595
|
+
}
|
|
1596
|
+
function getTrinket(playerData) {
|
|
1597
|
+
return playerData.items?.find((item) => item.slot === 6);
|
|
1598
|
+
}
|
|
1599
|
+
function getRoleQuest(playerData) {
|
|
1600
|
+
return playerData.items?.find((item) => item.slot === 8);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
export { ActionSubType, ActionType, ApiClient, ApiError, BestOfType, ChampSelectStateStore, GameApi, GameState, GameStateApi, GameStateStore, IngameApi, LeagueBroadcastClient, MatchApi, MatchRuleSet, PickBanPhase, PreGameApi, RestApi, SeasonApi, TimeLineActionType, WebSocketManager, getRoleQuest, getSortedInventory, getTrinket, shallowEqual };
|
|
669
1604
|
//# sourceMappingURL=index.js.map
|
|
670
1605
|
//# sourceMappingURL=index.js.map
|