Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

tmi.js

Package Overview
Dependencies
Maintainers
1
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tmi.js - npm Package Compare versions

Comparing version 1.6.0 to 1.7.0

5

index.js

@@ -0,4 +1,5 @@

var client = require("./lib/client");
module.exports = {
client: require("./lib/client"),
Client: require("./lib/client")
client,
Client: client
};

52

lib/api.js

@@ -1,2 +0,2 @@

var request = require("request");
var fetch = require("node-fetch");
var _ = require("./utils");

@@ -13,15 +13,34 @@

// We are inside a Node application, so we can use the request module..
// We are inside a Node application, so we can use the node-fetch module..
if(_.isNode()) {
var opts = _.merge({ method: "GET", json: true }, options, { url });
request(opts, callback);
var url = opts.url;
if(opts.qs) {
var qs = new URLSearchParams(opts.qs);
url += `?${qs}`;
}
var response = {};
/** @type {ReturnType<import('node-fetch')['default']>} */
const fetchPromise = fetch(url, {
method: opts.method,
headers: opts.headers,
body: opts.body
});
fetchPromise.then(res => {
response = { statusCode: res.status, headers: res.headers };
return opts.json ? res.json() : res.text();
})
.then(
data => callback(null, response, data),
err => callback(err, response, null)
);
}
// Inside an extension -> we cannot use jsonp!
else if(_.isExtension() || _.isReactNative()) {
options = _.merge({ url, method: "GET", headers: {} }, options);
// Web application, extension, React Native etc.
else {
var opts = _.merge({ method: "GET", headers: {} }, options, { url });
// prepare request
var xhr = new XMLHttpRequest();
xhr.open(options.method, options.url, true);
for(var name in options.headers) {
xhr.setRequestHeader(name, options.headers[name]);
xhr.open(opts.method, opts.url, true);
for(var name in opts.headers) {
xhr.setRequestHeader(name, opts.headers[name]);
}

@@ -43,19 +62,4 @@ xhr.responseType = "json";

}
// Inside a web application, use jsonp..
else {
var script = document.createElement("script");
// Callbacks must match the regex [a-zA-Z_$][\w$]*(\.[a-zA-Z_$][\w$]*)*
var callbackName = `jsonp_callback_${Math.round(100000 * Math.random())}`;
window[callbackName] = function(data) {
delete window[callbackName];
document.body.removeChild(script);
callback(null, null, data);
};
// Inject the script in the document..
script.src = `${url}${url.includes("?") ? "&" : "?"}callback=${callbackName}`;
document.body.appendChild(script);
}
}
module.exports = api;
var api = require("./api");
var commands = require("./commands");
var eventEmitter = require("./events").EventEmitter;
var EventEmitter = require("./events").EventEmitter;
var logger = require("./logger");
var parse = require("./parser");
var timer = require("./timer");
var ws = global.WebSocket || global.MozWebSocket || require("ws");
var _global = typeof global !== "undefined" ? global : typeof window !== "undefined" ? window : {};
var _WebSocket = _global.WebSocket || require("ws");
var _ = require("./utils");

@@ -13,3 +14,2 @@

if(this instanceof client === false) { return new client(opts); }
this.setMaxListeners(0);

@@ -23,2 +23,3 @@ this.opts = _.get(opts, {});

this.clientId = _.get(this.opts.options.clientId, null);
this._globalDefaultChannel = _.channel(_.get(this.opts.options.globalDefaultChannel, "#tmijs"));

@@ -35,3 +36,6 @@ this.maxReconnectAttempts = _.get(this.opts.connection.maxReconnectAttempts, Infinity);

this.secure = _.get(this.opts.connection.secure, false);
this.secure = _.get(
this.opts.connection.secure,
!this.opts.connection.server && !this.opts.connection.port
);

@@ -68,7 +72,18 @@ // Raw data and object for emote-sets..

eventEmitter.call(this);
EventEmitter.call(this);
this.setMaxListeners(0);
}
_.inherits(client, eventEmitter);
_.inherits(client, EventEmitter);
// Emit multiple events..
client.prototype.emits = function emits(types, values) {
for (var i = 0; i < types.length; i++) {
var val = i < values.length ? values[i] : values[values.length - 1];
this.emit.apply(this, [types[i]].concat(val));
}
};
client.prototype.off = client.prototype.removeListener;
client.prototype.api = api;

