halo-infinite-api 1.2.2 → 2.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.
- package/README.md +1 -1
- package/dist/authentication/halo-authentication-client.d.ts +4 -5
- package/dist/authentication/halo-authentication-client.js +23 -69
- package/dist/authentication/halo-authentication-client.js.map +1 -1
- package/dist/authentication/xbox-authentication-client.d.ts +9 -9
- package/dist/authentication/xbox-authentication-client.js +80 -63
- package/dist/authentication/xbox-authentication-client.js.map +1 -1
- package/dist/core/halo-infinite-client.d.ts +5 -8
- package/dist/core/halo-infinite-client.js +5 -35
- package/dist/core/halo-infinite-client.js.map +1 -1
- package/dist/core/spartan-token-fetchers/auto-xsts-sartan-token-provider.d.ts +11 -0
- package/dist/core/spartan-token-fetchers/auto-xsts-sartan-token-provider.js +43 -0
- package/dist/core/spartan-token-fetchers/auto-xsts-sartan-token-provider.js.map +1 -0
- package/dist/core/spartan-token-fetchers/index.d.ts +3 -0
- package/dist/core/spartan-token-fetchers/index.js +2 -0
- package/dist/core/spartan-token-fetchers/index.js.map +1 -0
- package/dist/core/spartan-token-fetchers/static-xsts-ticket-token-spartan-token-provider.d.ts +12 -0
- package/dist/core/spartan-token-fetchers/static-xsts-ticket-token-spartan-token-provider.js +26 -0
- package/dist/core/spartan-token-fetchers/static-xsts-ticket-token-spartan-token-provider.js.map +1 -0
- package/dist/core/spartan-token-providers/auto-xsts-spartan-token-provider.d.ts +11 -0
- package/dist/core/spartan-token-providers/auto-xsts-spartan-token-provider.js +32 -0
- package/dist/core/spartan-token-providers/auto-xsts-spartan-token-provider.js.map +1 -0
- package/dist/core/spartan-token-providers/index.d.ts +3 -0
- package/dist/core/spartan-token-providers/index.js +2 -0
- package/dist/core/spartan-token-providers/index.js.map +1 -0
- package/dist/core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.d.ts +12 -0
- package/dist/core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.js +26 -0
- package/dist/core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.js.map +1 -0
- package/dist/core/token-persister.d.ts +4 -0
- package/dist/core/token-persister.js +2 -0
- package/dist/core/token-persister.js.map +1 -0
- package/dist/core/token-persisters/index.d.ts +4 -0
- package/dist/core/token-persisters/index.js +2 -0
- package/dist/core/token-persisters/index.js.map +1 -0
- package/dist/core/token-persisters/local-storage-token-persister.d.ts +2 -0
- package/dist/core/token-persisters/local-storage-token-persister.js +15 -0
- package/dist/core/token-persisters/local-storage-token-persister.js.map +1 -0
- package/dist/core/token-persisters/node-fs-token-persister.d.ts +2 -0
- package/dist/core/token-persisters/node-fs-token-persister.js +24 -0
- package/dist/core/token-persisters/node-fs-token-persister.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/util/expiry-token-cache.d.ts +9 -0
- package/dist/util/expiry-token-cache.js +48 -0
- package/dist/util/expiry-token-cache.js.map +1 -0
- package/dist/util/resolvable-promise.d.ts +8 -0
- package/dist/util/resolvable-promise.js +31 -0
- package/dist/util/resolvable-promise.js.map +1 -0
- package/package.json +3 -2
- package/src/authentication/halo-authentication-client.ts +30 -72
- package/src/authentication/xbox-authentication-client.ts +107 -81
- package/src/core/halo-infinite-client.ts +9 -66
- package/src/core/spartan-token-providers/auto-xsts-spartan-token-provider.ts +55 -0
- package/src/core/spartan-token-providers/index.ts +3 -0
- package/src/core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.ts +36 -0
- package/src/core/token-persisters/index.ts +4 -0
- package/src/core/token-persisters/local-storage-token-persister.ts +15 -0
- package/src/core/token-persisters/node-fs-token-persister.ts +23 -0
- package/src/index.ts +8 -0
- package/src/util/expiry-token-cache.ts +51 -0
- package/src/util/resolvable-promise.ts +32 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/spartan-token-fetchers/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TokenPersister } from "../token-persister";
|
|
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,26 @@
|
|
|
1
|
+
import { HaloAuthenticationClient } from "../../authentication/halo-authentication-client";
|
|
2
|
+
/**
|
|
3
|
+
* A SpartanTokenProvider that fetches uses a pre-fetched XSTS ticket token.
|
|
4
|
+
* Since requests to the Halo API are subject to CORS restrictions a
|
|
5
|
+
* HaloAuthenticationClient can be instantitated with a pre-fetched XSTS ticket
|
|
6
|
+
* and run on a server (such as one provided by the user).
|
|
7
|
+
*/
|
|
8
|
+
export class StaticXstsTicketTokenSpartanTokenProvider {
|
|
9
|
+
getSpartanToken;
|
|
10
|
+
constructor(xstsTicketToken, tokenPersister) {
|
|
11
|
+
const haloAuthClient = new HaloAuthenticationClient(() => xstsTicketToken, async () => {
|
|
12
|
+
if (tokenPersister) {
|
|
13
|
+
return await tokenPersister.load("halo.authToken");
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}, async (token) => {
|
|
19
|
+
if (tokenPersister) {
|
|
20
|
+
await tokenPersister.save("halo.authToken", token);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
this.getSpartanToken = () => haloAuthClient.getSpartanToken();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=static-xsts-ticket-token-spartan-token-provider.js.map
|
package/dist/core/spartan-token-fetchers/static-xsts-ticket-token-spartan-token-provider.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-xsts-ticket-token-spartan-token-provider.js","sourceRoot":"","sources":["../../../src/core/spartan-token-fetchers/static-xsts-ticket-token-spartan-token-provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,iDAAiD,CAAC;AAG3F;;;;;GAKG;AAEH,MAAM,OAAO,yCAAyC;IAGpC,eAAe,CAAwB;IAEvD,YAAY,eAAuB,EAAE,cAA+B;QAClE,MAAM,cAAc,GAAG,IAAI,wBAAwB,CACjD,GAAG,EAAE,CAAC,eAAe,EACrB,KAAK,IAAI,EAAE;YACT,IAAI,cAAc,EAAE;gBAClB,OAAO,MAAM,cAAc,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;aACpD;iBAAM;gBACL,OAAO,IAAI,CAAC;aACb;QACH,CAAC,EACD,KAAK,EAAE,KAAK,EAAE,EAAE;YACd,IAAI,cAAc,EAAE;gBAClB,MAAM,cAAc,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;aACpD;QACH,CAAC,CACF,CAAC;QAEF,IAAI,CAAC,eAAe,GAAG,GAAG,EAAE,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC;IAChE,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(clientId: string, redirectUri: string, getAuthCode: (authorizeUrl: string) => Promise<string>, tokenPersister?: TokenPersister);
|
|
11
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { RelyingParty, XboxAuthenticationClient, } from "../../authentication/xbox-authentication-client";
|
|
2
|
+
import { HaloAuthenticationClient } from "../../authentication/halo-authentication-client";
|
|
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 class AutoXstsSpartanTokenProvider {
|
|
9
|
+
getSpartanToken;
|
|
10
|
+
constructor(clientId, redirectUri, getAuthCode, tokenPersister) {
|
|
11
|
+
const xboxAuthClient = new XboxAuthenticationClient(clientId, redirectUri, getAuthCode, tokenPersister);
|
|
12
|
+
const haloAuthClient = new HaloAuthenticationClient(async () => {
|
|
13
|
+
const accessToken = await xboxAuthClient.getAccessToken();
|
|
14
|
+
const userToken = await xboxAuthClient.getUserToken(accessToken);
|
|
15
|
+
const xstsTicket = await xboxAuthClient.getXstsTicket(userToken, RelyingParty.Halo);
|
|
16
|
+
return xstsTicket.Token;
|
|
17
|
+
}, async () => {
|
|
18
|
+
if (tokenPersister) {
|
|
19
|
+
return await tokenPersister.load("halo.authToken");
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}, async (token) => {
|
|
25
|
+
if (tokenPersister) {
|
|
26
|
+
await tokenPersister.save("halo.authToken", token);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
this.getSpartanToken = () => haloAuthClient.getSpartanToken();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# 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/spartan-token-providers/auto-xsts-spartan-token-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,wBAAwB,GACzB,MAAM,iDAAiD,CAAC;AAEzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,iDAAiD,CAAC;AAG3F;;;;GAIG;AACH,MAAM,OAAO,4BAA4B;IACvB,eAAe,CAAwB;IAEvD,YACE,QAAgB,EAChB,WAAmB,EACnB,WAAsD,EACtD,cAA+B;QAE/B,MAAM,cAAc,GAAG,IAAI,wBAAwB,CACjD,QAAQ,EACR,WAAW,EACX,WAAW,EACX,cAAc,CACf,CAAC;QACF,MAAM,cAAc,GAAG,IAAI,wBAAwB,CACjD,KAAK,IAAI,EAAE;YACT,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,cAAc,EAAE,CAAC;YAC1D,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;YACjE,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,aAAa,CACnD,SAAS,EACT,YAAY,CAAC,IAAI,CAClB,CAAC;YACF,OAAO,UAAU,CAAC,KAAK,CAAC;QAC1B,CAAC,EACD,KAAK,IAAI,EAAE;YACT,IAAI,cAAc,EAAE;gBAClB,OAAO,MAAM,cAAc,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;aACpD;iBAAM;gBACL,OAAO,IAAI,CAAC;aACb;QACH,CAAC,EACD,KAAK,EAAE,KAAK,EAAE,EAAE;YACd,IAAI,cAAc,EAAE;gBAClB,MAAM,cAAc,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;aACpD;QACH,CAAC,CACF,CAAC;QAEF,IAAI,CAAC,eAAe,GAAG,GAAG,EAAE,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC;IAChE,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/spartan-token-providers/index.ts"],"names":[],"mappings":""}
|
package/dist/core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.d.ts
ADDED
|
@@ -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,26 @@
|
|
|
1
|
+
import { HaloAuthenticationClient } from "../../authentication/halo-authentication-client";
|
|
2
|
+
/**
|
|
3
|
+
* A SpartanTokenProvider that fetches uses a pre-fetched XSTS ticket token.
|
|
4
|
+
* Since requests to the Halo API are subject to CORS restrictions a
|
|
5
|
+
* HaloAuthenticationClient can be instantitated with a pre-fetched XSTS ticket
|
|
6
|
+
* and run on a server (such as one provided by the user).
|
|
7
|
+
*/
|
|
8
|
+
export class StaticXstsTicketTokenSpartanTokenProvider {
|
|
9
|
+
getSpartanToken;
|
|
10
|
+
constructor(xstsTicketToken, tokenPersister) {
|
|
11
|
+
const haloAuthClient = new HaloAuthenticationClient(() => xstsTicketToken, async () => {
|
|
12
|
+
if (tokenPersister) {
|
|
13
|
+
return await tokenPersister.load("halo.authToken");
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}, async (token) => {
|
|
19
|
+
if (tokenPersister) {
|
|
20
|
+
await tokenPersister.save("halo.authToken", token);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
this.getSpartanToken = () => haloAuthClient.getSpartanToken();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=static-xsts-ticket-token-spartan-token-provider.js.map
|
package/dist/core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-xsts-ticket-token-spartan-token-provider.js","sourceRoot":"","sources":["../../../src/core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,iDAAiD,CAAC;AAG3F;;;;;GAKG;AAEH,MAAM,OAAO,yCAAyC;IAGpC,eAAe,CAAwB;IAEvD,YAAY,eAAuB,EAAE,cAA+B;QAClE,MAAM,cAAc,GAAG,IAAI,wBAAwB,CACjD,GAAG,EAAE,CAAC,eAAe,EACrB,KAAK,IAAI,EAAE;YACT,IAAI,cAAc,EAAE;gBAClB,OAAO,MAAM,cAAc,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;aACpD;iBAAM;gBACL,OAAO,IAAI,CAAC;aACb;QACH,CAAC,EACD,KAAK,EAAE,KAAK,EAAE,EAAE;YACd,IAAI,cAAc,EAAE;gBAClB,MAAM,cAAc,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;aACpD;QACH,CAAC,CACF,CAAC;QAEF,IAAI,CAAC,eAAe,GAAG,GAAG,EAAE,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC;IAChE,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-persister.js","sourceRoot":"","sources":["../../src/core/token-persister.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/token-persisters/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const localStorageTokenPersister = {
|
|
2
|
+
load: (tokenName) => {
|
|
3
|
+
const json = localStorage.getItem(tokenName);
|
|
4
|
+
if (json) {
|
|
5
|
+
return JSON.parse(json);
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
save: (tokenName, token) => {
|
|
12
|
+
localStorage.setItem(tokenName, JSON.stringify(token));
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=local-storage-token-persister.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-storage-token-persister.js","sourceRoot":"","sources":["../../../src/core/token-persisters/local-storage-token-persister.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,0BAA0B,GAAmB;IACxD,IAAI,EAAE,CAAC,SAAS,EAAE,EAAE;QAClB,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,IAAI,EAAE;YACR,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SACzB;aAAM;YACL,OAAO,IAAI,CAAC;SACb;IACH,CAAC;IACD,IAAI,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;QACzB,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACzD,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
export const nodeFsTokenPersister = {
|
|
3
|
+
load: async (tokenName) => {
|
|
4
|
+
const storageFileName = `./tokens/${tokenName}`;
|
|
5
|
+
try {
|
|
6
|
+
const json = await fs.readFile(storageFileName, { encoding: "utf-8" });
|
|
7
|
+
return JSON.parse(json);
|
|
8
|
+
}
|
|
9
|
+
catch (e) {
|
|
10
|
+
if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
throw e;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
save: async (tokenName, token) => {
|
|
19
|
+
const storageFileName = `./tokens/${tokenName}`;
|
|
20
|
+
await fs.mkdir(`./tokens/`, { recursive: true });
|
|
21
|
+
await fs.writeFile(storageFileName, JSON.stringify(token));
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=node-fs-token-persister.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-fs-token-persister.js","sourceRoot":"","sources":["../../../src/core/token-persisters/node-fs-token-persister.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAG7B,MAAM,CAAC,MAAM,oBAAoB,GAAmB;IAClD,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;QACxB,MAAM,eAAe,GAAG,YAAY,SAAS,EAAE,CAAC;QAChD,IAAI;YACF,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;YACvE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SACzB;QAAC,OAAO,CAAC,EAAE;YACV,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE;gBACpE,OAAO,IAAI,CAAC;aACb;iBAAM;gBACL,MAAM,CAAC,CAAC;aACT;SACF;IACH,CAAC;IACD,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE;QAC/B,MAAM,eAAe,GAAG,YAAY,SAAS,EAAE,CAAC;QAChD,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,MAAM,EAAE,CAAC,SAAS,CAAC,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7D,CAAC;CACF,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { HaloInfiniteClient, AssetKindTypeMap, } from "./core/halo-infinite-client";
|
|
2
|
+
export { XboxAuthenticationClient, RelyingParty, } from "./authentication/xbox-authentication-client";
|
|
2
3
|
export { Playlist } from "./models/halo-infinite/playlist";
|
|
3
4
|
export { PlaylistCsrContainer } from "./models/halo-infinite/playlist-csr-container";
|
|
4
5
|
export { UserInfo } from "./models/halo-infinite/user-info";
|
|
@@ -14,3 +15,7 @@ export { MatchOutcome } from "./models/halo-infinite/match-outcome";
|
|
|
14
15
|
export { MatchSkill } from "./models/halo-infinite/match-skill";
|
|
15
16
|
export { AssetVersionLink } from "./models/halo-infinite/asset-version-link";
|
|
16
17
|
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";
|
|
21
|
+
export { TokenPersister } from "./core/token-persisters";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export { HaloInfiniteClient, } from "./core/halo-infinite-client";
|
|
2
|
+
export { XboxAuthenticationClient, RelyingParty, } from "./authentication/xbox-authentication-client";
|
|
2
3
|
export { MatchType } from "./models/halo-infinite/match-type";
|
|
3
4
|
export { GameVariantCategory } from "./models/halo-infinite/game-variant-category";
|
|
4
5
|
export { AssetKind } from "./models/halo-infinite/asset-kind";
|
|
5
6
|
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";
|
|
6
9
|
//# 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;
|
|
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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DateTime } from "luxon";
|
|
2
|
+
export declare class ExpiryTokenCache<TToken extends {
|
|
3
|
+
expiresAt: DateTime;
|
|
4
|
+
}, TArgs extends any[]> {
|
|
5
|
+
private readonly tokenFetcher;
|
|
6
|
+
private tokenFetchPromise;
|
|
7
|
+
constructor(tokenFetcher: (...args: TArgs) => Promise<TToken>);
|
|
8
|
+
getToken(...args: TArgs): Promise<TToken>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { DateTime } from "luxon";
|
|
2
|
+
import { ResolvablePromise } from "./resolvable-promise";
|
|
3
|
+
export class ExpiryTokenCache {
|
|
4
|
+
tokenFetcher;
|
|
5
|
+
tokenFetchPromise = undefined;
|
|
6
|
+
constructor(tokenFetcher) {
|
|
7
|
+
this.tokenFetcher = tokenFetcher;
|
|
8
|
+
}
|
|
9
|
+
// TODO: Compare args and separate cache entries based on input
|
|
10
|
+
async getToken(...args) {
|
|
11
|
+
if (this.tokenFetchPromise) {
|
|
12
|
+
// Someone either already has a token or is in the process of getting one
|
|
13
|
+
// Wait for them to finish, then check for validity
|
|
14
|
+
const currentToken = await this.tokenFetchPromise;
|
|
15
|
+
if (currentToken.expiresAt > DateTime.now()) {
|
|
16
|
+
// Current token is valid, return it
|
|
17
|
+
return currentToken;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
// Current token expired, start a new promise
|
|
21
|
+
this.tokenFetchPromise = new ResolvablePromise();
|
|
22
|
+
try {
|
|
23
|
+
const newToken = await this.tokenFetcher(...args);
|
|
24
|
+
this.tokenFetchPromise.resolve(newToken);
|
|
25
|
+
return newToken;
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
this.tokenFetchPromise.reject(e);
|
|
29
|
+
throw e;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// No one has a token, start a new promise
|
|
35
|
+
this.tokenFetchPromise = new ResolvablePromise();
|
|
36
|
+
try {
|
|
37
|
+
const newToken = await this.tokenFetcher(...args);
|
|
38
|
+
this.tokenFetchPromise.resolve(newToken);
|
|
39
|
+
return newToken;
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
this.tokenFetchPromise.reject(e);
|
|
43
|
+
throw e;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=expiry-token-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expiry-token-cache.js","sourceRoot":"","sources":["../../src/util/expiry-token-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,OAAO,gBAAgB;IAOR;IAHX,iBAAiB,GAA0C,SAAS,CAAC;IAE7E,YACmB,YAAiD;QAAjD,iBAAY,GAAZ,YAAY,CAAqC;IACjE,CAAC;IAEJ,+DAA+D;IAC/D,KAAK,CAAC,QAAQ,CAAC,GAAG,IAAW;QAC3B,IAAI,IAAI,CAAC,iBAAiB,EAAE;YAC1B,yEAAyE;YACzE,mDAAmD;YACnD,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC;YAElD,IAAI,YAAY,CAAC,SAAS,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE;gBAC3C,oCAAoC;gBACpC,OAAO,YAAY,CAAC;aACrB;iBAAM;gBACL,6CAA6C;gBAC7C,IAAI,CAAC,iBAAiB,GAAG,IAAI,iBAAiB,EAAU,CAAC;gBAEzD,IAAI;oBACF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC;oBAClD,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;oBACzC,OAAO,QAAQ,CAAC;iBACjB;gBAAC,OAAO,CAAC,EAAE;oBACV,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;oBACjC,MAAM,CAAC,CAAC;iBACT;aACF;SACF;aAAM;YACL,0CAA0C;YAC1C,IAAI,CAAC,iBAAiB,GAAG,IAAI,iBAAiB,EAAU,CAAC;YAEzD,IAAI;gBACF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC;gBAClD,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACzC,OAAO,QAAQ,CAAC;aACjB;YAAC,OAAO,CAAC,EAAE;gBACV,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACjC,MAAM,CAAC,CAAC;aACT;SACF;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare class ResolvablePromise<TReturn> extends Promise<TReturn> {
|
|
2
|
+
isCompleted: boolean;
|
|
3
|
+
readonly resolve: (value: TReturn | PromiseLike<TReturn>) => void;
|
|
4
|
+
readonly reject: (reason?: unknown) => void;
|
|
5
|
+
constructor();
|
|
6
|
+
static get [Symbol.species](): PromiseConstructor;
|
|
7
|
+
get [Symbol.toStringTag](): string;
|
|
8
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export class ResolvablePromise extends Promise {
|
|
2
|
+
isCompleted = false;
|
|
3
|
+
resolve;
|
|
4
|
+
reject;
|
|
5
|
+
constructor() {
|
|
6
|
+
let resolve;
|
|
7
|
+
let reject;
|
|
8
|
+
super((res, rej) => {
|
|
9
|
+
resolve = res;
|
|
10
|
+
reject = rej;
|
|
11
|
+
});
|
|
12
|
+
this.resolve = (v) => {
|
|
13
|
+
this.isCompleted = true;
|
|
14
|
+
return resolve(v);
|
|
15
|
+
};
|
|
16
|
+
this.reject = (r) => {
|
|
17
|
+
this.isCompleted = true;
|
|
18
|
+
return reject(r);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// you can also use Symbol.species in order to
|
|
22
|
+
// return a Promise for then/catch/finally
|
|
23
|
+
static get [Symbol.species]() {
|
|
24
|
+
return Promise;
|
|
25
|
+
}
|
|
26
|
+
// Promise overrides his Symbol.toStringTag
|
|
27
|
+
get [Symbol.toStringTag]() {
|
|
28
|
+
return "ResolvablePromise";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=resolvable-promise.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvable-promise.js","sourceRoot":"","sources":["../../src/util/resolvable-promise.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,iBAA2B,SAAQ,OAAgB;IAC9D,WAAW,GAAG,KAAK,CAAC;IACX,OAAO,CAAkD;IACzD,MAAM,CAA6B;IAC5C;QACE,IAAI,OAAyD,CAAC;QAC9D,IAAI,MAAmC,CAAC;QACxC,KAAK,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACjB,OAAO,GAAG,GAAG,CAAC;YACd,MAAM,GAAG,GAAG,CAAC;QACf,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,EAAE;YACnB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC,CAAC;QACF,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE;YAClB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;YACxB,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC;IAED,8CAA8C;IAC9C,0CAA0C;IAC1C,MAAM,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;QACzB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,2CAA2C;IAC3C,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACtB,OAAO,mBAAmB,CAAC;IAC7B,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "halo-infinite-api",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "2.0.0",
|
|
5
5
|
"description": "An NPM package for accessing the official Halo Infinite API.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"scripts": {
|
|
@@ -34,8 +34,9 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"axios": "^1.3.5",
|
|
37
|
+
"expiry-map": "^2.0.0",
|
|
37
38
|
"luxon": "^3.3.0",
|
|
38
|
-
"pkce-challenge": "^
|
|
39
|
+
"pkce-challenge": "^3.1.0",
|
|
39
40
|
"simple-oauth2": "^5.0.0"
|
|
40
41
|
},
|
|
41
42
|
"publishConfig": {
|
|
@@ -3,6 +3,7 @@ import { DateTime } from "luxon";
|
|
|
3
3
|
import type { SpartanToken } from "../models/spartan-token";
|
|
4
4
|
import type { SpartanTokenRequest } from "../models/spartan-token-request";
|
|
5
5
|
import { coalesceDateTime } from "../util/date-time";
|
|
6
|
+
import { ExpiryTokenCache } from "../util/expiry-token-cache";
|
|
6
7
|
|
|
7
8
|
export interface Token {
|
|
8
9
|
token: string;
|
|
@@ -10,81 +11,21 @@ export interface Token {
|
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export class HaloAuthenticationClient {
|
|
13
|
-
private
|
|
14
|
+
private spartanTokenCache = new ExpiryTokenCache(async () => {
|
|
15
|
+
const persistedToken = await this.loadToken();
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
) {}
|
|
23
|
-
|
|
24
|
-
public async getSpartanToken() {
|
|
25
|
-
if (this.currentTokenPromise) {
|
|
26
|
-
// Someone either already has a token or is in the process of getting one
|
|
27
|
-
// Wait for them to finish, then check for validity
|
|
28
|
-
const currentToken = await this.currentTokenPromise;
|
|
29
|
-
|
|
30
|
-
if (currentToken.expiresAt > DateTime.now()) {
|
|
31
|
-
// Current token is valid, return it
|
|
32
|
-
return currentToken.token;
|
|
33
|
-
} else {
|
|
34
|
-
// Current token expired, start a new promise
|
|
35
|
-
let promiseResolver!: (token: Token) => void;
|
|
36
|
-
let promiseRejector!: (error: unknown) => void;
|
|
37
|
-
this.currentTokenPromise = new Promise<Token>((resolve, reject) => {
|
|
38
|
-
promiseResolver = resolve;
|
|
39
|
-
promiseRejector = reject;
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
const xstsToken = await this.fetchXstsToken();
|
|
44
|
-
const newToken = await this.fetchSpartanToken(xstsToken);
|
|
45
|
-
promiseResolver(newToken);
|
|
46
|
-
await this.saveToken(newToken);
|
|
47
|
-
return newToken.token;
|
|
48
|
-
} catch (e) {
|
|
49
|
-
promiseRejector(e);
|
|
50
|
-
throw e;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
// We are the first caller, create a promise to block subsequent callers
|
|
55
|
-
let promiseResolver!: (token: Token) => void;
|
|
56
|
-
let promiseRejector!: (error: unknown) => void;
|
|
57
|
-
this.currentTokenPromise = new Promise<Token>((resolve, reject) => {
|
|
58
|
-
promiseResolver = resolve;
|
|
59
|
-
promiseRejector = reject;
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
const loadedToken = await this.loadToken();
|
|
64
|
-
const currentToken = {
|
|
65
|
-
token: loadedToken?.token ?? "",
|
|
66
|
-
expiresAt: coalesceDateTime(loadedToken?.expiresAt),
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
if (currentToken.expiresAt && currentToken.expiresAt > DateTime.now()) {
|
|
70
|
-
// Current token is valid, return it and alert other callers if applicable
|
|
71
|
-
promiseResolver(currentToken as Token);
|
|
72
|
-
return currentToken.token;
|
|
73
|
-
} else {
|
|
74
|
-
const xstsToken = await this.fetchXstsToken();
|
|
75
|
-
const newToken = await this.fetchSpartanToken(xstsToken);
|
|
76
|
-
promiseResolver(newToken);
|
|
77
|
-
await this.saveToken(newToken);
|
|
78
|
-
return newToken.token;
|
|
79
|
-
}
|
|
80
|
-
} catch (e) {
|
|
81
|
-
promiseRejector(e);
|
|
82
|
-
throw e;
|
|
17
|
+
if (persistedToken?.expiresAt) {
|
|
18
|
+
const currentToken = {
|
|
19
|
+
token: persistedToken.token,
|
|
20
|
+
expiresAt: coalesceDateTime(persistedToken.expiresAt) as DateTime,
|
|
21
|
+
};
|
|
22
|
+
if (currentToken.expiresAt && currentToken.expiresAt > DateTime.now()) {
|
|
23
|
+
return currentToken;
|
|
83
24
|
}
|
|
84
25
|
}
|
|
85
|
-
}
|
|
86
26
|
|
|
87
|
-
|
|
27
|
+
const xstsToken = await this.fetchXstsToken();
|
|
28
|
+
|
|
88
29
|
const tokenRequest: SpartanTokenRequest = {
|
|
89
30
|
Audience: "urn:343:s3:services",
|
|
90
31
|
MinVersion: "4",
|
|
@@ -106,9 +47,26 @@ export class HaloAuthenticationClient {
|
|
|
106
47
|
},
|
|
107
48
|
}
|
|
108
49
|
);
|
|
109
|
-
|
|
50
|
+
|
|
51
|
+
const newToken = {
|
|
110
52
|
token: response.data.SpartanToken,
|
|
111
53
|
expiresAt: DateTime.fromISO(response.data.ExpiresUtc.ISO8601Date),
|
|
112
54
|
};
|
|
55
|
+
await this.saveToken(newToken);
|
|
56
|
+
return newToken;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
constructor(
|
|
60
|
+
private readonly fetchXstsToken: () => Promise<string> | string,
|
|
61
|
+
private readonly loadToken: () => Promise<{
|
|
62
|
+
token: string;
|
|
63
|
+
expiresAt: unknown;
|
|
64
|
+
} | null>,
|
|
65
|
+
private readonly saveToken: (token: Token) => Promise<void>
|
|
66
|
+
) {}
|
|
67
|
+
|
|
68
|
+
public async getSpartanToken() {
|
|
69
|
+
const { token } = await this.spartanTokenCache.getToken();
|
|
70
|
+
return token;
|
|
113
71
|
}
|
|
114
72
|
}
|