halo-infinite-api 4.0.6 → 5.0.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.
Files changed (46) hide show
  1. package/dist/authentication/xbox-authentication-client.d.ts +3 -2
  2. package/dist/authentication/xbox-authentication-client.js +8 -7
  3. package/dist/authentication/xbox-authentication-client.js.map +1 -1
  4. package/dist/core/halo-infinite-client.d.ts +2 -1
  5. package/dist/core/halo-infinite-client.js +5 -2
  6. package/dist/core/halo-infinite-client.js.map +1 -1
  7. package/dist/core/token-providers/auto-token-provider.d.ts +13 -0
  8. package/dist/core/token-providers/auto-token-provider.js +34 -0
  9. package/dist/core/token-providers/auto-token-provider.js.map +1 -0
  10. package/dist/core/token-providers/spartan-token-providers/auto-xsts-spartan-token-provider.d.ts +11 -0
  11. package/dist/core/token-providers/spartan-token-providers/auto-xsts-spartan-token-provider.js +29 -0
  12. package/dist/core/token-providers/spartan-token-providers/auto-xsts-spartan-token-provider.js.map +1 -0
  13. package/dist/core/token-providers/spartan-token-providers/index.d.ts +3 -0
  14. package/dist/core/token-providers/spartan-token-providers/index.js +2 -0
  15. package/dist/core/token-providers/spartan-token-providers/index.js.map +1 -0
  16. package/dist/core/token-providers/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.d.ts +12 -0
  17. package/dist/core/token-providers/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.js +25 -0
  18. package/dist/core/token-providers/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.js.map +1 -0
  19. package/dist/core/token-providers/xbox-token-provider.d.ts +3 -0
  20. package/dist/core/token-providers/xbox-token-provider.js +2 -0
  21. package/dist/core/token-providers/xbox-token-provider.js.map +1 -0
  22. package/dist/core/xbox-client.d.ts +13 -0
  23. package/dist/core/xbox-client.js +28 -0
  24. package/dist/core/xbox-client.js.map +1 -0
  25. package/dist/index.d.ts +4 -3
  26. package/dist/index.js +3 -2
  27. package/dist/index.js.map +1 -1
  28. package/dist/models/halo-infinite/game-variant-category.d.ts +3 -1
  29. package/dist/models/halo-infinite/game-variant-category.js +2 -0
  30. package/dist/models/halo-infinite/game-variant-category.js.map +1 -1
  31. package/dist/models/halo-infinite/stats.d.ts +46 -4
  32. package/dist/util/keyed-expiry-token-cache.d.ts +13 -0
  33. package/dist/util/keyed-expiry-token-cache.js +74 -0
  34. package/dist/util/keyed-expiry-token-cache.js.map +1 -0
  35. package/package.json +1 -1
  36. package/src/authentication/xbox-authentication-client.ts +18 -12
  37. package/src/core/halo-infinite-client.ts +15 -3
  38. package/src/core/{spartan-token-providers/auto-xsts-spartan-token-provider.ts → token-providers/auto-token-provider.ts} +15 -3
  39. package/src/core/{spartan-token-providers → token-providers/spartan-token-providers}/static-xsts-ticket-token-spartan-token-provider.ts +3 -3
  40. package/src/core/token-providers/xbox-token-provider.ts +3 -0
  41. package/src/core/xbox-client.ts +48 -0
  42. package/src/index.ts +7 -3
  43. package/src/models/halo-infinite/game-variant-category.ts +2 -0
  44. package/src/models/halo-infinite/stats.ts +51 -4
  45. package/src/util/keyed-expiry-token-cache.ts +90 -0
  46. /package/src/core/{spartan-token-providers → token-providers/spartan-token-providers}/index.ts +0 -0
@@ -1,5 +1,6 @@
1
1
  import { DateTime } from "luxon";
2
2
  import { TokenPersister } from "../core/token-persisters";
3
+ import { XboxTicket } from "../models/xbox-ticket";
3
4
  export declare enum RelyingParty {
4
5
  Xbox = "http://xboxlive.com",
5
6
  Halo = "https://prod.xsts.halowaypoint.com/"
@@ -15,7 +16,7 @@ export declare class XboxAuthenticationClient {
15
16
  private xstsTicketCache;
16
17
  private readonly httpClient;
17
18
  constructor(tokenPersister?: TokenPersister | undefined);
18
- getXstsTicket(getOauth2AccessToken: () => Promise<string>): Promise<{
19
+ getXstsTicket(getOauth2AccessToken: () => Promise<string>, relyingParty: RelyingParty): Promise<{
19
20
  expiresAt: DateTime;
20
21
  IssueInstant: string;
21
22
  NotAfter: string;
@@ -32,5 +33,5 @@ export declare class XboxAuthenticationClient {
32
33
  }];
33
34
  };
34
35
  }>;
35
- getXboxLiveV3Token: (userHash: string, userToken: string) => string;
36
+ getXboxLiveV3Token: (xboxTicket: XboxTicket) => string;
36
37
  }
@@ -1,5 +1,6 @@
1
1
  import axios from "axios";
2
2
  import { DateTime } from "luxon";
3
+ import { KeyedExpiryTokenCache } from "../util/keyed-expiry-token-cache";
3
4
  import { ExpiryTokenCache } from "../util/expiry-token-cache";
4
5
  export var RelyingParty;
