@fnlb-project/fnbr
Version:
A library to interact with Epic Games' Fortnite HTTP and XMPP services
166 lines • 7.75 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const Base_1 = tslib_1.__importDefault(require("../Base"));
const AuthenticationMissingError_1 = tslib_1.__importDefault(require("../exceptions/AuthenticationMissingError"));
const constants_1 = require("../../resources/constants");
const EpicgamesAPIError_1 = tslib_1.__importDefault(require("../exceptions/EpicgamesAPIError"));
/**
* Represents the client's HTTP manager
* @private
*/
class HTTP extends Base_1.default {
/**
* @param client The main client
*/
constructor(client) {
super(client);
}
/**
* Sends an HTTP request
* @param config The request config
* @param retries How many times this request has been retried (5xx errors)
*/
async request(config, retries = 0) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
const reqStartTime = Date.now();
const { url, method = 'GET', headers = {}, data, responseType } = config;
let body;
const finalHeaders = {
'Accept-Language': this.client.config.language,
...this.client.config.defaultHeaders,
...headers,
};
if (data) {
if (headers['Content-Type'] === 'application/x-www-form-urlencoded') {
body = data;
finalHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
}
else if (headers['Content-Type'] === 'application/json' || (typeof data === 'object' && !(data instanceof ArrayBuffer))) {
body = JSON.stringify(data);
finalHeaders['Content-Type'] = 'application/json';
}
else {
body = data;
}
}
try {
const response = await ((_a = this.client.config.restFetchAdapter) !== null && _a !== void 0 ? _a : fetch)(this.client.config.restTransformURL ? this.client.config.restTransformURL(url) : url, {
method,
headers: finalHeaders,
body,
});
const reqDuration = ((Date.now() - reqStartTime) / 1000);
this.client.debug(`${method.toUpperCase()} ${url} (${reqDuration.toFixed(2)}s): `
+ `${response.status} ${response.statusText}`, 'http');
if (!response.ok) {
let errorData = null;
let responseBody = '';
try {
if ((_b = response.headers.get('content-type')) === null || _b === void 0 ? void 0 : _b.includes('application/json')) {
errorData = await response.json();
}
else if ((_c = response.headers.get('content-type')) === null || _c === void 0 ? void 0 : _c.includes('text')) {
responseBody = await response.text();
}
else {
responseBody = await response.text();
}
}
catch {
}
const errorMessage = `HTTP ${response.status}: ${method} ${url}: ${responseBody}`;
const error = new Error(errorMessage);
Object.assign(error, {
response,
errorData,
responseBody,
});
throw error;
}
const contentType = response.headers.get("Content-Type") || "";
if (responseType === 'arraybuffer') {
return await response.arrayBuffer();
}
else if (responseType === 'blob' || contentType.includes("application/octet-stream")) {
return await response.blob();
}
else if (responseType === 'json' || contentType.includes("application/json")) {
return await response.json();
}
else if (responseType === 'formdata' || contentType.includes("multipart/form-data")) {
return await response.formData();
}
else if (contentType.includes("image/")) {
const blob = await response.blob();
return URL.createObjectURL(blob);
}
else if (contentType.includes("application/x-www-form-urlencoded")) {
const text = await response.text();
return new URLSearchParams(text);
}
else {
return await response.text();
}
}
catch (err) {
const reqDuration = ((Date.now() - reqStartTime) / 1000);
this.client.debug(`${method.toUpperCase()} ${url} (${reqDuration.toFixed(2)}s): ${err.name} - ${err.message}`, 'http');
if (((_e = (_d = err.response) === null || _d === void 0 ? void 0 : _d.status) === null || _e === void 0 ? void 0 : _e.toString().startsWith('5')) && retries < this.client.config.restRetryLimit) {
return this.request(config, retries + 1);
}
if (((_f = err.response) === null || _f === void 0 ? void 0 : _f.status) === 429 ||
((_g = err.errorData) === null || _g === void 0 ? void 0 : _g.errorCode) === 'errors.com.epicgames.common.throttled') {
const match = (_j = (_h = err.errorData) === null || _h === void 0 ? void 0 : _h.errorMessage) === null || _j === void 0 ? void 0 : _j.match(/in (\d+) second/);
const retryAfter = parseInt(((_k = err.response) === null || _k === void 0 ? void 0 : _k.headers.get('Retry-After')) ||
((_m = (_l = err.errorData) === null || _l === void 0 ? void 0 : _l.messageVars) === null || _m === void 0 ? void 0 : _m[0]) ||
(match === null || match === void 0 ? void 0 : match[1]) ||
'0', 10);
if (!Number.isNaN(retryAfter)) {
const sleepTimeout = retryAfter * 1000 + 500;
await new Promise((res) => setTimeout(res, sleepTimeout));
return this.request(config, retries);
}
}
throw err;
}
}
/**
* Sends an HTTP request to the Fortnite API
* @param config The request config
* @param includeAuthentication Whether to include authentication
* @throws {EpicgamesAPIError}
*/
async epicgamesRequest(config, auth) {
var _a, _b, _c;
if (auth) {
const authSession = this.client.auth.sessions.get(auth);
if (!authSession)
throw new AuthenticationMissingError_1.default(auth);
await authSession.refreshLock.wait();
}
try {
return await this.request({
...config,
headers: {
...config.headers,
...(auth && {
Authorization: `bearer ${this.client.auth.sessions.get(auth).accessToken}`,
}),
},
});
}
catch (err) {
if (auth && constants_1.invalidTokenCodes.includes((_a = err.errorData) === null || _a === void 0 ? void 0 : _a.errorCode)) {
await this.client.auth.sessions.get(auth).refresh();
return this.epicgamesRequest(config, auth);
}
if (typeof ((_b = err.errorData) === null || _b === void 0 ? void 0 : _b.errorCode) === 'string') {
throw new EpicgamesAPIError_1.default(err.errorData, config, ((_c = err.response) === null || _c === void 0 ? void 0 : _c.status) || 500);
}
throw err;
}
}
}
exports.default = HTTP;
//# sourceMappingURL=HTTP.js.map