pw-js-api
Version:
A PixelWalker Library, aims to be minimal with support for browsers.
340 lines • 29 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const PWGameClient_js_1 = tslib_1.__importDefault(require("../game/PWGameClient.js"));
const Constants_js_1 = require("../util/Constants.js");
const Misc_js_1 = require("../util/Misc.js");
/**
* Note if you want to join a world, use new PWGameClient() then run .init()
*/
class PWApiClient {
constructor(email, password, options) {
/**
* Account details with email and password, if applicable.
*/
this.account = {
email: "",
password: ""
};
this.loggedIn = false;
this.options = {
endpoints: {
Api: Constants_js_1.Endpoint.Api,
GameHTTP: Constants_js_1.Endpoint.GameHTTP,
GameWS: Constants_js_1.Endpoint.GameWS,
}
};
if (typeof password === "object") {
this.options = (0, Misc_js_1.mergeObjects)(this.options, password);
password = undefined;
}
else if (options)
this.options = (0, Misc_js_1.mergeObjects)(this.options, options);
if (password === undefined) {
this.token = email;
this.loggedIn = true;
return;
}
this.account.email = email;
this.account.password = password;
// this.token = token;
}
authenticate(email, password) {
if (email === undefined) {
if (this.account.email.length === 0 || this.account.password.length === 0)
throw Error("No email/password given.");
email = this.account.email;
password = this.account.password;
}
return this.request(`${this.options.endpoints.Api}/api/collections/users/auth-with-password`, { identity: email, password }, undefined, this.options.endpoints.Api !== Constants_js_1.Endpoint.Api).then(res => {
if ("token" in res) {
this.token = res.token;
this.loggedIn = true;
}
return res;
}); //.then(console.log);
}
/**
* Internal.
*/
getJoinKey(roomType, roomId) {
return this.request(`${this.options.endpoints.Api}/api/joinkey/${roomType}/${roomId}`, undefined, true, this.options.endpoints.Api !== Constants_js_1.Endpoint.Api);
}
/**
* This route is available to take if you chose to create an API client to then join a world, in which case this returns the Game Client instance.
*
* Make sure the API client is already authenticated before calling this.
*
* The 3rd parameter is for if you wish to customise the reconnectability of the game client.
*/
joinWorld(roomId, obj) {
const game = new PWGameClient_js_1.default(this, obj === null || obj === void 0 ? void 0 : obj.gameSettings);
return game.joinWorld(roomId, obj === null || obj === void 0 ? void 0 : obj.joinData);
}
// I feel like this is cursed.
/**
* This will be an empty array if getRoomTypes has never been used successfully at least once.
*/
get roomTypes() {
return PWApiClient.roomTypes;
}
/**
* Non-authenticated. This will refresh the room types each time, so make sure to check if roomTypes is available.
*/
getRoomTypes() {
return PWApiClient.getRoomTypes(this.options.endpoints.GameHTTP);
}
/**
* Non-authenticated. This will refresh the room types each time, so make sure to check if roomTypes is available.
*/
static getRoomTypes(EndpointURL = Constants_js_1.Endpoint.GameHTTP) {
return this.request(`${EndpointURL}/listroomtypes`, undefined, undefined, EndpointURL !== Constants_js_1.Endpoint.GameHTTP)
.then(res => {
PWApiClient.roomTypes = res;
return this.getListBlocks(true);
})
.then(() => {
return PWApiClient.roomTypes;
});
}
/**
* Non-authenticated. Returns the mappings from the game API.
*
* Note: This library also exports "BlockNames" which is an enum containing the block names along with their respective id.
*
* @deprecated Use getListBlocks()
*/
getMappings() {
return PWApiClient.getMappings();
}
/**
* Non-authenticated. Returns the mappings from the game API.
*
* Note: This library also exports "BlockNames" which is an enum containing the block names along with their respective id.
*
* @deprecated Use getListBlocks()
*/
static getMappings() {
return this.request(`${Constants_js_1.Endpoint.GameHTTP}/mappings`);
}
getListBlocks(skipCache = false, toObject) {
// Yes, this actually gets typescript compiler to stop moaning
if (toObject)
return PWApiClient.getListBlocks(skipCache, toObject, this.options.endpoints.GameHTTP);
return PWApiClient.getListBlocks(skipCache, toObject, this.options.endpoints.GameHTTP);
}
static getListBlocks() {
return tslib_1.__awaiter(this, arguments, void 0, function* (skipCache = false, toObject, EndpointURL = Constants_js_1.Endpoint.GameHTTP) {
if (!skipCache) {
if (this.listBlocks !== undefined && !toObject)
return this.listBlocks;
if (this.listBlocksObj !== undefined && toObject)
return this.listBlocksObj;
}
return this.request(`${EndpointURL}/listblocks`, undefined, undefined, EndpointURL !== Constants_js_1.Endpoint.GameHTTP)
.then(res => {
const obj = {};
const arr = []; // PW doesn't sort the returned endpoint data despite data structure means it's perfectly capable
for (let i = 0, len = res.length; i < len; i++) {
obj[res[i].PaletteId.toUpperCase()] = res[i];
arr[res[i].Id] = res[i];
}
this.listBlocksObj = obj;
this.listBlocks = arr;
if (toObject)
return obj;
else
return arr;
});
});
}
getOwnedWorlds(page = 1, perPage = 10, query) {
if (typeof page === "object") {
query = page;
page = 1;
}
return this.request(`${this.options.endpoints.Api}/api/collections/worlds/records?page=${page}&perPage=${perPage}${(0, Misc_js_1.queryToString)(query)}`, undefined, true, this.options.endpoints.Api !== Constants_js_1.Endpoint.Api);
}
getPlayers(page = 1, perPage = 10, query) {
if (typeof page === "object") {
query = page;
page = 1;
}
return PWApiClient.getPlayers(page, perPage, query, this.options.endpoints.Api);
}
static getPlayers(page = 1, perPage = 10, query, EndpointURL = Constants_js_1.Endpoint.Api) {
if (typeof page === "object") {
if (typeof perPage === "string") {
EndpointURL = perPage;
perPage = 10;
}
query = page;
page = 1;
}
return this.request(`${EndpointURL}/api/collections/users/records?page=${page}&perPage=${perPage}${(0, Misc_js_1.queryToString)(query)}`, undefined, undefined, EndpointURL !== Constants_js_1.Endpoint.Api);
}
getPublicWorlds(page = 1, perPage = 10, query) {
if (typeof page === "object") {
query = page;
page = 1;
}
return PWApiClient.getPublicWorlds(page, perPage, query, this.options.endpoints.Api);
}
static getPublicWorlds(page = 1, perPage = 10, query, EndpointURL = Constants_js_1.Endpoint.Api) {
if (typeof page === "object") {
if (typeof perPage === "string") {
EndpointURL = perPage;
perPage = 10;
}
query = page;
page = 1;
}
return this.request(`${EndpointURL}/api/collections/worlds/records?page=${page}&perPage=${perPage}${(0, Misc_js_1.queryToString)(query)}`, undefined, undefined, EndpointURL !== Constants_js_1.Endpoint.Api);
}
getWootedWorlds(page = 1, perPage = 10, query) {
if (typeof page === "object") {
query = page;
page = 1;
}
return PWApiClient.getWootedWorlds(page, perPage, query, this.options.endpoints.Api);
}
static getWootedWorlds(page = 1, perPage = 10, query, EndpointURL = Constants_js_1.Endpoint.Api) {
if (typeof page === "object") {
if (typeof perPage === "string") {
EndpointURL = perPage;
perPage = 10;
}
query = page;
page = 1;
}
return this.request(`${EndpointURL}/api/collections/worlds/records?page=${page}&perPage=${perPage}${(0, Misc_js_1.queryToString)(query)}`, undefined, undefined, EndpointURL !== Constants_js_1.Endpoint.Api);
}
/**
* Returns the lobby result.
*/
getVisibleWorlds() {
return PWApiClient.getVisibleWorlds(this.options.endpoints.GameHTTP);
}
/**
* Returns the lobby result.
*/
static getVisibleWorlds(EndpointURL = Constants_js_1.Endpoint.GameHTTP) {
if (this.roomTypes.length === 0)
throw Error("roomTypes is empty - use getRoomTypes first!");
return this.request(`${EndpointURL}/room/list/${this.roomTypes[0]}`, undefined, undefined, EndpointURL !== Constants_js_1.Endpoint.GameHTTP);
}
/**
* Returns the world, if it exists and is public.
*/
getPublicWorld(id) {
return this.getPublicWorlds(1, 1, { filter: { id } })
.then(res => res.items[0]);
}
/**
* Returns the world, if it exists and is public.
*/
static getPublicWorld(id) {
return this.getPublicWorlds(1, 1, { filter: { id } })
.then(res => res.items[0]);
}
getMinimap(world, toURL = false) {
if (toURL)
return `${this.options.endpoints.Api}/api/files/rhrbt6wqhc4s0cp/${world.id}/${world.minimap}`;
return PWApiClient.getMinimap(world, toURL, this.options.endpoints.Api);
}
static getMinimap(world, toURL = false, EndpointURL = Constants_js_1.Endpoint.Api) {
if (toURL)
return `${EndpointURL}/api/files/rhrbt6wqhc4s0cp/${world.id}/${world.minimap}`;
return this.request(this.getMinimap(world, true, EndpointURL), undefined, undefined, EndpointURL !== Constants_js_1.Endpoint.Api)
.then(res => {
if ("message" in res)
throw Error("Minimap doesn't exist, the world may be unlisted.");
return res;
});
}
/**
* Note that username is cap sensitive, and may require you to use toUppercase
*/
getPlayerByName(username) {
return this.getPlayers(1, 1, { filter: { username } })
.then(res => res.items[0]);
}
/**
* Note that username is cap sensitive, and may require you to use toUppercase
*/
static getPlayerByName(username) {
return this.getPlayers(1, 1, { filter: { username } })
.then(res => res.items[0]);
}
// This doesn't seem to work so I commented it out, not removing it as there might be an oversight idk
// getMessageTypes() {
// return this.request<string[]>(`${Endpoint.GameHTTP}/message_types`)
// .then(res => res instanceof Uint8Array ? [] : res ?? []);
// }
/**
* IMPORTANT: This will return JSON for any responses that have the content-type of json, anything else will be sent back as ArrayBuffer.
* If you're expecting raw bytes, make sure the endpoint is guaranteed to give you that otherwise there isn't a reason.
*
* This requires the manager to be authenticated, it will error if otherwise.
* @param url Requires to be a full URL with endpoint unfortunately. It will throw error if it doesn't match any of the 2 HTTP endpoint URLs.
* @param body If this is passed, the request will become a POST. (If you need to send a POST but has no data, just send an empty object).
* @param token The API token (not join key), this is if you wish to use authenticated API calls without having to instantise an api client yourself.
* @param overrideURL If true, this will skip checking if the URL truly belongs to PW (production wise).
*/
static request(url, body, token, overrideURL = false) {
if (!overrideURL && !(url.startsWith(Constants_js_1.Endpoint.Api) || url.startsWith(Constants_js_1.Endpoint.GameHTTP) || url.startsWith(Constants_js_1.Endpoint.Client + "/atlases/")))
throw Error("URL given does not have the correct endpoint URL, this is for safety.");
const headers = {
// "user-agent": "PW-TS-API/0.0.1"
};
if (typeof token === "string")
headers["authorization"] = token;
if (typeof body === "object")
body = JSON.stringify(body);
let method = "GET";
if (typeof body !== "undefined") {
headers["content-type"] = "application/json";
method = "POST";
}
let status = 0;
return fetch(url, {
headers, method,
body: body
}).then(res => {
var _a;
if (res.status === 403)
throw Error("Forbidden access - token invalid or unauthorised.");
// else if (res.status !== 200) throw Error("")
status = res.status;
if ((_a = res.headers.get("content-type")) === null || _a === void 0 ? void 0 : _a.startsWith("application/json"))
return res.json();
else
return res.arrayBuffer();
})
.then(data => {
if (status > 400)
throw data;
else
return data;
});
}
/**
* IMPORTANT: This will return JSON for any responses that have the content-type of json, anything else will be sent back as Uint8array.
* If you're expecting raw bytes, make sure the endpoint is guaranteed to give you that otherwise there isn't a reason.
*
* This requires the manager to be authenticated, it will error if otherwise.
* @param url Requires to be a full URL with endpoint unfortunately. It will throw error if it doesn't match any of the 2 HTTP endpoint URLs.
* @param body If this is passed, the request will become a POST. (If you need to send a POST but has no data, just send an empty object).
* @param isAuthenticated If true, this will send the token as the header.
* @param overrideURL If true, this will skip checking if the URL truly belongs to PW (production wise).
*/
request(url, body, isAuthenticated = false, overrideURL = false) {
return PWApiClient.request(url, body, isAuthenticated ? this.token : undefined, overrideURL);
}
}
/**
* This will be an empty array if getRoomTypes has never been used successfully at least once.
*/
PWApiClient.roomTypes = [];
exports.default = PWApiClient;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUFdBcGlDbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9saWIvYXBpL1BXQXBpQ2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHNGQUFtRDtBQUduRCx1REFBZ0Q7QUFDaEQsNkNBQThEO0FBRTlEOztHQUVHO0FBQ0gsTUFBcUIsV0FBVztJQXlDNUIsWUFBWSxLQUFhLEVBQUUsUUFBb0MsRUFBRSxPQUEwQjtRQW5DM0Y7O1dBRUc7UUFDSyxZQUFPLEdBQUc7WUFDZCxLQUFLLEVBQUUsRUFBRTtZQUNULFFBQVEsRUFBRSxFQUFFO1NBQ2YsQ0FBQTtRQUlELGFBQVEsR0FBRyxLQUFLLENBQUM7UUEwQmIsSUFBSSxDQUFDLE9BQU8sR0FBRztZQUNYLFNBQVMsRUFBRTtnQkFDUCxHQUFHLEVBQUUsdUJBQVEsQ0FBQyxHQUFHO2dCQUNqQixRQUFRLEVBQUUsdUJBQVEsQ0FBQyxRQUFRO2dCQUMzQixNQUFNLEVBQUUsdUJBQVEsQ0FBQyxNQUFNO2FBQzFCO1NBQ0osQ0FBQTtRQUVELElBQUksT0FBTyxRQUFRLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDL0IsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFBLHNCQUFZLEVBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsQ0FBQztZQUNwRCxRQUFRLEdBQUcsU0FBUyxDQUFDO1FBQ3pCLENBQUM7YUFBTSxJQUFJLE9BQU87WUFBRSxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUEsc0JBQVksRUFBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRXZFLElBQUksUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3pCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1lBQ25CLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO1lBQ3JCLE9BQU87UUFDWCxDQUFDO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEdBQUcsS0FBSyxD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