5
6
  (function (RelyingParty) {
@@ -31,7 +32,7 @@ export class XboxAuthenticationClient {
31
32
  await this.tokenPersister?.save("xbox.userToken", result);
32
33
  return result;
33
34
  }, async () => (await this.tokenPersister?.load("xbox.userToken")) ?? null);
34
- xstsTicketCache = new ExpiryTokenCache(async (userToken, relyingParty) => {
35
+ xstsTicketCache = new KeyedExpiryTokenCache(async (relyingParty, userToken) => {
35
36
  const response = await this.httpClient.post("https://xsts.auth.xboxlive.com/xsts/authorize", {
36
37
  RelyingParty: relyingParty,
37
38
  TokenType: "JWT",
@@ -50,16 +51,16 @@ export class XboxAuthenticationClient {
50
51
  ...response.data,
51
52
  expiresAt: DateTime.fromISO(response.data.NotAfter),
52
53
  };
53
- await this.tokenPersister?.save("xbox.xstsTicket", result);
54
+ await this.tokenPersister?.save("xbox.xstsTicket." + relyingParty, result);
54
55
  return result;
55
- }, async () => (await this.tokenPersister?.load("xbox.xstsTicket")) ?? null);
56
+ }, async (relyingParty) => (await this.tokenPersister?.load("xbox.xstsTicket." + relyingParty)) ?? null);
56
57
  httpClient;
57
58
  constructor(tokenPersister) {
58
59
  this.tokenPersister = tokenPersister;
59
60
  this.httpClient = axios.create();
60
61
  }
61
- async getXstsTicket(getOauth2AccessToken) {
62
- let xstsTicket = await this.xstsTicketCache.getExistingToken();
62
+ async getXstsTicket(getOauth2AccessToken, relyingParty) {
63
+ let xstsTicket = await this.xstsTicketCache.getExistingToken(relyingParty);
63
64
  if (!xstsTicket) {
64
65
  let userToken = await this.userTokenCache.getExistingToken();
65
66
  if (!userToken) {
@@ -67,10 +68,10 @@ export class XboxAuthenticationClient {
67
68
  // worrying if it is expired.
68
69
  userToken = await this.userTokenCache.getToken(await getOauth2AccessToken());
69
70
  }
70
- xstsTicket = await this.xstsTicketCache.getToken(userToken.Token, RelyingParty.Halo);
71
+ xstsTicket = await this.xstsTicketCache.getToken(relyingParty, userToken.Token);
71
72
  }
72
73
  return xstsTicket;
73
74
  }
74
- getXboxLiveV3Token = (userHash, userToken) => `XBL3.0 x=${userHash};${userToken}`;
75
+ getXboxLiveV3Token = (xboxTicket) => `XBL3.0 x=${xboxTicket.DisplayClaims.xui[0].uhs};${xboxTicket.Token}`;
75
76
  }
76
77
  //# sourceMappingURL=xbox-authentication-client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"xbox-authentication-client.js","sourceRoot":"","sources":["../../src/authentication/xbox-authentication-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"xbox-authentication-client.js","sourceRoot":"","sources":["../../src/authentication/xbox-authentication-client.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,7 @@ import { Playlist } from "../models/halo-infinite/playlist";
8
8
  import { PlaylistCsrContainer } from "../models/halo-infinite/playlist-csr-container";
9
9
  import { ServiceRecord } from "../models/halo-infinite/service-record";
10
10
  import { UserInfo } from "../models/halo-infinite/user-info";
11
- import { SpartanTokenProvider } from "./spartan-token-providers";
11
+ import { SpartanTokenProvider } from "./token-providers/spartan-token-providers";
12
12
  interface ResultContainer<TValue> {
13
13
  Id: string;
14
14
  ResultCode: 0 | 1;
@@ -47,6 +47,7 @@ export declare class HaloInfiniteClient {
47
47
  */
48
48
  getPlaylist: (playlistId: string) => Promise<Playlist>;
49
49
  getPlayerMatches: (playerXuid: string, type?: MatchType, count?: number, start?: number) => Promise<PlayerMatchHistory[]>;
50
+ getPlayerServiceRecord(playerXuid: string, type?: MatchType): Promise<ServiceRecord>;
50
51
  getMatchStats: (matchId: string) => Promise<MatchStats<import("..").GameVariantCategory>>;
51
52
  getMatchSkill: (matchId: string, playerIds: string[]) => Promise<ResultContainer<MatchSkill<0>>[]>;
52
53
  /** Gets authoring metadata about a specific asset. */
@@ -9,7 +9,7 @@ const assetKindUrlMap = {
9
9
  [AssetKind.Playlist]: "Playlists",
10
10
  };
11
11
  function wrapPlayerId(playerId) {
12
- if (/^\w+(\d+)/) {
12
+ if (/^\w+\(\d+\)/.test(playerId)) {
13
13
  return playerId;
14
14
  }
15
15
  else {
@@ -92,8 +92,11 @@ export class HaloInfiniteClient {
92
92
  if (type !== MatchType.All) {
93
93
  params.type = type.toString();
94
94
  }
95
- return this.executePaginationRequest(count, start, params, `https://${HaloCoreEndpoints.StatsOrigin}.${HaloCoreEndpoints.ServiceDomain}/hi/players/xuid(${wrapPlayerId(playerXuid)})/matches`, "get");
95
+ return this.executePaginationRequest(count, start, params, `https://${HaloCoreEndpoints.StatsOrigin}.${HaloCoreEndpoints.ServiceDomain}/hi/players/${wrapPlayerId(playerXuid)}/matches`, "get");
96
96
  };
97
+ getPlayerServiceRecord(playerXuid, type = MatchType.All) {
98
+ return this.executeRequest(`https://${HaloCoreEndpoints.StatsOrigin}.${HaloCoreEndpoints.ServiceDomain}/hi/players/${wrapPlayerId(playerXuid)}/Matchmade/servicerecord`, "get");
99
+ }
97
100
  getMatchStats = (matchId) => this.executeRequest(`https://${HaloCoreEndpoints.StatsOrigin}.${HaloCoreEndpoints.ServiceDomain}/hi/matches/${matchId}/stats`, "get");
98
101
  getMatchSkill = async (matchId, playerIds) => {
99
102
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"halo-infinite-client.js","sourceRoot":"","sources":["../../src/core/halo-infinite-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"halo-infinite-client.js","sourceRoot":"","sources":["../../src/core/halo-infinite-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,YAAY,EAAU,MAAM,OAAO,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAMrE,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAG/D,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAM/D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AA0B1D,MAAM,eAAe,GAAG;IACtB,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM;IACvB,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,iBAAiB;IAC7C,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,WAAW;CAGlC,CAAC;AAEF,SAAS,YAAY,CAAC,QAAgB;IACpC,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;QAChC,OAAO,QAAQ,CAAC;KACjB;SAAM;QACL,cAAc;QACd,OAAO,QAAQ,QAAQ,GAAG,CAAC;KAC5B;AACH,CAAC;AAED,SAAS,cAAc,CAAC,QAAgB;IACtC,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9C,IAAI,KAAK,EAAE;QACT,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;KACjB;SAAM;QACL,OAAO,QAAQ,CAAC;KACjB;AACH,CAAC;AAED,MAAM,OAAO,kBAAkB;IACT;IAApB,YAAoB,oBAA0C;QAA1C,yBAAoB,GAApB,oBAAoB,CAAsB;IAAG,CAAC;IAE1D,KAAK,CAAC,cAAc,CAC1B,GAAW,EACX,MAAc,EACd,eAAe,GAAG,IAAI,EACtB,YAAY,GAAG,KAAK,EACpB,YAAoB,eAAe,CAAC,wBAAwB;QAE5D,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC;YAC/B,YAAY,EAAE,SAAS;YACvB,MAAM,EAAE,kBAAkB;SAC3B,CAAC,CAAC;QAEH,IAAI,eAAe,EAAE;YACnB,OAAO,CAAC,GAAG,CACT,6BAA6B,EAC7B,MAAM,IAAI,CAAC,oBAAoB,CAAC,eAAe,EAAE,CAClD,CAAC;SACH;QAED,IAAI,YAAY,EAAE;YAChB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;SAC9C;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAI;YACtC,GAAG;YACH,MAAM;YACN,OAAO;SACR,CAAC,CAAC;QAEH,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,qBAAqB,CACjC,GAAG,IAAsD;QAEzD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CAAsB,GAAG,IAAI,CAAC,CAAC;QAEvE,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;IAEO,KAAK,CAAC,wBAAwB,CACpC,KAAa,EACb,KAAa,EACb,eAAuC,EACvC,GAAG,IAAsD;QAEzD,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,CACtC,GAAG,GAAG,IAAI,IAAI,eAAe,CAAC;YAC5B,GAAG,eAAe;YAClB,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE;YACvB,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE;SACxB,CAAC,EAAE,EACJ,GAAG,IAAI,CACR,CAAC;QAEF,OAAO,MAAM,CAAC,OAAO,CAAC;IACxB,CAAC;IAED;;;OAGG;IACI,cAAc,GAAG,CAAC,UAAkB,EAAE,SAAmB,EAAE,EAAE,CAClE,IAAI,CAAC,qBAAqB,CACxB,WAAW,iBAAiB,CAAC,WAAW,IACtC,iBAAiB,CAAC,aACpB,gBAAgB,UAAU,iBAAiB,SAAS;SACjD,GAAG,CAAC,YAAY,CAAC;SACjB,IAAI,CAAC,GAAG,CAAC,EAAE,EACd,KAAK,CACN,CAAC;IAEJ;;OAEG;IACI,OAAO,GAAG,CAAC,QAAgB,EAAE,EAAE,CACpC,IAAI,CAAC,cAAc,CACjB,WAAW,iBAAiB,CAAC,OAAO,IAAI,iBAAiB,CAAC,aAAa,aAAa,QAAQ,GAAG,EAC/F,KAAK,CACN,CAAC;IAEJ;;OAEG;IACI,QAAQ,GAAG,CAAC,KAAe,EAAE,EAAE;QACpC,OAAO,IAAI,CAAC,cAAc,CACxB,WAAW,iBAAiB,CAAC,OAAO,IAClC,iBAAiB,CAAC,aACpB,gBAAgB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAC/D,KAAK,CACN,CAAC;IACJ,CAAC,CAAC;IAEF;;OAEG;IACI,oBAAoB,GAAG,CAAC,QAAgB,EAAE,EAAE,CACjD,IAAI,CAAC,cAAc,CACjB,WAAW,iBAAiB,CAAC,WAAW,IAAI,iBAAiB,CAAC,aAAa,eAAe,QAAQ,0BAA0B,EAC5H,KAAK,CACN,CAAC;IAEJ;;OAEG;IACI,WAAW,GAAG,CAAC,UAAkB,EAAE,EAAE,CAC1C,IAAI,CAAC,cAAc,CACjB,WAAW,iBAAiB,CAAC,aAAa,IAAI,iBAAiB,CAAC,aAAa,yCAAyC,UAAU,OAAO,EACvI,KAAK,CACN,CAAC;IAEG,gBAAgB,GAAG,CACxB,UAAkB,EAClB,OAAkB,SAAS,CAAC,GAAG,EAC/B,QAAgB,EAAE,EAClB,QAAgB,CAAC,EACjB,EAAE;QACF,IAAI,MAAM,GAA2B,EAAE,CAAC;QACxC,IAAI,IAAI,KAAK,SAAS,CAAC,GAAG,EAAE;YAC1B,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;SAC/B;QACD,OAAO,IAAI,CAAC,wBAAwB,CAClC,KAAK,EACL,KAAK,EACL,MAAM,EACN,WAAW,iBAAiB,CAAC,WAAW,IACtC,iBAAiB,CAAC,aACpB,eAAe,YAAY,CAAC,UAAU,CAAC,UAAU,EACjD,KAAK,CACN,CAAC;IACJ,CAAC,CAAC;IAEK,sBAAsB,CAC3B,UAAkB,EAClB,OAAkB,SAAS,CAAC,GAAG;QAE/B,OAAO,IAAI,CAAC,cAAc,CACxB,WAAW,iBAAiB,CAAC,WAAW,IACtC,iBAAiB,CAAC,aACpB,eAAe,YAAY,CAAC,UAAU,CAAC,0BAA0B,EACjE,KAAK,CACN,CAAC;IACJ,CAAC;IAEM,aAAa,GAAG,CAAC,OAAe,EAAE,EAAE,CACzC,IAAI,CAAC,cAAc,CACjB,WAAW,iBAAiB,CAAC,WAAW,IAAI,iBAAiB,CAAC,aAAa,eAAe,OAAO,QAAQ,EACzG,KAAK,CACN,CAAC;IAEG,aAAa,GAAG,KAAK,EAAE,OAAe,EAAE,SAAmB,EAAE,EAAE;QACpE,IAAI;YACF,OAAO,MAAM,IAAI,CAAC,qBAAqB,CACrC,WAAW,iBAAiB,CAAC,WAAW,IACtC,iBAAiB,CAAC,aACpB,eAAe,OAAO,kBAAkB,SAAS;iBAC9C,GAAG,CAAC,YAAY,CAAC;iBACjB,IAAI,CAAC,GAAG,CAAC,EAAE,EACd,KAAK,CACN,CAAC;SACH;QAAC,OAAO,CAAC,EAAE;YACV,IACE,CAAC,YAAY,UAAU;gBACvB,CAAC,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG;gBAC1B,CAAC,CAAC,QAAQ,CAAC,IAAI,EACf;gBACA,OAAQ,CAAC,CAAC,QAAQ,CAAC,IAA4C,CAAC,KAAK,CAAC;aACvE;iBAAM;gBACL,MAAM,CAAC,CAAC;aACT;SACF;IACH,CAAC,CAAC;IAEF,sDAAsD;IAC/C,QAAQ,GAAG,CAChB,SAAqB,EACrB,OAAe,EACf,EAAE,CACF,IAAI,CAAC,cAAc,CACjB,WAAW,iBAAiB,CAAC,eAAe,IAAI,iBAAiB,CAAC,aAAa,OAAO,eAAe,CAAC,SAAS,CAAC,IAAI,OAAO,EAAE,EAC7H,KAAK,CACN,CAAC;IAEJ,wEAAwE;IACjE,uBAAuB,GAAG,CAC/B,SAAqB,EACrB,OAAe,EACf,SAAiB,EACjB,EAAE,CACF,IAAI,CAAC,cAAc,CACjB,WAAW,iBAAiB,CAAC,eAAe,IAAI,iBAAiB,CAAC,aAAa,OAAO,eAAe,CAAC,SAAS,CAAC,IAAI,OAAO,aAAa,SAAS,EAAE,EACnJ,KAAK,CACN,CAAC;CACL"}
@@ -0,0 +1,13 @@
1
+ import { TokenPersister } from "../token-persisters";
2
+ import { SpartanTokenProvider } from "./spartan-token-providers";
3
+ import { XboxTokenProvider } from "./xbox-token-provider";
4
+ /**
5
+ * A SpartanTokenProvider that fetches both the Xbox and Halo tokens in the same
6
+ * process. This is useful for applications that do not need to contend with
7
+ * CORS restrictions.
8
+ */
9
+ export declare class AutoTokenProvider implements SpartanTokenProvider, XboxTokenProvider {
10
+ readonly getSpartanToken: () => Promise<string>;
11
+ readonly getXboxLiveV3Token: () => Promise<string>;
12
+ constructor(getOauth2AccessToken: () => Promise<string>, tokenPersister?: TokenPersister);
13
+ }
@@ -0,0 +1,34 @@
1
+ import { RelyingParty, XboxAuthenticationClient, } from "../../authentication/xbox-authentication-client";
2
+ import { HaloAuthenticationClient } from "../../authentication/halo-authentication-client";
3
+ import { inMemoryTokenPersister } from "../token-persisters/in-memory-token-persister";
4
+ /**
5
+ * A SpartanTokenProvider that fetches both the Xbox and Halo tokens in the same
6
+ * process. This is useful for applications that do not need to contend with
7
+ * CORS restrictions.
8
+ */
9
+ export class AutoTokenProvider {
10
+ getSpartanToken;
11
+ getXboxLiveV3Token;
12
+ constructor(getOauth2AccessToken, tokenPersister) {
13
+ let actualTokenPersister;
14
+ if (tokenPersister) {
15
+ actualTokenPersister = tokenPersister;
16
+ }
17
+ else {
18
+ actualTokenPersister = inMemoryTokenPersister;
19
+ }
20
+ const xboxAuthClient = new XboxAuthenticationClient(tokenPersister);
21
+ const haloAuthClient = new HaloAuthenticationClient(async () => {
22
+ const xstsTicket = await xboxAuthClient.getXstsTicket(getOauth2AccessToken, RelyingParty.Halo);
23
+ return xstsTicket.Token;
24
+ }, async () => await actualTokenPersister.load("halo.authToken"), async (token) => {
25
+ await actualTokenPersister.save("halo.authToken", token);
26
+ });
27
+ this.getSpartanToken = () => haloAuthClient.getSpartanToken();
28
+ this.getXboxLiveV3Token = async () => {
29
+ const xstsTicket = await xboxAuthClient.getXstsTicket(getOauth2AccessToken, RelyingParty.Xbox);
30
+ return xboxAuthClient.getXboxLiveV3Token(xstsTicket);
31
+ };
32
+ }
33
+ }
34
+ //# sourceMappingURL=auto-token-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-token-provider.js","sourceRoot":"","sources":["../../../src/core/token-providers/auto-token-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,wBAAwB,GACzB,MAAM,iDAAiD,CAAC;AAEzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,iDAAiD,CAAC;AAE3F,OAAO,EAAE,sBAAsB,EAAE,MAAM,+CAA+C,CAAC;AAGvF;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IAGZ,eAAe,CAAwB;IACvC,kBAAkB,CAAwB;IAE1D,YACE,oBAA2C,EAC3C,cAA+B;QAE/B,IAAI,oBAAoC,CAAC;QACzC,IAAI,cAAc,EAAE;YAClB,oBAAoB,GAAG,cAAc,CAAC;SACvC;aAAM;YACL,oBAAoB,GAAG,sBAAsB,CAAC;SAC/C;QACD,MAAM,cAAc,GAAG,IAAI,wBAAwB,CAAC,cAAc,CAAC,CAAC;QACpE,MAAM,cAAc,GAAG,IAAI,wBAAwB,CACjD,KAAK,IAAI,EAAE;YACT,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,CACnD,oBAAoB,EACpB,YAAY,CAAC,IAAI,CAClB,CAAC;YACF,OAAO,UAAU,CAAC,KAAK,CAAC;QAC1B,CAAC,EACD,KAAK,IAAI,EAAE,CAAC,MAAM,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAC7D,KAAK,EAAE,KAAK,EAAE,EAAE;YACd,MAAM,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;QAC3D,CAAC,CACF,CAAC;QAEF,IAAI,CAAC,eAAe,GAAG,GAAG,EAAE,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC;QAC9D,IAAI,CAAC,kBAAkB,GAAG,KAAK,IAAI,EAAE;YACnC,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,CACnD,oBAAoB,EACpB,YAAY,CAAC,IAAI,CAClB,CAAC;YACF,OAAO,cAAc,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;QACvD,CAAC,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ import { TokenPersister } from "../../token-persisters";
2
+ import { SpartanTokenProvider } from ".";
3
+ /**
4
+ * A SpartanTokenProvider that fetches both the Xbox and Halo tokens in the same
5
+ * process. This is useful for applications that do not need to contend with
6
+ * CORS restrictions.
7
+ */
8
+ export declare class AutoXstsSpartanTokenProvider implements SpartanTokenProvider {
9
+ readonly getSpartanToken: () => Promise<string>;
10
+ constructor(getOauth2AccessToken: () => Promise<string>, tokenPersister?: TokenPersister);
11
+ }
@@ -0,0 +1,29 @@
1
+ import { XboxAuthenticationClient, } from "../../../authentication/xbox-authentication-client";
2
+ import { HaloAuthenticationClient } from "../../../authentication/halo-authentication-client";
3
+ import { inMemoryTokenPersister } from "../../token-persisters/in-memory-token-persister";
4
+ /**
5
+ * A SpartanTokenProvider that fetches both the Xbox and Halo tokens in the same
6
+ * process. This is useful for applications that do not need to contend with
7
+ * CORS restrictions.
8
+ */
9
+ export class AutoXstsSpartanTokenProvider {
10
+ getSpartanToken;
11
+ constructor(getOauth2AccessToken, tokenPersister) {
12
+ let actualTokenPersister;
13
+ if (tokenPersister) {
14
+ actualTokenPersister = tokenPersister;
15
+ }
16
+ else {
17
+ actualTokenPersister = inMemoryTokenPersister;
18
+ }
19
+ const xboxAuthClient = new XboxAuthenticationClient(tokenPersister);
20
+ const haloAuthClient = new HaloAuthenticationClient(async () => {
21
+ const xstsTicket = await xboxAuthClient.getXstsTicket(getOauth2AccessToken);
22
+ return xstsTicket.Token;
23
+ }, async () => await actualTokenPersister.load("halo.authToken"), async (token) => {
24
+ await actualTokenPersister.save("halo.authToken", token);
25
+ });
26
+ this.getSpartanToken = () => haloAuthClient.getSpartanToken();
27
+ }
28
+ }
29
+ //# sourceMappingURL=auto-xsts-spartan-token-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-xsts-spartan-token-provider.js","sourceRoot":"","sources":["../../../../src/core/token-providers/spartan-token-providers/auto-xsts-spartan-token-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,wBAAwB,GACzB,MAAM,oDAAoD,CAAC;AAE5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAE9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,kDAAkD,CAAC;AAE1F;;;;GAIG;AACH,MAAM,OAAO,4BAA4B;IACvB,eAAe,CAAwB;IAEvD,YACE,oBAA2C,EAC3C,cAA+B;QAE/B,IAAI,oBAAoC,CAAC;QACzC,IAAI,cAAc,EAAE;YAClB,oBAAoB,GAAG,cAAc,CAAC;SACvC;aAAM;YACL,oBAAoB,GAAG,sBAAsB,CAAC;SAC/C;QACD,MAAM,cAAc,GAAG,IAAI,wBAAwB,CAAC,cAAc,CAAC,CAAC;QACpE,MAAM,cAAc,GAAG,IAAI,wBAAwB,CACjD,KAAK,IAAI,EAAE;YACT,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,CACnD,oBAAoB,CACrB,CAAC;YACF,OAAO,UAAU,CAAC,KAAK,CAAC;QAC1B,CAAC,EACD,KAAK,IAAI,EAAE,CAAC,MAAM,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAC7D,KAAK,EAAE,KAAK,EAAE,EAAE;YACd,MAAM,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;QAC3D,CAAC,CACF,CAAC;QAEF,IAAI,CAAC,eAAe,GAAG,GAAG,EAAE,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC;IAChE,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ export interface SpartanTokenProvider {
2
+ getSpartanToken(): Promise<string>;
3
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/token-providers/spartan-token-providers/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ import { TokenPersister } from "../../token-persisters";
2
+ import { SpartanTokenProvider } from ".";
3
+ /**
4
+ * A SpartanTokenProvider that fetches uses a pre-fetched XSTS ticket token.
5
+ * Since requests to the Halo API are subject to CORS restrictions a
6
+ * HaloAuthenticationClient can be instantitated with a pre-fetched XSTS ticket
7
+ * and run on a server (such as one provided by the user).
8
+ */
9
+ export declare class StaticXstsTicketTokenSpartanTokenProvider implements SpartanTokenProvider {
10
+ readonly getSpartanToken: () => Promise<string>;
11
+ constructor(xstsTicketToken: string, tokenPersister?: TokenPersister);
12
+ }
@@ -0,0 +1,25 @@
1
+ import { HaloAuthenticationClient } from "../../../authentication/halo-authentication-client";
2
+ import { inMemoryTokenPersister } from "../../token-persisters/in-memory-token-persister";
3
+ /**
4
+ * A SpartanTokenProvider that fetches uses a pre-fetched XSTS ticket token.
5
+ * Since requests to the Halo API are subject to CORS restrictions a
6
+ * HaloAuthenticationClient can be instantitated with a pre-fetched XSTS ticket
7
+ * and run on a server (such as one provided by the user).
8
+ */
9
+ export class StaticXstsTicketTokenSpartanTokenProvider {
10
+ getSpartanToken;
11
+ constructor(xstsTicketToken, tokenPersister) {
12
+ let actualTokenPersister;
13
+ if (tokenPersister) {
14
+ actualTokenPersister = tokenPersister;
15
+ }
16
+ else {
17
+ actualTokenPersister = inMemoryTokenPersister;
18
+ }
19
+ const haloAuthClient = new HaloAuthenticationClient(() => xstsTicketToken, async () => await actualTokenPersister.load("halo.authToken"), async (token) => {
20
+ await actualTokenPersister.save("halo.authToken", token);
21
+ });
22
+ this.getSpartanToken = () => haloAuthClient.getSpartanToken();
23
+ }
24
+ }
25
+ //# sourceMappingURL=static-xsts-ticket-token-spartan-token-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-xsts-ticket-token-spartan-token-provider.js","sourceRoot":"","sources":["../../../../src/core/token-providers/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC;AAE9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,kDAAkD,CAAC;AAE1F;;;;;GAKG;AACH,MAAM,OAAO,yCAAyC;IAGpC,eAAe,CAAwB;IAEvD,YAAY,eAAuB,EAAE,cAA+B;QAClE,IAAI,oBAAoC,CAAC;QACzC,IAAI,cAAc,EAAE;YAClB,oBAAoB,GAAG,cAAc,CAAC;SACvC;aAAM;YACL,oBAAoB,GAAG,sBAAsB,CAAC;SAC/C;QAED,MAAM,cAAc,GAAG,IAAI,wBAAwB,CACjD,GAAG,EAAE,CAAC,eAAe,EACrB,KAAK,IAAI,EAAE,CAAC,MAAM,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAC7D,KAAK,EAAE,KAAK,EAAE,EAAE;YACd,MAAM,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;QAC3D,CAAC,CACF,CAAC;QAEF,IAAI,CAAC,eAAe,GAAG,GAAG,EAAE,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC;IAChE,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ export interface XboxTokenProvider {
2
+ getXboxLiveV3Token: () => Promise<string>;
3
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=xbox-token-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xbox-token-provider.js","sourceRoot":"","sources":["../../../src/core/token-providers/xbox-token-provider.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import { XboxTokenProvider } from "./token-providers/xbox-token-provider";
2
+ export declare class XboxClient {
3
+ private xboxTokenProvider;
4
+ constructor(xboxTokenProvider: XboxTokenProvider);
5
+ private executeRequest;
6
+ searchUsers(query: string): Promise<{
7
+ id: string;
8
+ gamertag: string;
9
+ displayPicUri: string;
10
+ score: 0.0;
11
+ }[]>;
12
+ recentPlayers(): Promise<unknown>;
13
+ }
@@ -0,0 +1,28 @@
1
+ import axios, { AxiosHeaders } from "axios";
2
+ export class XboxClient {
3
+ xboxTokenProvider;
4
+ constructor(xboxTokenProvider) {
5
+ this.xboxTokenProvider = xboxTokenProvider;
6
+ }
7
+ async executeRequest(url, method) {
8
+ const headers = new AxiosHeaders({
9
+ Accept: "application/json",
10
+ Authorization: await this.xboxTokenProvider.getXboxLiveV3Token(),
11
+ "x-xbl-contract-version": "1",
12
+ });
13
+ const response = await axios.request({
14
+ url,
15
+ method,
16
+ headers,
17
+ });
18
+ return response.data;
19
+ }
20
+ async searchUsers(query) {
21
+ const { results } = await this.executeRequest(`https://usersearch.xboxlive.com/suggest?q=${encodeURIComponent(query)}`, "GET");
22
+ return results.map(({ result }) => result);
23
+ }
24
+ async recentPlayers() {
25
+ return await this.executeRequest("https://peoplehub.xboxlive.com/users/me/people/recentplayers", "GET");
26
+ }
27
+ }
28
+ //# sourceMappingURL=xbox-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xbox-client.js","sourceRoot":"","sources":["../../src/core/xbox-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,YAAY,EAAU,MAAM,OAAO,CAAC;AAGpD,MAAM,OAAO,UAAU;IACD;IAApB,YAAoB,iBAAoC;QAApC,sBAAiB,GAAjB,iBAAiB,CAAmB;IAAG,CAAC;IAEpD,KAAK,CAAC,cAAc,CAAI,GAAW,EAAE,MAAc;QACzD,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC;YAC/B,MAAM,EAAE,kBAAkB;YAC1B,aAAa,EAAE,MAAM,IAAI,CAAC,iBAAiB,CAAC,kBAAkB,EAAE;YAChE,wBAAwB,EAAE,GAAG;SAC9B,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAI;YACtC,GAAG;YACH,MAAM;YACN,OAAO;SACR,CAAC,CAAC;QAEH,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,KAAa;QACpC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,cAAc,CAa3C,6CAA6C,kBAAkB,CAAC,KAAK,CAAC,EAAE,EACxE,KAAK,CACN,CAAC;QACF,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;IAEM,KAAK,CAAC,aAAa;QACxB,OAAO,MAAM,IAAI,CAAC,cAAc,CAC9B,8DAA8D,EAC9D,KAAK,CACN,CAAC;IACJ,CAAC;CACF"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { HaloInfiniteClient, AssetKindTypeMap, } from "./core/halo-infinite-client";
2
+ export { XboxClient } from "./core/xbox-client";
2
3
  export { XboxAuthenticationClient, RelyingParty, } from "./authentication/xbox-authentication-client";
3
4
  export { Playlist } from "./models/halo-infinite/playlist";
4
5
  export { PlaylistCsrContainer } from "./models/halo-infinite/playlist-csr-container";
@@ -15,8 +16,8 @@ export { MatchOutcome } from "./models/halo-infinite/match-outcome";
15
16
  export { MatchSkill } from "./models/halo-infinite/match-skill";
16
17
  export { AssetVersionLink } from "./models/halo-infinite/asset-version-link";
17
18
  export { MatchInfo } from "./models/halo-infinite/match-info";
18
- export { SpartanTokenProvider } from "./core/spartan-token-providers";
19
- export { AutoXstsSpartanTokenProvider } from "./core/spartan-token-providers/auto-xsts-spartan-token-provider";
20
- export { StaticXstsTicketTokenSpartanTokenProvider } from "./core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider";
19
+ export { SpartanTokenProvider } from "./core/token-providers/spartan-token-providers";
20
+ export { AutoTokenProvider, AutoTokenProvider as AutoXstsSpartanTokenProvider, } from "./core/token-providers/auto-token-provider";
21
+ export { StaticXstsTicketTokenSpartanTokenProvider } from "./core/token-providers/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider";
21
22
  export { TokenPersister } from "./core/token-persisters";
22
23
  export { PlaylistExperience } from "./models/halo-infinite/playlist-experience";
package/dist/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
  export { HaloInfiniteClient, } from "./core/halo-infinite-client";
2
+ export { XboxClient } from "./core/xbox-client";
2
3
  export { XboxAuthenticationClient, RelyingParty, } from "./authentication/xbox-authentication-client";
3
4
  export { MatchType } from "./models/halo-infinite/match-type";
4
5
  export { GameVariantCategory } from "./models/halo-infinite/game-variant-category";
5
6
  export { AssetKind } from "./models/halo-infinite/asset-kind";
6
7
  export { MatchOutcome } from "./models/halo-infinite/match-outcome";
7
- export { AutoXstsSpartanTokenProvider } from "./core/spartan-token-providers/auto-xsts-spartan-token-provider";
8
- export { StaticXstsTicketTokenSpartanTokenProvider } from "./core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider";
8
+ export { AutoTokenProvider, AutoTokenProvider as AutoXstsSpartanTokenProvider, } from "./core/token-providers/auto-token-provider";
9
+ export { StaticXstsTicketTokenSpartanTokenProvider } from "./core/token-providers/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider";
9
10
  export { PlaylistExperience } from "./models/halo-infinite/playlist-experience";
10
11
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAEnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,wBAAwB,EACxB,YAAY,GACb,MAAM,6CAA6C,CAAC;AAKrD,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAC;AAKnF,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAKpE,OAAO,EAAE,4BAA4B,EAAE,MAAM,iEAAiE,CAAC;AAC/G,OAAO,EAAE,yCAAyC,EAAE,MAAM,gFAAgF,CAAC;AAE3I,OAAO,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAEnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,wBAAwB,EACxB,YAAY,GACb,MAAM,6CAA6C,CAAC;AAKrD,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAC;AAKnF,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAKpE,OAAO,EACL,iBAAiB,EACjB,iBAAiB,IAAI,4BAA4B,GAClD,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,yCAAyC,EAAE,MAAM,gGAAgG,CAAC;AAE3J,OAAO,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAC"}
@@ -7,8 +7,10 @@ export declare enum GameVariantCategory {
7
7
  MultiplayerTotalControl = 14,
8
8
  MultiplayerCtf = 15,
9
9
  MultiplayerOddball = 18,
10
+ MultiplayerStockpile = 19,
10
11
  MultiplayerInfection = 22,
11
12
  MultiplayerGrifball = 25,
12
13
  MultiplayerLandGrab = 39,
13
- MultiplayerExtraction = 17
14
+ MultiplayerExtraction = 17,
15
+ MultiplayerFirefight = 42
14
16
  }
@@ -8,9 +8,11 @@ export var GameVariantCategory;
8
8
  GameVariantCategory[GameVariantCategory["MultiplayerTotalControl"] = 14] = "MultiplayerTotalControl";
9
9
  GameVariantCategory[GameVariantCategory["MultiplayerCtf"] = 15] = "MultiplayerCtf";
10
10
  GameVariantCategory[GameVariantCategory["MultiplayerOddball"] = 18] = "MultiplayerOddball";
11
+ GameVariantCategory[GameVariantCategory["MultiplayerStockpile"] = 19] = "MultiplayerStockpile";
11
12
  GameVariantCategory[GameVariantCategory["MultiplayerInfection"] = 22] = "MultiplayerInfection";
12
13
  GameVariantCategory[GameVariantCategory["MultiplayerGrifball"] = 25] = "MultiplayerGrifball";
13
14
  GameVariantCategory[GameVariantCategory["MultiplayerLandGrab"] = 39] = "MultiplayerLandGrab";
14
15
  GameVariantCategory[GameVariantCategory["MultiplayerExtraction"] = 17] = "MultiplayerExtraction";
16
+ GameVariantCategory[GameVariantCategory["MultiplayerFirefight"] = 42] = "MultiplayerFirefight";
15
17
  })(GameVariantCategory || (GameVariantCategory = {}));
16
18
  //# sourceMappingURL=game-variant-category.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"game-variant-category.js","sourceRoot":"","sources":["../../../src/models/halo-infinite/game-variant-category.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,mBAaX;AAbD,WAAY,mBAAmB;IAC7B,uFAAqB,CAAA;IACrB,6FAAwB,CAAA;IACxB,uFAAqB,CAAA;IACrB,kGAA2B,CAAA;IAC3B,sGAA6B,CAAA;IAC7B,oGAA4B,CAAA;IAC5B,kFAAmB,CAAA;IACnB,0FAAuB,CAAA;IACvB,8FAAyB,CAAA;IACzB,4FAAwB,CAAA;IACxB,4FAAwB,CAAA;IACxB,gGAA0B,CAAA;AAC5B,CAAC,EAbW,mBAAmB,KAAnB,mBAAmB,QAa9B"}
1
+ {"version":3,"file":"game-variant-category.js","sourceRoot":"","sources":["../../../src/models/halo-infinite/game-variant-category.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,mBAeX;AAfD,WAAY,mBAAmB;IAC7B,uFAAqB,CAAA;IACrB,6FAAwB,CAAA;IACxB,uFAAqB,CAAA;IACrB,kGAA2B,CAAA;IAC3B,sGAA6B,CAAA;IAC7B,oGAA4B,CAAA;IAC5B,kFAAmB,CAAA;IACnB,0FAAuB,CAAA;IACvB,8FAAyB,CAAA;IACzB,8FAAyB,CAAA;IACzB,4FAAwB,CAAA;IACxB,4FAAwB,CAAA;IACxB,gGAA0B,CAAA;IAC1B,8FAAyB,CAAA;AAC3B,CAAC,EAfW,mBAAmB,KAAnB,mBAAmB,QAe9B"}
@@ -1,5 +1,5 @@
1
1
  import { GameVariantCategory } from "./game-variant-category";
2
- interface OddballStats {
2
+ export interface OddballStats {
3
3
  KillsAsSkullCarrier: number;
4
4
  LongestTimeAsSkullCarrier: string;
5
5
  SkullCarriersKilled: number;
@@ -7,7 +7,7 @@ interface OddballStats {
7
7
  TimeAsSkullCarrier: string;
8
8
  SkullScoringTicks: number;
9
9
  }
10
- interface ZonesStats {
10
+ export interface ZonesStats {
11
11
  StrongholdCaptures: number;
12
12
  StrongholdDefensiveKills: number;
13
13
  StrongholdOffensiveKills: number;
@@ -15,7 +15,7 @@ interface ZonesStats {
15
15
  StrongholdOccupationTime: string;
16
16
  StrongholdScoringTicks: number;
17
17
  }
18
- interface CaptureTheFlagStats {
18
+ export interface CaptureTheFlagStats {
19
19
  FlagCaptureAssists: number;
20
20
  FlagCaptures: number;
21
21
  FlagCarriersKilled: number;
@@ -28,13 +28,46 @@ interface CaptureTheFlagStats {
28
28
  KillsAsFlagReturner: number;
29
29
  TimeAsFlagCarrier: string;
30
30
  }
31
- interface ExtractionStats {
31
+ export interface ExtractionStats {
32
32
  SuccessfulExtractions: number;
33
33
  ExtractionConversionsDenied: number;
34
34
  ExtractionConversionsCompleted: number;
35
35
  ExtractionInitiationsDenied: number;
36
36
  ExtractionInitiationsCompleted: number;
37
37
  }
38
+ export interface EliminationStats {
39
+ AlliesRevived: number;
40
+ EliminationAssists: number;
41
+ Eliminations: number;
42
+ EnemyRevivesDenied: number;
43
+ Executions: number;
44
+ KillsAsLastPlayerStanding: number;
45
+ LastPlayersStandingKilled: number;
46
+ RoundsSurvived: number;
47
+ TimesRevivedByAlly: number;
48
+ }
49
+ export interface InfectionStats {
50
+ AlphasKilled: number;
51
+ SpartansInfected: number;
52
+ SpartansInfectedAsAlpha: number;
53
+ KillsAsLastSpartanStanding: number;
54
+ LastSpartansStandingInfected: number;
55
+ RoundsAsAlpha: number;
56
+ RoundsAsLastSpartanStanding: number;
57
+ RoundsFinishedAsInfected: number;
58
+ RoundsSurvivedAsSpartan: number;
59
+ RoundsSurvivedAsLastSpartanStanding: number;
60
+ TimeAsLastSpartanStanding: string;
61
+ InfectedKilled: number;
62
+ }
63
+ export interface StockpileStats {
64
+ KillsAsPowerSeedCarrier: number;
65
+ PowerSeedCarriersKilled: number;
66
+ PowerSeedsDeposited: number;
67
+ PowerSeedsStolen: number;
68
+ TimeAsPowerSeedCarrier: string;
69
+ TimeAsPowerSeedDriver: string;
70
+ }
38
71
  type StatsMap = {
39
72
  [GameVariantCategory.MultiplayerOddball]: {
40
73
  OddballStats: OddballStats;
@@ -51,6 +84,15 @@ type StatsMap = {
51
84
  [GameVariantCategory.MultiplayerExtraction]: {
52
85
  ExtractionStats: ExtractionStats;
53
86
  };
87
+ [GameVariantCategory.MultiplayerFirefight]: {
88
+ EliminationStats: EliminationStats;
89
+ };
90
+ [GameVariantCategory.MultiplayerInfection]: {
91
+ InfectionSTats: InfectionStats;
92
+ };
93
+ [GameVariantCategory.MultiplayerStockpile]: {
94
+ StockpileStats: StockpileStats;
95
+ };
54
96
  };
55
97
  export type Stats<TCategory extends GameVariantCategory = GameVariantCategory> = {
56
98
  CoreStats: {
@@ -0,0 +1,13 @@
1
+ import { DateTime } from "luxon";
2
+ export declare class KeyedExpiryTokenCache<TToken extends {
3
+ expiresAt: DateTime;
4
+ }, TKey extends string, TArgs extends any[]> {
5
+ private readonly generateNewToken;
6
+ private readonly existingTokenFetcher;
7
+ private readonly tokenFetchPromiseMap;
8
+ constructor(generateNewToken: (key: TKey, ...args: TArgs) => Promise<TToken>, existingTokenFetcher: (key: TKey) => Promise<(Omit<TToken, "expiresAt"> & {
9
+ expiresAt: unknown;
10
+ }) | null>);
11
+ getToken(key: TKey, ...args: TArgs): Promise<TToken>;
12
+ getExistingToken(key: TKey): Promise<TToken | null>;
13
+ }
@@ -0,0 +1,74 @@
1
+ import { DateTime } from "luxon";
2
+ import { ResolvablePromise } from "./resolvable-promise";
3
+ import { coalesceDateTime } from "./date-time";
4
+ export class KeyedExpiryTokenCache {
5
+ generateNewToken;
6
+ existingTokenFetcher;
7
+ tokenFetchPromiseMap = new Map();
8
+ constructor(generateNewToken, existingTokenFetcher) {
9
+ this.generateNewToken = generateNewToken;
10
+ this.existingTokenFetcher = existingTokenFetcher;
11
+ }
12
+ async getToken(key, ...args) {
13
+ let tokenFetchPromise = this.tokenFetchPromiseMap.get(key);
14
+ if (tokenFetchPromise) {
15
+ // Someone either already has a token or is in the process of getting one
16
+ // Wait for them to finish, then check for validity
17
+ const currentToken = await tokenFetchPromise;
18
+ if (currentToken.expiresAt > DateTime.now()) {
19
+ // Current token is valid, return it
20
+ return currentToken;
21
+ }
22
+ else {
23
+ // Current token expired, start a new promise
24
+ tokenFetchPromise = new ResolvablePromise();
25
+ this.tokenFetchPromiseMap.set(key, tokenFetchPromise);
26
+ try {
27
+ const newToken = await this.generateNewToken(key, ...args);
28
+ tokenFetchPromise.resolve(newToken);
29
+ return newToken;
30
+ }
31
+ catch (e) {
32
+ tokenFetchPromise.reject(e);
33
+ tokenFetchPromise = undefined;
34
+ throw e;
35
+ }
36
+ }
37
+ }
38
+ else {
39
+ // No one has a token, start a new promise
40
+ tokenFetchPromise = new ResolvablePromise();
41
+ this.tokenFetchPromiseMap.set(key, tokenFetchPromise);
42
+ try {
43
+ const existingToken = await this.getExistingToken(key);
44
+ if (existingToken?.expiresAt) {
45
+ const expiresAt = coalesceDateTime(existingToken.expiresAt);
46
+ if (expiresAt && expiresAt > DateTime.now()) {
47
+ const newToken = { ...existingToken, expiresAt };
48
+ tokenFetchPromise.resolve(newToken);
49
+ return newToken;
50
+ }
51
+ }
52
+ const newToken = await this.generateNewToken(key, ...args);
53
+ tokenFetchPromise.resolve(newToken);
54
+ return newToken;
55
+ }
56
+ catch (e) {
57
+ tokenFetchPromise.reject(e);
58
+ tokenFetchPromise = undefined;
59
+ throw e;
60
+ }
61
+ }
62
+ }
63
+ async getExistingToken(key) {
64
+ const existingToken = await this.existingTokenFetcher(key);
65
+ if (existingToken?.expiresAt) {
66
+ const expiresAt = coalesceDateTime(existingToken.expiresAt);
67
+ if (expiresAt && expiresAt > DateTime.now()) {
68
+ return { ...existingToken, expiresAt };
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+ }
74
+ //# sourceMappingURL=keyed-expiry-token-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyed-expiry-token-cache.js","sourceRoot":"","sources":["../../src/util/keyed-expiry-token-cache.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "halo-infinite-api",
3
3
  "type": "module",
4
- "version": "4.0.6",
4
+ "version": "5.0.0",
5
5
  "description": "An NPM package for accessing the official Halo Infinite API.",
6
6
  "main": "dist/index.js",
7
7
  "scripts": {
@@ -2,7 +2,7 @@ import axios, { AxiosInstance } from "axios";
2
2
  import { DateTime } from "luxon";
3
3
  import { TokenPersister } from "../core/token-persisters";
4
4
  import { XboxTicket } from "../models/xbox-ticket";
5
- import { coalesceDateTime } from "../util/date-time";
5
+ import { KeyedExpiryTokenCache } from "../util/keyed-expiry-token-cache";
6
6
  import { ExpiryTokenCache } from "../util/expiry-token-cache";
7
7
 
8
8
  export enum RelyingParty {
@@ -51,8 +51,8 @@ export class XboxAuthenticationClient {
51
51
  "xbox.userToken"
52
52
  )) ?? null
53
53
  );
54
- private xstsTicketCache = new ExpiryTokenCache(
55
- async (userToken: string, relyingParty: RelyingParty) => {
54
+ private xstsTicketCache = new KeyedExpiryTokenCache(
55
+ async (relyingParty: RelyingParty, userToken: string) => {
56
56
  const response = await this.httpClient.post<XboxTicket>(
57
57
  "https://xsts.auth.xboxlive.com/xsts/authorize",
58
58
  {
@@ -76,12 +76,15 @@ export class XboxAuthenticationClient {
76
76
  ...response.data,
77
77
  expiresAt: DateTime.fromISO(response.data.NotAfter),
78
78
  };
79
- await this.tokenPersister?.save("xbox.xstsTicket", result);
79
+ await this.tokenPersister?.save(
80
+ "xbox.xstsTicket." + relyingParty,
81
+ result
82
+ );
80
83
  return result;
81
84
  },
82
- async () =>
85
+ async (relyingParty) =>
83
86
  (await this.tokenPersister?.load<XboxTicket & { expiresAt: unknown }>(
84
- "xbox.xstsTicket"
87
+ "xbox.xstsTicket." + relyingParty
85
88
  )) ?? null
86
89
  );
87
90
 
@@ -91,8 +94,11 @@ export class XboxAuthenticationClient {
91
94
  this.httpClient = axios.create();
92
95
  }
93
96
 
94
- public async getXstsTicket(getOauth2AccessToken: () => Promise<string>) {
95
- let xstsTicket = await this.xstsTicketCache.getExistingToken();
97
+ public async getXstsTicket(
98
+ getOauth2AccessToken: () => Promise<string>,
99
+ relyingParty: RelyingParty
100
+ ) {
101
+ let xstsTicket = await this.xstsTicketCache.getExistingToken(relyingParty);
96
102
  if (!xstsTicket) {
97
103
  let userToken = await this.userTokenCache.getExistingToken();
98
104
  if (!userToken) {
@@ -103,13 +109,13 @@ export class XboxAuthenticationClient {
103
109
  );
104
110
  }
105
111
  xstsTicket = await this.xstsTicketCache.getToken(
106
- userToken.Token,
107
- RelyingParty.Halo
112
+ relyingParty,
113
+ userToken.Token
108
114
  );
109
115
  }
110
116
  return xstsTicket;
111
117
  }
112
118
 
113
- public getXboxLiveV3Token = (userHash: string, userToken: string) =>
114
- `XBL3.0 x=${userHash};${userToken}`;
119
+ public getXboxLiveV3Token = (xboxTicket: XboxTicket) =>
120
+ `XBL3.0 x=${xboxTicket.DisplayClaims.xui[0].uhs};${xboxTicket.Token}`;
115
121
  }
@@ -15,7 +15,7 @@ import { PlaylistCsrContainer } from "../models/halo-infinite/playlist-csr-conta
15
15
  import { ServiceRecord } from "../models/halo-infinite/service-record";
16
16
  import { UserInfo } from "../models/halo-infinite/user-info";
17
17
  import { GlobalConstants } from "../util/global-contants";
18
- import { SpartanTokenProvider } from "./spartan-token-providers";
18
+ import { SpartanTokenProvider } from "./token-providers/spartan-token-providers";
19
19
 
20
20
  interface ResultContainer<TValue> {
21
21
  Id: string;
@@ -49,7 +49,7 @@ const assetKindUrlMap = {
49
49
  };
50
50
 
51
51
  function wrapPlayerId(playerId: string) {
52
- if (/^\w+(\d+)/) {
52
+ if (/^\w+\(\d+\)/.test(playerId)) {
53
53
  return playerId;
54
54
  } else {
55
55
  // Assume xuid
@@ -197,11 +197,23 @@ export class HaloInfiniteClient {
197
197
  params,
198
198
  `https://${HaloCoreEndpoints.StatsOrigin}.${
199
199
  HaloCoreEndpoints.ServiceDomain
200
- }/hi/players/xuid(${wrapPlayerId(playerXuid)})/matches`,
200
+ }/hi/players/${wrapPlayerId(playerXuid)}/matches`,
201
201
  "get"
202
202
  );
203
203
  };
204
204
 
205
+ public getPlayerServiceRecord(
206
+ playerXuid: string,
207
+ type: MatchType = MatchType.All
208
+ ) {
209
+ return this.executeRequest<ServiceRecord>(
210
+ `https://${HaloCoreEndpoints.StatsOrigin}.${
211
+ HaloCoreEndpoints.ServiceDomain
212
+ }/hi/players/${wrapPlayerId(playerXuid)}/Matchmade/servicerecord`,
213
+ "get"
214
+ );
215
+ }
216
+
205
217
  public getMatchStats = (matchId: string) =>
206
218
  this.executeRequest<MatchStats>(
207
219
  `https://${HaloCoreEndpoints.StatsOrigin}.${HaloCoreEndpoints.ServiceDomain}/hi/matches/${matchId}/stats`,
@@ -4,16 +4,20 @@ import {
4
4
  } from "../../authentication/xbox-authentication-client";
5
5
  import { TokenPersister } from "../token-persisters";
6
6
  import { HaloAuthenticationClient } from "../../authentication/halo-authentication-client";
7
- import { SpartanTokenProvider } from ".";
7
+ import { SpartanTokenProvider } from "./spartan-token-providers";
8
8
  import { inMemoryTokenPersister } from "../token-persisters/in-memory-token-persister";
9
+ import { XboxTokenProvider } from "./xbox-token-provider";
9
10
 
10
11
  /**
11
12
  * A SpartanTokenProvider that fetches both the Xbox and Halo tokens in the same
12
13
  * process. This is useful for applications that do not need to contend with
13
14
  * CORS restrictions.
14
15
  */
15
- export class AutoXstsSpartanTokenProvider implements SpartanTokenProvider {
16
+ export class AutoTokenProvider
17
+ implements SpartanTokenProvider, XboxTokenProvider
18
+ {
16
19
  public readonly getSpartanToken: () => Promise<string>;
20
+ public readonly getXboxLiveV3Token: () => Promise<string>;
17
21
 
18
22
  constructor(
19
23
  getOauth2AccessToken: () => Promise<string>,
@@ -29,7 +33,8 @@ export class AutoXstsSpartanTokenProvider implements SpartanTokenProvider {
29
33
  const haloAuthClient = new HaloAuthenticationClient(
30
34
  async () => {
31
35
  const xstsTicket = await xboxAuthClient.getXstsTicket(
32
- getOauth2AccessToken
36
+ getOauth2AccessToken,
37
+ RelyingParty.Halo
33
38
  );
34
39
  return xstsTicket.Token;
35
40
  },
@@ -40,5 +45,12 @@ export class AutoXstsSpartanTokenProvider implements SpartanTokenProvider {
40
45
  );
41
46
 
42
47
  this.getSpartanToken = () => haloAuthClient.getSpartanToken();
48
+ this.getXboxLiveV3Token = async () => {
49
+ const xstsTicket = await xboxAuthClient.getXstsTicket(
50
+ getOauth2AccessToken,
51
+ RelyingParty.Xbox
52
+ );
53
+ return xboxAuthClient.getXboxLiveV3Token(xstsTicket);
54
+ };
43
55
  }
44
56
  }
@@ -1,7 +1,7 @@
1
- import { TokenPersister } from "../token-persisters";
2
- import { HaloAuthenticationClient } from "../../authentication/halo-authentication-client";
1
+ import { TokenPersister } from "../../token-persisters";
2
+ import { HaloAuthenticationClient } from "../../../authentication/halo-authentication-client";
3
3
  import { SpartanTokenProvider } from ".";
4
- import { inMemoryTokenPersister } from "../token-persisters/in-memory-token-persister";
4
+ import { inMemoryTokenPersister } from "../../token-persisters/in-memory-token-persister";
5
5
 
6
6
  /**
7
7
  * A SpartanTokenProvider that fetches uses a pre-fetched XSTS ticket token.
@@ -0,0 +1,3 @@
1
+ export interface XboxTokenProvider {
2
+ getXboxLiveV3Token: () => Promise<string>;
3
+ }
@@ -0,0 +1,48 @@
1
+ import axios, { AxiosHeaders, Method } from "axios";
2
+ import { XboxTokenProvider } from "./token-providers/xbox-token-provider";
3
+
4
+ export class XboxClient {
5
+ constructor(private xboxTokenProvider: XboxTokenProvider) {}
6
+
7
+ private async executeRequest<T>(url: string, method: Method) {
8
+ const headers = new AxiosHeaders({
9
+ Accept: "application/json",
10
+ Authorization: await this.xboxTokenProvider.getXboxLiveV3Token(),
11
+ "x-xbl-contract-version": "1",
12
+ });
13
+ const response = await axios.request<T>({
14
+ url,
15
+ method,
16
+ headers,
17
+ });
18
+
19
+ return response.data;
20
+ }
21
+
22
+ public async searchUsers(query: string) {
23
+ const { results } = await this.executeRequest<{
24
+ results: [
25
+ {
26
+ result: {
27
+ id: string;
28
+ gamertag: string;
29
+ displayPicUri: string;
30
+ score: 0.0;
31
+ };
32
+ text: string;
33
+ }
34
+ ];
35
+ }>(
36
+ `https://usersearch.xboxlive.com/suggest?q=${encodeURIComponent(query)}`,
37
+ "GET"
38
+ );
39
+ return results.map(({ result }) => result);
40
+ }
41
+
42
+ public async recentPlayers() {
43
+ return await this.executeRequest<unknown>(
44
+ "https://peoplehub.xboxlive.com/users/me/people/recentplayers",
45
+ "GET"
46
+ );
47
+ }
48
+ }
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ export {
2
2
  HaloInfiniteClient,
3
3
  AssetKindTypeMap,
4
4
  } from "./core/halo-infinite-client";
5
+ export { XboxClient } from "./core/xbox-client";
5
6
  export {
6
7
  XboxAuthenticationClient,
7
8
  RelyingParty,
@@ -21,8 +22,11 @@ export { MatchOutcome } from "./models/halo-infinite/match-outcome";
21
22
  export { MatchSkill } from "./models/halo-infinite/match-skill";
22
23
  export { AssetVersionLink } from "./models/halo-infinite/asset-version-link";
23
24
  export { MatchInfo } from "./models/halo-infinite/match-info";
24
- export { SpartanTokenProvider } from "./core/spartan-token-providers";
25
- export { AutoXstsSpartanTokenProvider } from "./core/spartan-token-providers/auto-xsts-spartan-token-provider";
26
- export { StaticXstsTicketTokenSpartanTokenProvider } from "./core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider";
25
+ export { SpartanTokenProvider } from "./core/token-providers/spartan-token-providers";
26
+ export {
27
+ AutoTokenProvider,
28
+ AutoTokenProvider as AutoXstsSpartanTokenProvider,
29
+ } from "./core/token-providers/auto-token-provider";
30
+ export { StaticXstsTicketTokenSpartanTokenProvider } from "./core/token-providers/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider";
27
31
  export { TokenPersister } from "./core/token-persisters";
28
32
  export { PlaylistExperience } from "./models/halo-infinite/playlist-experience";
@@ -7,8 +7,10 @@ export enum GameVariantCategory {
7
7
  MultiplayerTotalControl = 14,
8
8
  MultiplayerCtf = 15,
9
9
  MultiplayerOddball = 18,
10
+ MultiplayerStockpile = 19,
10
11
  MultiplayerInfection = 22,
11
12
  MultiplayerGrifball = 25,
12
13
  MultiplayerLandGrab = 39,
13
14
  MultiplayerExtraction = 17,
15
+ MultiplayerFirefight = 42,
14
16
  }
@@ -1,6 +1,6 @@
1
1
  import { GameVariantCategory } from "./game-variant-category";
2
2
 
3
- interface OddballStats {
3
+ export interface OddballStats {
4
4
  KillsAsSkullCarrier: number;
5
5
  LongestTimeAsSkullCarrier: string;
6
6
  SkullCarriersKilled: number;
@@ -8,7 +8,8 @@ interface OddballStats {
8
8
  TimeAsSkullCarrier: string;
9
9
  SkullScoringTicks: number;
10
10
  }
11
- interface ZonesStats {
11
+
12
+ export interface ZonesStats {
12
13
  StrongholdCaptures: number;
13
14
  StrongholdDefensiveKills: number;
14
15
  StrongholdOffensiveKills: number;
@@ -16,7 +17,8 @@ interface ZonesStats {
16
17
  StrongholdOccupationTime: string;
17
18
  StrongholdScoringTicks: number;
18
19
  }
19
- interface CaptureTheFlagStats {
20
+
21
+ export interface CaptureTheFlagStats {
20
22
  FlagCaptureAssists: number;
21
23
  FlagCaptures: number;
22
24
  FlagCarriersKilled: number;
@@ -30,7 +32,7 @@ interface CaptureTheFlagStats {
30
32
  TimeAsFlagCarrier: string;
31
33
  }
32
34
 
33
- interface ExtractionStats {
35
+ export interface ExtractionStats {
34
36
  SuccessfulExtractions: number;
35
37
  ExtractionConversionsDenied: number;
36
38
  ExtractionConversionsCompleted: number;
@@ -38,6 +40,42 @@ interface ExtractionStats {
38
40
  ExtractionInitiationsCompleted: number;
39
41
  }
40
42
 
43
+ export interface EliminationStats {
44
+ AlliesRevived: number;
45
+ EliminationAssists: number;
46
+ Eliminations: number;
47
+ EnemyRevivesDenied: number;
48
+ Executions: number;
49
+ KillsAsLastPlayerStanding: number;
50
+ LastPlayersStandingKilled: number;
51
+ RoundsSurvived: number;
52
+ TimesRevivedByAlly: number;
53
+ }
54
+
55
+ export interface InfectionStats {
56
+ AlphasKilled: number;
57
+ SpartansInfected: number;
58
+ SpartansInfectedAsAlpha: number;
59
+ KillsAsLastSpartanStanding: number;
60
+ LastSpartansStandingInfected: number;
61
+ RoundsAsAlpha: number;
62
+ RoundsAsLastSpartanStanding: number;
63
+ RoundsFinishedAsInfected: number;
64
+ RoundsSurvivedAsSpartan: number;
65
+ RoundsSurvivedAsLastSpartanStanding: number;
66
+ TimeAsLastSpartanStanding: string;
67
+ InfectedKilled: number;
68
+ }
69
+
70
+ export interface StockpileStats {
71
+ KillsAsPowerSeedCarrier: number;
72
+ PowerSeedCarriersKilled: number;
73
+ PowerSeedsDeposited: number;
74
+ PowerSeedsStolen: number;
75
+ TimeAsPowerSeedCarrier: string;
76
+ TimeAsPowerSeedDriver: string;
77
+ }
78
+
41
79
  type StatsMap = {
42
80
  [GameVariantCategory.MultiplayerOddball]: { OddballStats: OddballStats };
43
81
  [GameVariantCategory.MultiplayerStrongholds]: { ZonesStats: ZonesStats };
@@ -48,6 +86,15 @@ type StatsMap = {
48
86
  [GameVariantCategory.MultiplayerExtraction]: {
49
87
  ExtractionStats: ExtractionStats;
50
88
  };
89
+ [GameVariantCategory.MultiplayerFirefight]: {
90
+ EliminationStats: EliminationStats;
91
+ };
92
+ [GameVariantCategory.MultiplayerInfection]: {
93
+ InfectionSTats: InfectionStats;
94
+ };
95
+ [GameVariantCategory.MultiplayerStockpile]: {
96
+ StockpileStats: StockpileStats;
97
+ };
51
98
  };
52
99
 
53
100
  export type Stats<TCategory extends GameVariantCategory = GameVariantCategory> =
@@ -0,0 +1,90 @@
1
+ import { DateTime } from "luxon";
2
+ import { ResolvablePromise } from "./resolvable-promise";
3
+ import { coalesceDateTime } from "./date-time";
4
+
5
+ export class KeyedExpiryTokenCache<
6
+ TToken extends { expiresAt: DateTime },
7
+ TKey extends string,
8
+ TArgs extends any[]
9
+ > {
10
+ private readonly tokenFetchPromiseMap = new Map<
11
+ TKey,
12
+ ResolvablePromise<TToken>
13
+ >();
14
+
15
+ constructor(
16
+ private readonly generateNewToken: (
17
+ key: TKey,
18
+ ...args: TArgs
19
+ ) => Promise<TToken>,
20
+ private readonly existingTokenFetcher: (
21
+ key: TKey
22
+ ) => Promise<(Omit<TToken, "expiresAt"> & { expiresAt: unknown }) | null>
23
+ ) {}
24
+
25
+ async getToken(key: TKey, ...args: TArgs): Promise<TToken> {
26
+ let tokenFetchPromise = this.tokenFetchPromiseMap.get(key);
27
+ if (tokenFetchPromise) {
28
+ // Someone either already has a token or is in the process of getting one
29
+ // Wait for them to finish, then check for validity
30
+ const currentToken = await tokenFetchPromise;
31
+
32
+ if (currentToken.expiresAt > DateTime.now()) {
33
+ // Current token is valid, return it
34
+ return currentToken;
35
+ } else {
36
+ // Current token expired, start a new promise
37
+ tokenFetchPromise = new ResolvablePromise<TToken>();
38
+ this.tokenFetchPromiseMap.set(key, tokenFetchPromise);
39
+
40
+ try {
41
+ const newToken = await this.generateNewToken(key, ...args);
42
+ tokenFetchPromise.resolve(newToken);
43
+ return newToken;
44
+ } catch (e) {
45
+ tokenFetchPromise.reject(e);
46
+ tokenFetchPromise = undefined;
47
+ throw e;
48
+ }
49
+ }
50
+ } else {
51
+ // No one has a token, start a new promise
52
+ tokenFetchPromise = new ResolvablePromise<TToken>();
53
+ this.tokenFetchPromiseMap.set(key, tokenFetchPromise);
54
+
55
+ try {
56
+ const existingToken = await this.getExistingToken(key);
57
+
58
+ if (existingToken?.expiresAt) {
59
+ const expiresAt = coalesceDateTime(existingToken.expiresAt);
60
+ if (expiresAt && expiresAt > DateTime.now()) {
61
+ const newToken = { ...existingToken, expiresAt } as TToken;
62
+ tokenFetchPromise.resolve(newToken);
63
+ return newToken;
64
+ }
65
+ }
66
+
67
+ const newToken = await this.generateNewToken(key, ...args);
68
+ tokenFetchPromise.resolve(newToken);
69
+ return newToken;
70
+ } catch (e) {
71
+ tokenFetchPromise.reject(e);
72
+ tokenFetchPromise = undefined;
73
+ throw e;
74
+ }
75
+ }
76
+ }
77
+
78
+ async getExistingToken(key: TKey) {
79
+ const existingToken = await this.existingTokenFetcher(key);
80
+
81
+ if (existingToken?.expiresAt) {
82
+ const expiresAt = coalesceDateTime(existingToken.expiresAt);
83
+ if (expiresAt && expiresAt > DateTime.now()) {
84
+ return { ...existingToken, expiresAt } as TToken;
85
+ }
86
+ }
87
+
88
+ return null;
89
+ }
90
+ }