@@ -87,3 +102,5 @@

this.emit("raw_message", JSON.parse(JSON.stringify(message)), message);
if(this.listenerCount("raw_message")) {
this.emit("raw_message", JSON.parse(JSON.stringify(message)), message);
}

@@ -95,17 +112,15 @@ var channel = _.channel(_.get(message.params[0], null));

// Parse badges, badge-info and emotes..
message.tags = parse.badges(parse.badgeInfo(parse.emotes(message.tags)));
var tags = message.tags = parse.badges(parse.badgeInfo(parse.emotes(message.tags)));
// Transform IRCv3 tags..
if(message.tags) {
var tags = message.tags;
for(var key in tags) {
if(key !== "emote-sets" && key !== "ban-duration" && key !== "bits") {
var value = tags[key];
if(_.isBoolean(value)) { value = null; }
else if(value === "1") { value = true; }
else if(value === "0") { value = false; }
else if(_.isString(value)) { value = _.unescapeIRC(value); }
tags[key] = value;
}
for(var key in tags) {
if(key === "emote-sets" || key === "ban-duration" || key === "bits") {
continue;
}
var value = tags[key];
if(_.isBoolean(value)) { value = null; }
else if(value === "1") { value = true; }
else if(value === "0") { value = false; }
else if(_.isString(value)) { value = _.unescapeIRC(value); }
tags[key] = value;
}

@@ -119,3 +134,3 @@

this.emit("ping");
if(!_.isNull(this.ws) && this.ws.readyState === 1) {
if(this._isConnected()) {
this.ws.send("PONG");

@@ -159,3 +174,3 @@ }

this.log.info("Connected to server.");
this.userstate["#tmijs"] = {};
this.userstate[this._globalDefaultChannel] = {};
this.emits(["connected", "_promiseConnect"], [[this.server, this.port], [null]]);

@@ -168,3 +183,3 @@ this.reconnections = 0;

// Make sure the connection is opened before sending the message..
if(!_.isNull(this.ws) && this.ws.readyState === 1) {
if(this._isConnected()) {
this.ws.send("PING");

@@ -185,4 +200,6 @@ }

// Join all the channels from configuration with a 2 seconds interval..
var joinQueue = new timer.queue(2000);
// Join all the channels from the config with an interval..
var joinInterval = _.get(this.opts.options.joinInterval, 2000);
if(joinInterval < 300) joinInterval = 300;
var joinQueue = new timer.queue(joinInterval);
var joinChannels = _.union(this.opts.channels, this.channels);

@@ -194,3 +211,3 @@ this.channels = [];

joinQueue.add(() => {
if(!_.isNull(this.ws) && this.ws.readyState === 1) {
if(this._isConnected()) {
this.join(channel).catch(err => this.log.error(err));

@@ -339,2 +356,3 @@ }

case "bad_vip_grantee_already_vip":
case "bad_vip_max_vips_reached":
case "bad_vip_achievement_incomplete":

@@ -539,2 +557,3 @@ this.log.info(basicLog);

case "whisper_limit_per_sec":
case "whisper_restricted":
case "whisper_restricted_recipient":

@@ -551,2 +570,3 @@ this.log.info(basicLog);

case "tos_ban":
case "invalid_user":
this.log.info(basicLog);

@@ -580,3 +600,4 @@ this.emits([

"_promiseEmoteonly",
"_promiseEmoteonlyoff"
"_promiseEmoteonlyoff",
"_promiseWhisper"
], [noticeArr, [msgid, channel]]);

@@ -620,2 +641,3 @@ break;

case "usage_me":
case "unavailable_command":
this.log.info(basicLog);

@@ -654,2 +676,3 @@ this.emit("notice", channel, msgid, msg);

this.log.warn(`Could not parse NOTICE from tmi.twitch.tv:\n${JSON.stringify(message, null, 4)}`);
this.emit("notice", channel, msgid, msg);
}

@@ -662,12 +685,11 @@ break;

case "USERNOTICE":
var username = message.tags["display-name"] || message.tags["login"];
var plan = message.tags["msg-param-sub-plan"] || "";
var planName = _.unescapeIRC(_.get(message.tags["msg-param-sub-plan-name"], "")) || null;
var username = tags["display-name"] || tags["login"];
var plan = tags["msg-param-sub-plan"] || "";
var planName = _.unescapeIRC(_.get(tags["msg-param-sub-plan-name"], "")) || null;
var prime = plan.includes("Prime");
var methods = { prime, plan, planName };
var userstate = message.tags;
var streakMonths = ~~(message.tags["msg-param-streak-months"] || 0);
var recipient = message.tags["msg-param-recipient-display-name"] || message.tags["msg-param-recipient-user-name"];
var giftSubCount = ~~message.tags["msg-param-mass-gift-count"];
userstate["message-type"] = msgid;
var streakMonths = ~~(tags["msg-param-streak-months"] || 0);
var recipient = tags["msg-param-recipient-display-name"] || tags["msg-param-recipient-user-name"];
var giftSubCount = ~~tags["msg-param-mass-gift-count"];
tags["message-type"] = msgid;

@@ -678,3 +700,3 @@ switch(msgid) {

this.emits(["resub", "subanniversary"], [
[channel, username, streakMonths, msg, userstate, methods]
[channel, username, streakMonths, msg, tags, methods]
]);

@@ -685,3 +707,3 @@ break;

case "sub":
this.emit("subscription", channel, username, methods, msg, userstate);
this.emit("subscription", channel, username, methods, msg, tags);
break;

@@ -691,3 +713,3 @@

case "subgift":
this.emit("subgift", channel, username, streakMonths, recipient, methods, userstate);
this.emit("subgift", channel, username, streakMonths, recipient, methods, tags);
break;

@@ -698,3 +720,3 @@

case "anonsubgift":
this.emit("anonsubgift", channel, streakMonths, recipient, methods, userstate);
this.emit("anonsubgift", channel, streakMonths, recipient, methods, tags);
break;

@@ -704,3 +726,3 @@

case "submysterygift":
this.emit("submysterygift", channel, username, giftSubCount, methods, userstate);
this.emit("submysterygift", channel, username, giftSubCount, methods, tags);
break;

@@ -711,3 +733,3 @@

case "anonsubmysterygift":
this.emit("anonsubmysterygift", channel, giftSubCount, methods, userstate);
this.emit("anonsubmysterygift", channel, giftSubCount, methods, tags);
break;

@@ -717,3 +739,3 @@

case "primepaidupgrade":
this.emit("primepaidupgrade", channel, username, methods, userstate);
this.emit("primepaidupgrade", channel, username, methods, tags);
break;

@@ -723,4 +745,4 @@

case "giftpaidupgrade":
var sender = message.tags["msg-param-sender-name"] || message.tags["msg-param-sender-login"];
this.emit("giftpaidupgrade", channel, username, sender, userstate);
var sender = tags["msg-param-sender-name"] || tags["msg-param-sender-login"];
this.emit("giftpaidupgrade", channel, username, sender, tags);
break;

@@ -730,3 +752,3 @@

case "anongiftpaidupgrade":
this.emit("anongiftpaidupgrade", channel, username, userstate);
this.emit("anongiftpaidupgrade", channel, username, tags);
break;

@@ -736,6 +758,25 @@

case "raid":
var username = message.tags["msg-param-displayName"] || message.tags["msg-param-login"];
var viewers = message.tags["msg-param-viewerCount"];
this.emit("raided", channel, username, viewers);
var username = tags["msg-param-displayName"] || tags["msg-param-login"];
var viewers = +tags["msg-param-viewerCount"];
this.emit("raided", channel, username, viewers, tags);
break;
// Handle ritual
case "ritual":
var ritualName = tags["msg-param-ritual-name"];
switch(ritualName) {
// Handle new chatter ritual
case "new_chatter":
this.emit("newchatter", channel, username, tags, msg);
break;
// All unknown rituals should be passed through
default:
this.emit("ritual", ritualName, channel, username, tags, msg);
break;
}
break;
// All other msgid events should be emitted under a usernotice event
// until it comes up and needs to be added..
default:
this.emit("usernotice", msgid, channel, tags, msg);
break;
}

@@ -787,9 +828,8 @@

if(message.params.length > 1) {
var username = message.tags["login"];
var deletedMessage = msg;
var userstate = message.tags;
userstate["message-type"] = "messagedeleted";
var username = tags["login"];
tags["message-type"] = "messagedeleted";
this.log.info(`[${channel}] ${username}'s message has been deleted.`);
this.emit("messagedeleted", channel, username, deletedMessage, userstate);
this.emit("messagedeleted", channel, username, deletedMessage, tags);
}

@@ -802,4 +842,4 @@ break;

this.log.info(`Disconnecting and reconnecting in ${Math.round(this.reconnectTimer / 1000)} seconds..`);
this.disconnect();
setTimeout(() => this.connect(), this.reconnectTimer);
this.disconnect().catch(err => this.log.error(err));
setTimeout(() => this.connect().catch(err => this.log.error(err)), this.reconnectTimer);
break;

@@ -813,7 +853,7 @@

if(message.tags["user-type"] === "mod") {
if(!this.moderators[this.lastJoined]) {
this.moderators[this.lastJoined] = [];
if(!this.moderators[channel]) {
this.moderators[channel] = [];
}
if(!this.moderators[this.lastJoined].includes(this.username)) {
this.moderators[this.lastJoined].push(this.username);
if(!this.moderators[channel].includes(this.username)) {
this.moderators[channel].push(this.username);
}

@@ -824,3 +864,3 @@ }

if(!_.isJustinfan(this.getUsername()) && !this.userstate[channel]) {
this.userstate[channel] = message.tags;
this.userstate[channel] = tags;
this.lastJoined = channel;

@@ -837,3 +877,3 @@ this.channels.push(channel);

this.userstate[channel] = message.tags;
this.userstate[channel] = tags;
break;

@@ -843,3 +883,3 @@

case "GLOBALUSERSTATE":
this.globaluserstate = message.tags;
this.globaluserstate = tags;

@@ -872,4 +912,4 @@ // Received emote-sets..

else {
var minutes = ~~message.tags.slow;
var enabled = [channel, true, minutes];
var seconds = ~~message.tags.slow;
var enabled = [channel, true, seconds];
this.log.info(`[${channel}] This room is now in slow mode.`);

@@ -1035,21 +1075,37 @@ this.emits(["slow", "slowmode", "_promiseSlow"], [enabled, enabled, [null]]);

else {
var messagesLogLevel = _.get(this.opts.options.messagesLogLevel, "info")
// Message is an action (/me <message>)..
var actionMessage = _.actionMessage(msg);
if(actionMessage) {
message.tags["message-type"] = "action";
this.log.info(`[${channel}] *<${message.tags.username}>: ${actionMessage[1]}`);
this.emits(["action", "message"], [
[channel, message.tags, actionMessage[1], false]
]);
message.tags["message-type"] = actionMessage ? "action" : "chat";
msg = actionMessage ? actionMessage[1] : msg;
// Check for Bits prior to actions message
if (message.tags.hasOwnProperty("bits")) {
this.emit("cheer", channel, message.tags, msg);
}
else {
if(message.tags.hasOwnProperty("bits")) {
this.emit("cheer", channel, message.tags, msg);
//Handle Channel Point Redemptions (Require's Text Input)
if (message.tags.hasOwnProperty("msg-id")) {
if (message.tags["msg-id"] === "highlighted-message") {
var rewardtype = message.tags["msg-id"];
this.emit("redeem", channel, message.tags.username, rewardtype, message.tags, msg);
}
else if (message.tags["msg-id"] === "skip-subs-mode-message") {
var rewardtype = message.tags["msg-id"];
this.emit("redeem", channel, message.tags.username, rewardtype, message.tags, msg);
}
}
else if (message.tags.hasOwnProperty("custom-reward-id")) {
var rewardtype = message.tags["custom-reward-id"];
this.emit("redeem", channel, message.tags.username, rewardtype, message.tags, msg);
}
if(actionMessage) {
this.log[messagesLogLevel](`[${channel}] *<${message.tags.username}>: ${msg}`);
this.emits(["action", "message"], [
[channel, message.tags, msg, false]
]);
}
// Message is a regular chat message..
else {
message.tags["message-type"] = "chat";
this.log.info(`[${channel}] <${message.tags.username}>: ${msg}`);
this.log[messagesLogLevel](`[${channel}] <${message.tags.username}>: ${msg}`);
this.emits(["chat", "message"], [

@@ -1096,3 +1152,3 @@ [channel, message.tags, msg, false]

client.prototype._openConnection = function _openConnection() {
this.ws = new ws(`${this.secure ? "wss" : "ws"}://${this.server}:${this.port}/`, "irc");
this.ws = new _WebSocket(`${this.secure ? "wss" : "ws"}://${this.server}:${this.port}/`, "irc");

@@ -1130,2 +1186,5 @@ this.ws.onmessage = this._onMessage.bind(this);

}
else if(_.isJustinfan(this.username)) {
this.ws.send("PASS SCHMOOPIIE");
}
this.ws.send(`NICK ${this.username}`);

@@ -1187,3 +1246,3 @@ })

this.reconnecting = false;
this.connect();
this.connect().catch(err => this.log.error(err));
}, this.reconnectTimer);

@@ -1228,3 +1287,3 @@ }

this.reconnecting = false;
this.connect();
this.connect().catch(err => this.log.error(err));
}, this.reconnectTimer);

@@ -1268,3 +1327,8 @@ }

}
fn(resolve, reject);
if(typeof fn === 'function') {
fn(resolve, reject);
}
else {
resolve();
}
});

@@ -1315,2 +1379,4 @@ };

var messagesLogLevel = _.get(this.opts.options.messagesLogLevel, "info")
// Message is an action (/me <message>)..

@@ -1320,3 +1386,3 @@ var actionMessage = _.actionMessage(message);

userstate["message-type"] = "action";
this.log.info(`[${chan}] *<${this.getUsername()}>: ${actionMessage[1]}`);
this.log[messagesLogLevel](`[${chan}] *<${this.getUsername()}>: ${actionMessage[1]}`);
this.emits(["action", "message"], [

@@ -1330,3 +1396,3 @@ [chan, userstate, actionMessage[1], true]

userstate["message-type"] = "chat";
this.log.info(`[${chan}] <${this.getUsername()}>: ${message}`);
this.log[messagesLogLevel](`[${chan}] <${this.getUsername()}>: ${message}`);
this.emits(["chat", "message"], [

@@ -1336,3 +1402,8 @@ [chan, userstate, message, true]

}
fn(resolve, reject);
if(typeof fn === 'function') {
fn(resolve, reject);
}
else {
resolve();
}
});

@@ -1392,2 +1463,8 @@ };

// Determine if the client has a WebSocket and it's open..
client.prototype._isConnected = function _isConnected() {
return this.ws !== null && this.ws.readyState === 1;
}
// Disconnect from server..

@@ -1394,0 +1471,0 @@ client.prototype.disconnect = function disconnect() {

@@ -105,3 +105,3 @@ var _ = require("./utils");

// Send action message (/me <message>) on a channel..
action: function action(channel, message) {
action(channel, message) {
channel = _.channel(channel);

@@ -119,3 +119,3 @@ message = `\u0001ACTION ${message}\u0001`;

// Ban username on channel..
ban: function ban(channel, username, reason) {
ban(channel, username, reason) {
channel = _.channel(channel);

@@ -136,3 +136,3 @@ username = _.username(username);

// Clear all messages on a channel..
clear: function clear(channel) {
clear(channel) {
channel = _.channel(channel);

@@ -151,3 +151,3 @@

// Change the color of your username..
color: function color(channel, newColor) {
color(channel, newColor) {
newColor = _.get(newColor, channel);

@@ -166,3 +166,3 @@

// Run commercial on a channel for X seconds..
commercial: function commercial(channel, seconds) {
commercial(channel, seconds) {
channel = _.channel(channel);

@@ -181,5 +181,4 @@ seconds = _.get(seconds, 30);

// Delete a specific message on a channel
deletemessage: function deletemessage(channel, messageUUID) {
deletemessage(channel, messageUUID) {
channel = _.channel(channel);

@@ -198,3 +197,3 @@

// Enable emote-only mode on a channel..
emoteonly: function emoteonly(channel) {
emoteonly(channel) {
channel = _.channel(channel);

@@ -213,3 +212,3 @@

// Disable emote-only mode on a channel..
emoteonlyoff: function emoteonlyoff(channel) {
emoteonlyoff(channel) {
channel = _.channel(channel);

@@ -240,3 +239,3 @@

// Host a channel..
host: function host(channel, target) {
host(channel, target) {
channel = _.channel(channel);

@@ -256,3 +255,3 @@ target = _.username(target);

// Join a channel..
join: function join(channel) {
join(channel) {
channel = _.channel(channel);

@@ -285,3 +284,3 @@

// Mod username on channel..
mod: function mod(channel, username) {
mod(channel, username) {
channel = _.channel(channel);

@@ -301,3 +300,3 @@ username = _.username(username);

// Get list of mods on a channel..
mods: function mods(channel) {
mods(channel) {
channel = _.channel(channel);

@@ -329,3 +328,3 @@

// Send a ping to the server..
ping: function ping() {
ping() {
// Send the command to the server and race the Promise against a delay..

@@ -364,3 +363,3 @@ return this._sendCommand(this._getPromiseDelay(), null, "PING", (resolve, reject) => {

// Send a raw message to the server..
raw: function raw(message) {
raw(message) {
// Send the command to the server and race the Promise against a delay..

@@ -373,3 +372,3 @@ return this._sendCommand(this._getPromiseDelay(), null, message, (resolve, reject) => {

// Send a message on a channel..
say: function say(channel, message) {
say(channel, message) {
channel = _.channel(channel);

@@ -413,3 +412,3 @@

// Enable subscribers mode on a channel..
subscribers: function subscribers(channel) {
subscribers(channel) {
channel = _.channel(channel);

@@ -428,3 +427,3 @@

// Disable subscribers mode on a channel..
subscribersoff: function subscribersoff(channel) {
subscribersoff(channel) {
channel = _.channel(channel);

@@ -443,3 +442,3 @@

// Timeout username on channel for X seconds..
timeout: function timeout(channel, username, seconds, reason) {
timeout(channel, username, seconds, reason) {
channel = _.channel(channel);

@@ -467,3 +466,3 @@ username = _.username(username);

// Unban username on channel..
unban: function unban(channel, username) {
unban(channel, username) {
channel = _.channel(channel);

@@ -483,3 +482,3 @@ username = _.username(username);

// End the current hosting..
unhost: function unhost(channel) {
unhost(channel) {
channel = _.channel(channel);

@@ -498,3 +497,3 @@

// Unmod username on channel..
unmod: function unmod(channel, username) {
unmod(channel, username) {
channel = _.channel(channel);

@@ -514,3 +513,3 @@ username = _.username(username);

// Unvip username on channel..
unvip: function unvip(channel, username) {
unvip(channel, username) {
channel = _.channel(channel);

@@ -530,3 +529,3 @@ username = _.username(username);

// Add username to VIP list on channel..
vip: function vip(channel, username) {
vip(channel, username) {
channel = _.channel(channel);

@@ -546,3 +545,3 @@ username = _.username(username);

// Get list of VIPs on a channel..
vips: function vips(channel) {
vips(channel) {
channel = _.channel(channel);

@@ -561,3 +560,3 @@

// Send an whisper message to a user..
whisper: function whisper(username, message) {
whisper(username, message) {
username = _.username(username);

@@ -572,2 +571,12 @@

return this._sendCommand(this._getPromiseDelay(), "#tmijs", `/w ${username} ${message}`, (resolve, reject) => {
this.once("_promiseWhisper", (err) => {
if (err) { reject(err); }
});
}).catch((err) => {
// Either an "actual" error occured or the timeout triggered
// the latter means no errors have occured and we can resolve
// else just elevate the error
if(err && typeof err === 'string' && err.indexOf("No response from Twitch.") !== 0) {
throw err;
}
var from = _.channel(username),

@@ -586,8 +595,5 @@ userstate = _.merge({

]);
// At this time, there is no possible way to detect if a message has been sent has been eaten
// by the server, so we can only resolve the Promise.
resolve([username, message]);
return [username, message];
});
}
}

@@ -24,9 +24,2 @@ /*

if (!String.prototype.startsWith) {
String.prototype.startsWith = function(searchString, position) {
position = position || 0;
return this.indexOf(searchString, position) === position;
};
}
function EventEmitter() {

@@ -61,10 +54,2 @@ this._events = this._events || {};

// Emit multiple events..
EventEmitter.prototype.emits = function(types, values) {
for (var i = 0; i < types.length; i++) {
var val = i < values.length ? values[i] : values[values.length - 1];
this.emit.apply(this, [types[i]].concat(val));
}
}
EventEmitter.prototype.emit = function(type) {

@@ -71,0 +56,0 @@ var er, handler, len, args, i, listeners;

@@ -9,3 +9,3 @@ var _ = require("./utils");

// Return a console message depending on the logging level..
return function (message) {
return function(message) {
if(levels[level] >= levels[currentLevel]) {

@@ -19,3 +19,3 @@ console.log(`[${_.formatDate(new Date())}] ${level}: ${message}`);

// Change the current logging level..
setLevel: function(level) {
setLevel(level) {
currentLevel = level;

@@ -22,0 +22,0 @@ },

@@ -62,3 +62,3 @@ /*

// Parse Twitch badges..
badges: function badges(tags) {
badges(tags) {
return parseComplexTag(tags, "badges");

@@ -68,3 +68,3 @@ },

// Parse Twitch badge-info..
badgeInfo: function badgeInfo(tags) {
badgeInfo(tags) {
return parseComplexTag(tags, "badge-info");

@@ -74,3 +74,3 @@ },

// Parse Twitch emotes..
emotes: function emotes(tags) {
emotes(tags) {
return parseComplexTag(tags, "emotes", "/", ":", ",");

@@ -80,3 +80,3 @@ },

// Parse regex emotes..
emoteRegex: function emoteRegex(msg, code, id, obj) {
emoteRegex(msg, code, id, obj) {
nonspaceRegex.lastIndex = 0;

@@ -96,3 +96,3 @@ var regex = new RegExp("(\\b|^|\s)" + _.unescapeHtml(code) + "(\\b|$|\s)");

// Parse string emotes..
emoteString: function emoteString(msg, code, id, obj) {
emoteString(msg, code, id, obj) {
nonspaceRegex.lastIndex = 0;

@@ -112,3 +112,3 @@ var match;

// emote_id:first_index-last_index,another_first-another_last/another_emote_id:first_index-last_index
transformEmotes: function transformEmotes(emotes) {
transformEmotes(emotes) {
var transformed = "";

@@ -127,4 +127,13 @@

formTags(tags) {
var result = [];
for(var key in tags) {
var value = _.escapeIRC(tags[key]);
result.push(`${key}=${value}`);
}
return `@${result.join(';')}`;
},
// Parse Twitch messages..
msg: function msg(data) {
msg(data) {
var message = {

@@ -131,0 +140,0 @@ raw: data,

var actionMessageRegex = /^\u0001ACTION ([^\u0001]+)\u0001$/;
var justinFanRegex = /^(justinfan)(\d+$)/;
var unescapeIRCRegex = /\\([sn:r\\])/g;
var escapeIRCRegex = /([ \n;\r\\])/g;
var ircEscapedChars = { s: ' ', n: '', ':': ';', r: '' };
var ircUnescapedChars = { ' ': 's', '\n': 'n', ';': ':', '\r': 'r' };
var self = module.exports = {

@@ -74,2 +76,8 @@ // Return the second value if the first value is undefined..

),
escapeIRC: msg => !msg ? msg :
msg.replace(
escapeIRCRegex,
(m, p) => p in ircUnescapedChars ? `\\${ircUnescapedChars[p]}` : p
),

@@ -127,18 +135,2 @@ actionMessage: msg => msg.match(actionMessageRegex),

// Return whether inside a Chrome extension or not..
isExtension: () => {
try {
return window.chrome && chrome.runtime && chrome.runtime.id;
} catch(e) {}
return false;
},
// Return whether inside a React Native app..
isReactNative: () => {
try {
return navigator && navigator.product == "ReactNative";
} catch(e) {}
return false;
},
// Merge two objects..

@@ -145,0 +137,0 @@ merge: Object.assign,

{
"name": "tmi.js",
"version": "1.6.0",
"version": "1.7.0",
"description": "Javascript library for the Twitch Messaging Interface.",
"keywords": [
"tmi",
"tmijs",
"twitch",
"twitch.tv",
"stream",
"broadcast",
"chat",
"message",
"messaging",
"interface",
"subscriber",
"websocket",
"ws",
"bot",
"robot"
"bot"
],

@@ -31,3 +30,3 @@ "main": "index.js",

"scripts": {
"test": "istanbul cover node_modules/mocha/bin/_mocha -- --require should --exit",
"test": "nyc mocha -- --require should --exit",
"build": "npm-run-all --sequential build:*",

@@ -38,3 +37,3 @@ "build:rimraf": "rimraf ./build",

"build:browserify": "browserify index.js -o ./build/tmi.js",
"build:uglify": "uglifyjs --compress --mangle --output ./build/tmi.min.js --source-map ./build/tmi.js.map ./build/tmi.js",
"build:uglify": "uglifyjs --compress --mangle --output ./build/tmi.min.js --source-map \"filename='./build/tmi.js.map'\" ./build/tmi.js",
"build:sri": "node sri.js ./build/tmi.js",

@@ -52,21 +51,22 @@ "build:sri-min": "node sri.js ./build/tmi.min.js"

"dependencies": {
"request": "2.88.0",
"ws": "6.1.3"
"node-fetch": "2.6.1",
"ws": "7.4.0"
},
"devDependencies": {
"babel-preset-es2015": "6.6.0",
"babelify": "7.2.0",
"browserify": "13.0.0",
"hook-std": "0.2.0",
"istanbul": "0.4.5",
"mkdirp": "0.5.1",
"mocha": "5.2.0",
"npm-run-all": "1.7.0",
"rimraf": "2.5.2",
"should": "7.0.4",
"uglify-js": "2.6.2"
"@types/node-fetch": "2.5.7",
"babel-preset-env": "1.7.0",
"babelify": "10.0.0",
"browserify": "17.0.0",
"hook-std": "2.0.0",
"mkdirp": "1.0.4",
"mocha": "8.2.1",
"npm-run-all": "4.1.5",
"nyc": "15.1.0",
"rimraf": "3.0.2",
"should": "13.2.3",
"uglify-js": "3.11.6"
},
"browser": {
"ws": false,
"request": false
"node-fetch": false
},

@@ -79,3 +79,3 @@ "browserify": {

"presets": [
"es2015"
"env"
]

@@ -82,0 +82,0 @@ }

# tmi.js
[![Build Status](https://secure.travis-ci.org/tmijs/tmi.js.png?branch=master)](https://travis-ci.org/tmijs/tmi.js)
![Test Workflow Status](https://github.com/tmijs/tmi.js/workflows/Test/badge.svg)
[![Npm Version](https://img.shields.io/npm/v/tmi.js.svg?style=flat)](https://www.npmjs.org/package/tmi.js)

@@ -13,3 +13,3 @@ [![Downloads](https://img.shields.io/npm/dm/tmi.js.svg?style=flat)](https://www.npmjs.org/package/tmi.js)

[Documentation currently at tmijs/docs](https://github.com/tmijs/docs/tree/gh-pages/_posts) |
Changelog on the [release page](https://github.com/tmijs/tmi.js/releases)
[Changelog on the release page](https://github.com/tmijs/tmi.js/releases)

@@ -21,3 +21,3 @@ ## Install

```bash
npm i tmi.js
$ npm i tmi.js
```

@@ -28,4 +28,4 @@

const client = new tmi.Client({
options: { debug: true },
connections: {
options: { debug: true, messagesLogLevel: "info" },
connection: {
reconnect: true,

@@ -40,3 +40,3 @@ secure: true

});
client.connect();
client.connect().catch(console.error);
client.on('message', (channel, tags, message, self) => {

@@ -57,2 +57,8 @@ if(self) return;

```
```html
<script>
const client = new tmi.Client({ /* ... */ });
client.connect().catch(console.error);
</script>
```

@@ -74,3 +80,3 @@ #### Prebuilt Browser Releases

```bash
npm i -D @types/tmi.js
$ npm i -D @types/tmi.js
```

@@ -80,3 +86,3 @@

- Follow [@AlcaMagic on Twitter](https://twitter.com/AlcaMagic), [Alca on Twitch](https://www.twitch.tv/alca).
- Follow [@AlcaMagic on Twitter](https://twitter.com/AlcaMagic), [Alca on Twitch](https://twitch.tv/alca).
- Follow [@Schmoopiie on Twitter](https://twitter.com/Schmoopiie).

@@ -83,0 +89,0 @@ - Found a bug: [submit an issue.](https://github.com/tmijs/tmi.js/issues/new)

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc