twitch-chat-client
Version:
Interact with the Twitch Messaging Interface (aka Twitch chat).
901 lines • 41.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var ircv3_1 = require("ircv3");
var UserTools_1 = require("./Toolkit/UserTools");
var TwitchTags_1 = require("./Capabilities/TwitchTags/");
var TwitchCommands_1 = require("./Capabilities/TwitchCommands/");
var TwitchMembership_1 = require("./Capabilities/TwitchMembership");
var Commands_1 = require("ircv3/lib/Message/MessageTypes/Commands/");
var ClearChat_1 = require("./Capabilities/TwitchCommands/MessageTypes/ClearChat");
var HostTarget_1 = require("./Capabilities/TwitchCommands/MessageTypes/HostTarget");
var RoomState_1 = require("./Capabilities/TwitchCommands/MessageTypes/RoomState");
var UserNotice_1 = require("./Capabilities/TwitchCommands/MessageTypes/UserNotice");
var Whisper_1 = require("./Capabilities/TwitchCommands/MessageTypes/Whisper");
var Decorators_1 = require("./Toolkit/Decorators");
var PrivateMessage_1 = require("./StandardCommands/PrivateMessage");
/**
* An interface to Twitch chat.
*
* @inheritDoc
* @hideProtected
*/
var ChatClient = /** @class */ (function (_super) {
tslib_1.__extends(ChatClient, _super);
/**
* Creates a new Twitch chat client.
*
* @expandParams
*
* @param twitchClient The {@TwitchClient} instance to use for API requests.
* @param options
*/
function ChatClient(twitchClient, options) {
var _this = _super.call(this, {
connection: {
hostName: (options.webSocket === undefined ? !options.rawIrc : options.webSocket) ? 'irc-ws.chat.twitch.tv' : 'irc.chat.twitch.tv',
nick: options.userName.toLowerCase(),
password: options.token && "oauth:" + options.token.replace(/^oauth:/, ''),
secure: options.ssl === undefined ? !options.disableSsl : options.ssl
},
webSocket: (options.webSocket === undefined ? !options.rawIrc : options.webSocket),
logLevel: options.logLevel,
nonConformingCommands: ['004']
}) || this;
/**
* Fires when a user is timed out from a channel.
*
* @eventListener
* @param channel The channel the user is timed out from.
* @param user The timed out user.
* @param reason The reason for the timeout.
* @param duration The duration of the timeout, in seconds.
*/
_this.onTimeout = _this.registerEvent();
/**
* Fires when a user is permanently banned from a channel.
*
* @eventListener
* @param channel The channel the user is banned from.
* @param user The banned user.
* @param reason The reason for the ban.
*/
_this.onBan = _this.registerEvent();
/**
* Fires when a user upgrades their bits badge in a channel.
*
* @eventListener
* @param channel The channel where the bits badge was upgraded.
* @param user The user that has upgraded their bits badge.
* @param ritualInfo Additional information about the upgrade.
* @param msg The raw message that was received.
*/
_this.onBitsBadgeUpgrade = _this.registerEvent();
/**
* Fires when the chat of a channel is cleared.
*
* @eventListener
* @param channel The channel whose chat is cleared.
*/
_this.onChatClear = _this.registerEvent();
/**
* Fires when emote-only mode is toggled in a channel.
*
* @eventListener
* @param channel The channel where emote-only mode is being toggled.
* @param enabled Whether emote-only mode is being enabled. If false, it's being disabled.
*/
_this.onEmoteOnly = _this.registerEvent();
/**
* Fires when followers-only mode is toggled in a channel.
*
* @eventListener
* @param channel The channel where followers-only mode is being toggled.
* @param enabled Whether followers-only mode is being enabled. If false, it's being disabled.
* @param delay The time a user needs to follow the channel to be able to talk. Only available when `enabled === true`.
*/
_this.onFollowersOnly = _this.registerEvent();
/**
* Fires when a channel hosts another channel.
*
* @eventListener
* @param channel The hosting channel.
* @param target The channel that is being hosted.
* @param viewers The number of viewers in the hosting channel.
*
* If you're not logged in as the owner of the channel, this is undefined.
*/
_this.onHost = _this.registerEvent();
/**
* Fires when a channel you're logged in as its owner is being hosted by another channel.
*
* @eventListener
* @param channel The channel that is being hosted.
* @param byChannel The hosting channel.
* @param auto Whether the host was triggered automatically (by Twitch's auto-host functionality).
* @param viewers The number of viewers in the hosting channel.
*/
_this.onHosted = _this.registerEvent();
/**
* Fires when Twitch tells you the number of hosts you have remaining in the next half hour for the channel
* for which you're logged in as owner after hosting a channel.
*
* @eventListener
* @param channel The hosting channel.
* @param numberOfHosts The number of hosts remaining in the next half hour.
*/
_this.onHostsRemaining = _this.registerEvent();
/**
* Fires when a user joins a channel.
*
* The join/part events are cached by the Twitch chat server and will be batched and sent every 30-60 seconds.
*
* @eventListener
* @param channel The channel that is being joined.
* @param user The user that joined.
*/
_this.onJoin = _this.registerEvent();
/**
* Fires when a user leaves ("parts") a channel.
*
* The join/part events are cached by the Twitch chat server and will be batched and sent every 30-60 seconds.
*
* @eventListener
* @param channel The channel that is being left.
* @param user The user that left.
*/
_this.onPart = _this.registerEvent();
/**
* Fires when R9K mode is toggled in a channel.
*
* @eventListener
* @param channel The channel where R9K mode is being toggled.
* @param enabled Whether R9K mode is being enabled. If false, it's being disabled.
*/
_this.onR9k = _this.registerEvent();
/**
* Fires when host mode is disabled in a channel.
*
* @eventListener
* @param channel The channel where host mode is being disabled.
*/
_this.onUnhost = _this.registerEvent();
/**
* Fires when a user raids a channel.
*
* @eventListener
* @param channel The channel that was raided.
* @param user The user that has raided the channel.
* @param raidInfo Additional information about the raid.
* @param msg The raw message that was received.
*/
_this.onRaid = _this.registerEvent();
/**
* Fires when a user performs a "ritual" in a channel.
*
* @eventListener
* @param channel The channel where the ritual was performed.
* @param user The user that has performed the ritual.
* @param ritualInfo Additional information about the ritual.
* @param msg The raw message that was received.
*/
_this.onRitual = _this.registerEvent();
/**
* Fires when slow mode is toggled in a channel.
*
* @eventListener
* @param channel The channel where slow mode is being toggled.
* @param enabled Whether slow mode is being enabled. If false, it's being disabled.
* @param delay The time a user has to wait between sending messages. Only set when enabling slow mode.
*/
_this.onSlow = _this.registerEvent();
/**
* Fires when sub only mode is toggled in a channel.
*
* @eventListener
* @param channel The channel where sub only mode is being toggled.
* @param enabled Whether sub only mode is being enabled. If false, it's being disabled.
*/
_this.onSubsOnly = _this.registerEvent();
/**
* Fires when a user subscribes to a channel.
*
* @eventListener
* @param channel The channel that was subscribed to.
* @param user The subscribing user.
* @param subInfo Additional information about the subscription.
* @param msg The raw message that was received.
*/
_this.onSub = _this.registerEvent();
/**
* Fires when a user resubscribes to a channel.
*
* @eventListener
* @param channel The channel that was resubscribed to.
* @param user The resubscribing user.
* @param subInfo Additional information about the resubscription.
* @param msg The raw message that was received.
*/
_this.onResub = _this.registerEvent();
/**
* Fires when a user gifts a subscription to a channel to another user.
*
* @eventListener
* @param channel The channel that was subscribed to.
* @param user The user that the subscription was gifted to. The gifting user is defined in `subInfo.gifter`.
* @param subInfo Additional information about the subscription.
* @param msg The raw message that was received.
*/
_this.onSubGift = _this.registerEvent();
/**
* Fires when a user gifts random subscriptions to the community of a channel.
*
* @eventListener
* @param channel The channel that was subscribed to.
* @param user The gifting user.
* @param subInfo Additional information about the community subscription.
* @param msg The raw message that was received.
*/
_this.onCommunitySub = _this.registerEvent();
/**
* Fires when receiving a whisper from another user.
*
* @eventListener
* @param user The user that sent the whisper.
* @param message The message text.
* @param msg The raw message that was received.
*/
_this.onWhisper = _this.registerEvent();
/**
* Fires when you tried to execute a command you don't have sufficient permission for.
*
* @eventListener
* @param channel The channel that a command without sufficient permissions was executed on.
* @maram message The message text.
*/
_this.onNoPermission = _this.registerEvent();
// internal events to resolve promises and stuff
_this._onBanResult = _this.registerEvent();
_this._onTimeoutResult = _this.registerEvent();
_this._onUnbanResult = _this.registerEvent();
_this._onColorResult = _this.registerEvent();
_this._onCommercialResult = _this.registerEvent();
_this._onEmoteOnlyResult = _this.registerEvent();
_this._onEmoteOnlyOffResult = _this.registerEvent();
_this._onFollowersOnlyResult = _this.registerEvent();
_this._onFollowersOnlyOffResult = _this.registerEvent();
_this._onHostResult = _this.registerEvent();
_this._onUnhostResult = _this.registerEvent();
_this._onModResult = _this.registerEvent();
_this._onUnmodResult = _this.registerEvent();
_this._onModsResult = _this.registerEvent();
_this._onJoinResult = _this.registerEvent();
_this._onR9kResult = _this.registerEvent();
_this._onR9kOffResult = _this.registerEvent();
_this._onSlowResult = _this.registerEvent();
_this._onSlowOffResult = _this.registerEvent();
_this._onSubsOnlyResult = _this.registerEvent();
_this._onSubsOnlyOffResult = _this.registerEvent();
_this._twitchClient = twitchClient;
// tslint:disable:no-floating-promises
_this.registerCapability(TwitchTags_1.default);
_this.registerCapability(TwitchCommands_1.default);
// eslint-disable-next-line no-restricted-syntax
if (options.requestMembershipEvents !== false) {
_this.registerCapability(TwitchMembership_1.default);
}
// tslint:enable:no-floating-promises
_this.onMessage(ClearChat_1.default, function (_a) {
var _b = _a.params, channel = _b.channel, user = _b.user, tags = _a.tags;
if (user) {
var duration = tags.get('ban-duration');
var reason = tags.get('ban-reason');
if (duration === undefined) {
// ban
_this.emit(_this.onBan, channel, user, reason);
}
else {
// timeout
_this.emit(_this.onTimeout, channel, user, reason, Number(duration));
_this.emit(_this._onTimeoutResult, channel, user, reason, Number(duration));
}
}
else {
// full chat clear
_this.emit(_this.onChatClear, channel);
}
});
_this.onMessage(HostTarget_1.default, function (_a) {
var _b = _a.params, channel = _b.channel, targetAndViewers = _b.targetAndViewers;
var _c = tslib_1.__read(targetAndViewers.split(' '), 2), target = _c[0], viewers = _c[1];
if (target === '-') {
// unhost
_this.emit(_this.onUnhost, channel);
}
else {
var numViewers = Number(viewers);
_this.emit(_this.onHost, channel, target, isNaN(numViewers) ? undefined : numViewers);
}
});
_this.onMessage(Commands_1.ChannelJoin, function (_a) {
var prefix = _a.prefix, channel = _a.params.channel;
_this.emit(_this.onJoin, channel, prefix.nick);
});
_this.onMessage(Commands_1.ChannelPart, function (_a) {
var prefix = _a.prefix, channel = _a.params.channel;
_this.emit(_this.onPart, channel, prefix.nick);
});
_this.onMessage(PrivateMessage_1.default, function (_a) {
var prefix = _a.prefix, _b = _a.params, channel = _b.target, message = _b.message;
if (prefix && prefix.nick === 'jtv') {
// 1 = who hosted
// 2 = auto-host or not
// 3 = how many viewers (not always present)
var match = message.match(ChatClient.HOST_MESSAGE_REGEX);
if (match) {
_this.emit(_this.onHosted, channel, match[1], Boolean(match[2]), match[3] === '' ? undefined : Number(match[3]));
}
}
});
_this.onMessage(RoomState_1.default, function (_a) {
var channel = _a.params.channel, tags = _a.tags;
var isInitial = false;
if (tags.has('subs-only') && tags.has('slow')) {
// this is the full state - so we just successfully joined
_this.emit(_this._onJoinResult, channel, tags);
isInitial = true;
}
if (tags.has('slow')) {
var slowDelay = Number(tags.get('slow'));
if (slowDelay) {
_this.emit(_this._onSlowResult, channel, slowDelay);
if (!isInitial) {
_this.emit(_this.onSlow, channel, true, slowDelay);
}
}
else {
_this.emit(_this._onSlowOffResult, channel);
if (!isInitial) {
_this.emit(_this.onSlow, channel, false);
}
}
}
if (tags.has('followers-only')) {
var followDelay = Number(tags.get('followers-only'));
if (followDelay === -1) {
_this.emit(_this._onFollowersOnlyOffResult, channel);
if (!isInitial) {
_this.emit(_this.onFollowersOnly, channel, false);
}
}
else {
_this.emit(_this._onFollowersOnlyResult, channel, followDelay);
if (!isInitial) {
_this.emit(_this.onFollowersOnly, channel, true, followDelay);
}
}
}
});
_this.onMessage(UserNotice_1.default, function (userNotice) {
var _a = userNotice.params, channel = _a.channel, message = _a.message, tags = userNotice.tags;
var messageType = tags.get('msg-id');
switch (messageType) {
case 'sub':
case 'resub': {
var event_1 = messageType === 'sub' ? _this.onSub : _this.onResub;
var plan = tags.get('msg-param-sub-plan');
var streakMonths = tags.get('msg-param-streak-months');
var subInfo = {
displayName: tags.get('display-name'),
plan: plan,
planName: tags.get('msg-param-sub-plan-name'),
isPrime: plan === 'Prime',
months: Number(tags.get('msg-param-cumulative-months')),
streak: streakMonths ? Number(streakMonths) : undefined,
message: message
};
_this.emit(event_1, channel, tags.get('login'), subInfo, userNotice);
break;
}
case 'subgift':
case 'anonsubgift': {
var plan = tags.get('msg-param-sub-plan');
var gifter = tags.get('login');
var isAnon = messageType === 'anonsubgift' || gifter === 'ananonymousgifter';
var subInfo = {
displayName: tags.get('msg-param-recipient-display-name'),
gifter: isAnon ? undefined : gifter,
gifterDisplayName: isAnon ? undefined : tags.get('display-name'),
gifterGiftCount: isAnon ? undefined : Number(tags.get('msg-param-sender-count')),
plan: plan,
planName: tags.get('msg-param-sub-plan-name'),
isPrime: plan === 'Prime',
months: Number(tags.get('msg-param-months'))
};
_this.emit(_this.onSubGift, channel, tags.get('msg-param-recipient-user-name'), subInfo, userNotice);
break;
}
case 'anonsubmysterygift':
case 'submysterygift': {
var gifter = tags.get('login');
var isAnon = messageType === 'anonsubmysterygift' || gifter === 'ananonymousgifter';
var communitySubInfo = {
gifter: isAnon ? undefined : gifter,
gifterDisplayName: isAnon ? undefined : tags.get('display-name'),
gifterGiftCount: isAnon ? undefined : Number(tags.get('msg-param-sender-count')),
count: Number(tags.get('msg-param-mass-gift-count')),
plan: tags.get('msg-param-sub-plan')
};
_this.emit(_this.onCommunitySub, channel, tags.get('login'), communitySubInfo, userNotice);
break;
}
case 'raid': {
var raidInfo = {
displayName: tags.get('msg-param-displayName'),
viewerCount: Number(tags.get('msg-param-viewerCount'))
};
_this.emit(_this.onRaid, channel, tags.get('login'), raidInfo, userNotice);
break;
}
case 'ritual': {
var ritualInfo = {
ritualName: tags.get('msg-param-ritual-name'),
message: message
};
_this.emit(_this.onRitual, channel, tags.get('login'), ritualInfo, userNotice);
break;
}
case 'bitsbadgetier': {
var badgeUpgradeInfo = {
displayName: tags.get('display-name'),
threshold: Number(tags.get('msg-param-threshold'))
};
_this.emit(_this.onBitsBadgeUpgrade, channel, tags.get('login'), badgeUpgradeInfo, userNotice);
break;
}
default: {
// eslint-disable-next-line no-console
console.warn("Unrecognized usernotice ID: " + messageType);
}
}
});
_this.onMessage(Whisper_1.default, function (whisper) {
_this.emit(_this.onWhisper, whisper.prefix.nick, whisper.params.message, whisper);
});
_this.onMessage(Commands_1.Notice, function (_a) {
var _b = _a.params, channel = _b.target, message = _b.message, tags = _a.tags;
var messageType = tags.get('msg-id');
// this event handler involves a lot of parsing strings you shouldn't parse...
// but Twitch doesn't give us the required info in tags (╯°□°)╯︵ ┻━┻
// (this code also might not do the right thing with foreign character display names...)
switch (messageType) {
// ban
case 'already_banned': {
var match = message.split(' ');
var user = (match && /^\w+$/.test(match[0])) ? match[0] : undefined;
_this.emit(_this._onBanResult, channel, user, messageType);
break;
}
case 'bad_ban_self': {
_this.emit(_this._onBanResult, channel, _this._userName, messageType);
break;
}
case 'bad_ban_broadcaster': {
_this.emit(_this._onBanResult, channel, UserTools_1.toUserName(channel), messageType);
break;
}
case 'bad_ban_admin':
case 'bad_ban_global_mod':
case 'bad_ban_staff': {
var match = message.match(/^You cannot ban (?:\w+ )+?(\w+)\.$/);
_this.emit(_this._onBanResult, channel, match ? match[1].toLowerCase() : undefined, messageType);
break;
}
case 'ban_success': {
var match = message.split(' ');
var user = (match && /^\w+$/.test(match[0])) ? match[0] : undefined;
_this.emit(_this._onBanResult, channel, user);
break;
}
// unban
case 'bad_unban_no_ban': {
var match = message.split(' ');
var user = (match && /^\w+$/.test(match[0])) ? match[0] : undefined;
_this.emit(_this._onUnbanResult, channel, user, messageType);
break;
}
case 'unban_success': {
var match = message.split(' ');
var user = (match && /^\w+$/.test(match[0])) ? match[0] : undefined;
_this.emit(_this._onUnbanResult, channel, user);
break;
}
// color
case 'turbo_only_color': {
_this.emit(_this._onColorResult, messageType);
break;
}
case 'color_changed': {
_this.emit(_this._onColorResult);
break;
}
// commercial
case 'bad_commercial_error': {
_this.emit(_this._onCommercialResult, channel, messageType);
break;
}
case 'commercial_success': {
_this.emit(_this._onCommercialResult, channel);
break;
}
// emote only
case 'already_emote_only_on': {
_this.emit(_this._onEmoteOnlyResult, channel, messageType);
break;
}
case 'emote_only_on': {
_this.emit(_this._onEmoteOnlyResult, channel);
_this.emit(_this.onEmoteOnly, channel, true);
break;
}
// emote only off
case 'already_emote_only_off': {
_this.emit(_this._onEmoteOnlyOffResult, channel, messageType);
break;
}
case 'emote_only_off': {
_this.emit(_this._onEmoteOnlyOffResult, channel);
_this.emit(_this.onEmoteOnly, channel, false);
break;
}
// host
case 'bad_host_hosting':
case 'bad_host_rate_exceeded':
case 'bad_host_error': {
_this.emit(_this._onHostResult, channel, messageType);
break;
}
case 'hosts_remaining': {
var remainingHostsFromChar = +message[0];
var remainingHosts = isNaN(remainingHostsFromChar) ? 0 : Number(remainingHostsFromChar);
_this.emit(_this._onHostResult, channel);
_this.emit(_this.onHostsRemaining, channel, remainingHosts);
break;
}
// unhost (only fails, success is handled by HOSTTARGET)
case 'not_hosting': {
_this.emit(_this._onUnhostResult, channel, messageType);
break;
}
// join (success is handled when ROOMSTATE comes in)
case 'msg_channel_suspended': {
_this.emit(_this._onJoinResult, channel, undefined, messageType);
break;
}
// mod
case 'bad_mod_banned':
case 'bad_mod_mod': {
var match = message.split(' ');
var user = (match && /^\w+$/.test(match[0])) ? match[0] : undefined;
_this.emit(_this._onModResult, channel, user, messageType);
break;
}
case 'mod_success': {
var match = message.match(/^You have added (\w+) /);
_this.emit(_this._onModResult, channel, match ? match[1] : undefined);
break;
}
// unmod
case 'bad_unmod_mod': {
var match = message.split(' ');
var user = (match && /^\w+$/.test(match[0])) ? match[0] : undefined;
_this.emit(_this._onUnmodResult, channel, user, messageType);
break;
}
case 'unmod_success': {
var match = message.match(/^You have removed (\w+) /);
_this.emit(_this._onUnmodResult, channel, match ? match[1] : undefined);
break;
}
// mods
case 'no_mods': {
_this.emit(_this._onModsResult, channel, []);
break;
}
case 'room_mods': {
var _c = tslib_1.__read(message.split(': '), 2), modList = _c[1];
var mods = modList.split(', ');
_this.emit(_this._onModsResult, channel, mods);
break;
}
// r9k
case 'already_r9k_on': {
_this.emit(_this._onR9kResult, channel, messageType);
break;
}
case 'r9k_on': {
_this.emit(_this._onR9kResult, channel);
_this.emit(_this.onR9k, channel, true);
break;
}
// r9k off
case 'already_r9k_off': {
_this.emit(_this._onR9kOffResult, channel, messageType);
break;
}
case 'r9k_off': {
_this.emit(_this._onR9kOffResult, channel);
_this.emit(_this.onR9k, channel, false);
break;
}
// subs only
case 'already_subs_on': {
_this.emit(_this._onSubsOnlyResult, channel, messageType);
break;
}
case 'subs_on': {
_this.emit(_this._onSubsOnlyResult, channel);
_this.emit(_this.onSubsOnly, channel, true);
break;
}
// subs only off
case 'already_subs_off': {
_this.emit(_this._onSubsOnlyOffResult, channel, messageType);
break;
}
case 'subs_off': {
_this.emit(_this._onSubsOnlyOffResult, channel);
_this.emit(_this.onSubsOnly, channel, false);
break;
}
// timeout (only fails, success is handled by CLEARCHAT)
case 'bad_timeout_self': {
_this.emit(_this._onTimeoutResult, channel, _this._userName, undefined, undefined, messageType);
break;
}
case 'bad_timeout_broadcaster': {
_this.emit(_this._onTimeoutResult, channel, UserTools_1.toUserName(channel), undefined, undefined, messageType);
break;
}
case 'bad_timeout_admin':
case 'bad_timeout_global_mod':
case 'bad_timeout_staff': {
var match = message.match(/^You cannot ban (?:\w+ )+?(\w+)\.$/);
_this.emit(_this._onTimeoutResult, channel, match ? match[1].toLowerCase() : undefined, undefined, undefined, messageType);
break;
}
case 'cmds_available': {
// do we really care?
break;
}
// there's other messages that show us the following things...
// ...like ROOMSTATE...
case 'followers_on':
case 'followers_on_zero':
case 'followers_off':
case 'slow_on':
case 'slow_off': {
break;
}
// ...and CLEARCHAT...
case 'timeout_success': {
break;
}
// ...and HOSTTARGET
case 'host_off':
case 'host_on':
case 'host_target_went_offline': {
break;
}
case 'unrecognized_cmd': {
break;
}
case 'no_permission': {
_this.emit(_this.onNoPermission, channel, message);
break;
}
case undefined: {
// this might be one of these weird authentication error notices that don't have a msg-id...
if (message === 'Login authentication failed'
|| message === 'Improperly formatted AUTH'
|| message === 'Invalid NICK') {
_this._connection.disconnect();
}
break;
}
default: {
if (!messageType || messageType.substr(0, 6) !== 'usage_') {
// eslint-disable-next-line no-console
console.warn("Unrecognized notice ID: '" + messageType + "'");
}
}
}
});
return _this;
}
/**
* Creates a new Twitch chat client with the user info from the TwitchClient instance.
*
* @expandParams
*
* @param twitchClient The TwitchClient instance to use for user info and API requests.
* @param options
*/
ChatClient.forTwitchClient = function (twitchClient, options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var scopes, accessToken, token;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (options.legacyScopes) {
scopes = ['chat_login'];
}
else if (options.readOnly) {
scopes = ['chat:read'];
}
else {
scopes = ['chat:read', 'chat:edit'];
}
return [4 /*yield*/, twitchClient.getAccessToken(scopes)];
case 1:
accessToken = _a.sent();
if (!accessToken) return [3 /*break*/, 3];
return [4 /*yield*/, twitchClient.getTokenInfo()];
case 2:
token = _a.sent();
if (token.valid) {
return [2 /*return*/, new this(twitchClient, tslib_1.__assign({}, options, { userName: token.userName, token: accessToken.accessToken }))];
}
_a.label = 3;
case 3: throw new Error('trying to get chat client for invalid token');
}
});
});
};
/**
* Creates a new anonymous Twitch chat client.
*
* @expandParams
*
* @param twitchClient Currently deprecated and ignored. You can safely pass undefined here.
* @param options
*/
ChatClient.anonymous = function (twitchClient, options) {
if (options === void 0) { options = {}; }
var randomSuffix = Math.floor(Math.random() * 100000).toString().padStart(5, '0');
var userName = "justinfan" + randomSuffix;
return new this(undefined, tslib_1.__assign({}, options, { userName: userName }));
};
/**
* Hosts a channel on another channel.
*
* @param target The host target, i.e. the channel that is being hosted.
* @param channel The host source, i.e. the channel that is hosting. Defaults to the channel of the connected user.
*/
ChatClient.prototype.host = function (target, channel) {
if (channel === void 0) { channel = this._nick; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _this = this;
return tslib_1.__generator(this, function (_a) {
channel = UserTools_1.toUserName(channel);
return [2 /*return*/, new Promise(function (resolve, reject) {
var e = _this._onHostResult(function (chan, error) {
if (UserTools_1.toUserName(chan) === channel) {
if (error) {
reject(error);
}
else {
resolve();
}
_this.removeListener(e);
}
});
_this.say(channel, "/host " + target);
})];
});
});
};
/**
* Ends any host on a channel.
*
* This only works when in the channel that was hosted in order to provide feedback about success of the command.
*
* If you don't need this feedback, consider using {@ChatClient#unhostOutside} instead.
*
* @param channel The channel to end the host on. Defaults to the channel of the connected user.
*/
ChatClient.prototype.unhost = function (channel) {
if (channel === void 0) { channel = this._nick; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _this = this;
return tslib_1.__generator(this, function (_a) {
channel = UserTools_1.toUserName(channel);
return [2 /*return*/, new Promise(function (resolve, reject) {
var e = _this._onUnhostResult(function (chan, error) {
if (UserTools_1.toUserName(chan) === channel) {
if (error) {
reject(error);
}
else {
resolve();
}
_this.removeListener(e);
}
});
_this.say(channel, '/unhost');
})];
});
});
};
/**
* Ends any host on a channel.
*
* This works even when not in the channel that was hosted, but provides no feedback about success of the command.
*
* If you need feedback about success, use {@ChatClient#unhost} (but make sure you're in the channel you are hosting).
*
* @param channel The channel to end the host on. Defaults to the channel of the connected user.
*/
ChatClient.prototype.unhostOutside = function (channel) {
if (channel === void 0) { channel = this._nick; }
this.say(channel, '/unhost');
};
ChatClient.prototype.say = function (channel, message) {
_super.prototype.say.call(this, UserTools_1.toChannelName(channel), message);
};
ChatClient.prototype.join = function (channel) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _this = this;
return tslib_1.__generator(this, function (_a) {
channel = UserTools_1.toChannelName(channel);
return [2 /*return*/, new Promise(function (resolve, reject) {
var timer;
var e = _this._onJoinResult(function (chan, state, error) {
if (chan === channel) {
clearTimeout(timer);
if (error) {
reject(error);
}
else {
resolve();
}
_this.removeListener(e);
}
});
timer = setTimeout(function () {
_this.removeListener(e);
reject(new Error("Did not receive a reply to join " + channel + " in time; assuming that the join failed"));
}, 10000);
_super.prototype.join.call(_this, channel);
})];
});
});
};
ChatClient.prototype.quit = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _this = this;
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, new Promise(function (resolve) {
var handler = function () {
_this._connection.removeListener('disconnect', handler);
resolve();
};
_this._connection.addListener('disconnect', handler);
_this._connection.disconnect();
})];
});
});
};
ChatClient.prototype.registerCoreMessageTypes = function () {
_super.prototype.registerCoreMessageTypes.call(this);
this.registerMessageType(PrivateMessage_1.default);
};
ChatClient.HOST_MESSAGE_REGEX = /(\w+) is now ((?:auto[- ])?)hosting you(?: for (?:up to )?(\d+))?/;
tslib_1.__decorate([
Decorators_1.NonEnumerable
], ChatClient.prototype, "_twitchClient", void 0);
return ChatClient;
}(ircv3_1.Client));
exports.default = ChatClient;
//# sourceMappingURL=ChatClient.js.map