UNPKG

fnbr

Version:

A library to interact with Epic Games' Fortnite HTTP and XMPP services

415 lines 18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const collection_1 = require("@discordjs/collection"); const async_queue_1 = require("@sapphire/async-queue"); const util_1 = require("util"); const Endpoints_1 = tslib_1.__importDefault(require("../../../resources/Endpoints")); const FriendNotFoundError_1 = tslib_1.__importDefault(require("../../exceptions/FriendNotFoundError")); const PartyAlreadyJoinedError_1 = tslib_1.__importDefault(require("../../exceptions/PartyAlreadyJoinedError")); const PartyMaxSizeReachedError_1 = tslib_1.__importDefault(require("../../exceptions/PartyMaxSizeReachedError")); const PartyMemberNotFoundError_1 = tslib_1.__importDefault(require("../../exceptions/PartyMemberNotFoundError")); const PartyPermissionError_1 = tslib_1.__importDefault(require("../../exceptions/PartyPermissionError")); const ClientPartyMeta_1 = tslib_1.__importDefault(require("./ClientPartyMeta")); const Party_1 = tslib_1.__importDefault(require("./Party")); const PartyChat_1 = tslib_1.__importDefault(require("./PartyChat")); const SentPartyInvitation_1 = tslib_1.__importDefault(require("./SentPartyInvitation")); const enums_1 = require("../../../resources/enums"); const EpicgamesAPIError_1 = tslib_1.__importDefault(require("../../exceptions/EpicgamesAPIError")); const deprecationNotOverXmppAnymore = 'Party Chat is not done over XMPP anymore, this function will be removed in a future version'; /** * Represents a party that the client is a member of */ class ClientParty extends Party_1.default { /** * @param client The main client * @param data The party's data */ constructor(client, data) { super(client, data instanceof Party_1.default ? data.toObject() : data); this.hiddenMemberIds = new Set(); this.pendingMemberConfirmations = new collection_1.Collection(); this.patchQueue = new async_queue_1.AsyncQueue(); this.chat = new PartyChat_1.default(this.client, this); this.meta = new ClientPartyMeta_1.default(this, data instanceof Party_1.default ? data.meta.schema : data.meta); } /** * Returns the client's party member */ get me() { return this.members.get(this.client.user.self.id); } /** * Whether the party is private */ get isPrivate() { return this.config.privacy.partyType === 'Private'; } /** * Leaves this party * @param createNew Whether a new party should be created * @throws {EpicgamesAPIError} */ async leave(createNew = true) { var _a; this.client.partyLock.lock(); try { await this.client.http.epicgamesRequest({ method: 'DELETE', url: `${Endpoints_1.default.BR_PARTY}/parties/${this.id}/members/${(_a = this.me) === null || _a === void 0 ? void 0 : _a.id}`, }, enums_1.AuthSessionStoreKey.Fortnite); } catch (e) { this.client.partyLock.unlock(); throw e; } this.client.party = undefined; this.client.partyLock.unlock(); if (createNew) await this.client.createParty(); } /** * Sends a party patch to Epicgames' servers * @param updated The updated schema * @param deleted The deleted schema keys * @throws {PartyPermissionError} You're not the leader of this party * @throws {EpicgamesAPIError} */ async sendPatch(updated, deleted = []) { await this.patchQueue.wait(); try { await this.client.http.epicgamesRequest({ method: 'PATCH', url: `${Endpoints_1.default.BR_PARTY}/parties/${this.id}`, headers: { 'Content-Type': 'application/json', }, data: { config: { join_confirmation: this.config.joinConfirmation, joinability: this.config.joinability, max_size: this.config.maxSize, discoverability: this.config.discoverability, }, meta: { delete: deleted, update: updated || this.meta.schema, }, party_state_overridden: {}, party_privacy_type: this.config.joinability, party_type: this.config.type, party_sub_type: this.config.subType, max_number_of_members: this.config.maxSize, invite_ttl_seconds: this.config.inviteTtl, revision: this.revision, }, }, enums_1.AuthSessionStoreKey.Fortnite); } catch (e) { if (e instanceof EpicgamesAPIError_1.default && e.code === 'errors.com.epicgames.social.party.stale_revision') { this.revision = parseInt(e.messageVars[1], 10); this.patchQueue.shift(); return this.sendPatch(updated); } this.patchQueue.shift(); if (e instanceof EpicgamesAPIError_1.default && e.code === 'errors.com.epicgames.social.party.party_change_forbidden') { throw new PartyPermissionError_1.default(); } throw e; } this.revision += 1; this.patchQueue.shift(); return undefined; } /** * Kicks a member from this party * @param member The member that should be kicked * @throws {PartyPermissionError} The client is not the leader of the party * @throws {PartyMemberNotFoundError} The party member wasn't found * @throws {EpicgamesAPIError} */ async kick(member) { if (!this.me.isLeader) throw new PartyPermissionError_1.default(); const partyMember = this.members.find((m) => m.displayName === member || m.id === member); if (!partyMember) throw new PartyMemberNotFoundError_1.default(member); try { await this.client.http.epicgamesRequest({ method: 'DELETE', url: `${Endpoints_1.default.BR_PARTY}/parties/${this.id}/members/${partyMember.id}`, }, enums_1.AuthSessionStoreKey.Fortnite); } catch (e) { if (e instanceof EpicgamesAPIError_1.default && e.code === 'errors.com.epicgames.social.party.party_change_forbidden') { throw new PartyPermissionError_1.default(); } throw e; } } /** * Sends a party invitation to a friend * @param friend The friend that will receive the invitation * @throws {FriendNotFoundError} The user is not friends with the client * @throws {PartyAlreadyJoinedError} The user is already a member of this party * @throws {PartyMaxSizeReachedError} The party reached its max size * @throws {EpicgamesAPIError} */ async invite(friend) { const resolvedFriend = this.client.friend.list.find((f) => f.id === friend || f.displayName === friend); if (!resolvedFriend) throw new FriendNotFoundError_1.default(friend); if (this.members.has(resolvedFriend.id)) throw new PartyAlreadyJoinedError_1.default(); if (this.size === this.maxSize) throw new PartyMaxSizeReachedError_1.default(); let invite; if (this.isPrivate) { invite = await this.client.http.epicgamesRequest({ method: 'POST', url: `${Endpoints_1.default.BR_PARTY}/parties/${this.id}/invites/${resolvedFriend.id}?sendPing=true`, headers: { 'Content-Type': 'application/json', }, data: { 'urn:epic:cfg:build-id_s': this.client.config.partyBuildId, 'urn:epic:conn:platform_s': this.client.config.platform, 'urn:epic:conn:type_s': 'game', 'urn:epic:invite:platformdata_s': '', 'urn:epic:member:dn_s': this.client.user.self.displayName, }, }, enums_1.AuthSessionStoreKey.Fortnite); } else { invite = await this.client.http.epicgamesRequest({ method: 'POST', url: `${Endpoints_1.default.BR_PARTY}/user/${resolvedFriend.id}/pings/${this.client.user.self.id}`, headers: { 'Content-Type': 'application/json', }, data: { 'urn:epic:invite:platformdata_s': '', }, }, enums_1.AuthSessionStoreKey.Fortnite); } return new SentPartyInvitation_1.default(this.client, this, this.client.user.self, resolvedFriend, invite); } /** * Refreshes the member positions of this party * @throws {PartyPermissionError} The client is not the leader of the party * @throws {EpicgamesAPIError} */ async refreshSquadAssignments() { if (!this.me.isLeader) throw new PartyPermissionError_1.default(); await this.sendPatch({ 'Default:SquadInformation_j': this.meta.refreshSquadAssignments(), }); } /** * Sends a message to the party chat * @param content The message that will be sent */ async sendMessage(content) { return this.chat.send(content); } /** * Ban a member from this party chat * @param member The member that should be banned * @deprecated This feature has been deprecated since epic moved chatting away from xmpp */ // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars async chatBan(member) { const deprecatedFn = (0, util_1.deprecate)(() => { }, deprecationNotOverXmppAnymore); return deprecatedFn(); } /** * Updates this party's privacy settings * @param privacy The updated party privacy * @param sendPatch Whether the updated privacy should be sent to epic's servers * @throws {PartyPermissionError} The client is not the leader of the party * @throws {EpicgamesAPIError} */ async setPrivacy(privacy, sendPatch = true) { if (!this.me.isLeader) throw new PartyPermissionError_1.default(); const updated = {}; const deleted = []; const privacyMeta = this.meta.get('Default:PrivacySettings_j'); if (privacyMeta) { updated['Default:PrivacySettings_j'] = this.meta.set('Default:PrivacySettings_j', { PrivacySettings: { ...privacyMeta.PrivacySettings, partyType: privacy.partyType, bOnlyLeaderFriendsCanJoin: privacy.onlyLeaderFriendsCanJoin, partyInviteRestriction: privacy.inviteRestriction, }, }); } updated['urn:epic:cfg:presence-perm_s'] = this.meta.set('urn:epic:cfg:presence-perm_s', privacy.presencePermission); updated['urn:epic:cfg:accepting-members_b'] = this.meta.set('urn:epic:cfg:accepting-members_b', privacy.acceptingMembers); updated['urn:epic:cfg:invite-perm_s'] = this.meta.set('urn:epic:cfg:invite-perm_s', privacy.invitePermission); if (privacy.partyType === 'Private') { deleted.push('urn:epic:cfg:not-accepting-members'); updated['urn:epic:cfg:not-accepting-members-reason_i'] = this.meta.set('urn:epic:cfg:not-accepting-members-reason_i', 7); this.config.discoverability = 'INVITED_ONLY'; this.config.joinability = 'INVITE_AND_FORMER'; } else { deleted.push('urn:epic:cfg:not-accepting-members-reason_i'); this.config.discoverability = 'ALL'; this.config.joinability = 'OPEN'; } this.meta.remove(deleted); if (sendPatch) await this.sendPatch(updated, deleted); this.config.privacy = { ...this.config.privacy, ...privacy, }; return { updated, deleted }; } /** * Sets this party's custom matchmaking key * @param key The custom matchmaking key * @throws {PartyPermissionError} The client is not the leader of the party * @throws {EpicgamesAPIError} */ async setCustomMatchmakingKey(key) { if (!this.me.isLeader) throw new PartyPermissionError_1.default(); await this.sendPatch({ 'Default:CustomMatchKey_s': this.meta.set('Default:CustomMatchKey_s', key || ''), }); } /** * Promotes a party member * @param member The member that should be promoted * @throws {PartyPermissionError} The client is not the leader of the party * @throws {PartyMemberNotFoundError} The party member wasn't found * @throws {EpicgamesAPIError} */ async promote(member) { if (!this.me.isLeader) throw new PartyPermissionError_1.default(); const partyMember = this.members.find((m) => m.displayName === member || m.id === member); if (!partyMember) throw new PartyMemberNotFoundError_1.default(member); try { await this.client.http.epicgamesRequest({ method: 'POST', url: `${Endpoints_1.default.BR_PARTY}/parties/${this.id}/members/${partyMember.id}/promote`, }, enums_1.AuthSessionStoreKey.Fortnite); } catch (e) { if (e instanceof EpicgamesAPIError_1.default && e.code === 'errors.com.epicgames.social.party.party_change_forbidden') { throw new PartyPermissionError_1.default(); } throw e; } } /** * Hides / Unhides a single party member * @param member The member that should be hidden * @param hide Whether the member should be hidden * @throws {PartyPermissionError} The client is not the leader of the party * @throws {PartyMemberNotFoundError} The party member wasn't found * @throws {EpicgamesAPIError} */ async hideMember(member, hide = true) { if (!this.me.isLeader) throw new PartyPermissionError_1.default(); const partyMember = this.members.find((m) => m.displayName === member || m.id === member); if (!partyMember) throw new PartyMemberNotFoundError_1.default(member); if (hide) { this.hiddenMemberIds.add(partyMember.id); } else { this.hiddenMemberIds.delete(partyMember.id); } await this.refreshSquadAssignments(); } /** * Hides / Unhides all party members except for the client * @param hide Whether all members should be hidden * @throws {PartyPermissionError} The client is not the leader of the party * @throws {EpicgamesAPIError} */ async hideMembers(hide = true) { if (!this.me.isLeader) throw new PartyPermissionError_1.default(); if (hide) { this.members.filter((m) => m.id !== this.me.id).forEach((m) => this.hiddenMemberIds.add(m.id)); } else { this.hiddenMemberIds.clear(); } await this.refreshSquadAssignments(); } /** * Updates the party's playlist * @param mnemonic The new mnemonic (Playlist id or island code, for example: playlist_defaultduo or 1111-1111-1111) * @param regionId The new region id * @param version The new version * @param options Playlist options * @throws {PartyPermissionError} The client is not the leader of the party * @throws {EpicgamesAPIError} */ async setPlaylist(mnemonic, regionId, version, options) { if (!this.me.isLeader) throw new PartyPermissionError_1.default(); let regionIdData = this.meta.get('Default:RegionId_s'); if (regionId) { regionIdData = this.meta.set('Default:RegionId_s', regionId); } let data = this.meta.get('Default:SelectedIsland_j'); data = this.meta.set('Default:SelectedIsland_j', { ...data, SelectedIsland: { ...data.SelectedIsland, linkId: { mnemonic, version: version !== null && version !== void 0 ? version : -1, }, ...options, }, }); await this.sendPatch({ 'Default:SelectedIsland_j': data, 'Default:RegionId_s': regionIdData, }); } /** * Updates the squad fill status of this party * @param fill Whether fill is enable or not * @throws {PartyPermissionError} The client is not the leader of the party * @throws {EpicgamesAPIError} */ async setSquadFill(fill = true) { if (!this.me.isLeader) throw new PartyPermissionError_1.default(); await this.sendPatch({ 'Default:AthenaSquadFill_b': this.meta.set('Default:AthenaSquadFill_b', fill), }); } /** * Updates the party's max member count * @param maxSize The new party max size (1-16) * @throws {PartyPermissionError} The client is not the leader of the party * @throws {RangeError} The new max member size must be between 1 and 16 (inclusive) and more than the current member count * @throws {EpicgamesAPIError} */ async setMaxSize(maxSize) { if (!this.me.isLeader) throw new PartyPermissionError_1.default(); if (maxSize < 1 || maxSize > 16) throw new RangeError('The new max member size must be between 1 and 16 (inclusive)'); if (maxSize < this.size) throw new RangeError('The new max member size must be higher than the current member count'); this.config.maxSize = maxSize; await this.sendPatch(this.meta.schema); } } exports.default = ClientParty; //# sourceMappingURL=ClientParty.js.map