@bluebottle_gg/league-broadcast-client 0.1.0 → 0.2.1

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