UNPKG

twitch-chat-client

Version:

Interact with the Twitch Messaging Interface (aka Twitch chat).

901 lines 41.2 kB
"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