UNPKG

keybase-bot

Version:
937 lines 43.9 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var child_process_1 = require("child_process"); var readline_1 = __importDefault(require("readline")); var client_base_1 = __importDefault(require("../client-base")); var utils_1 = require("../utils"); /** The chat module of your Keybase bot. For more info about the API this module uses, you may want to check out `keybase chat api`. */ var Chat = /** @class */ (function (_super) { __extends(Chat, _super); function Chat() { return _super !== null && _super.apply(this, arguments) || this; } /** * Lists your chats, with info on which ones have unread messages. * @memberof Chat * @param options - An object of options that can be passed to the method. * @returns - An array of chat conversations. If there are no conversations, the array is empty. * @example * const chatConversations = await bot.chat.list({unreadOnly: true}) * console.log(chatConversations) */ Chat.prototype.list = function (options) { return __awaiter(this, void 0, void 0, function () { var res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'list', options: options })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat list returned nothing.'); } return [2 /*return*/, res.conversations || []]; } }); }); }; /** * Lists conversation channels in a team * @memberof Chat * @param name - Name of the team * @param options - An object of options that can be passed to the method. * @returns - An array of chat conversations. If there are no conversations, the array is empty. * @example * bot.chat.listChannels('team_name').then(chatConversations => console.log(chatConversations)) */ Chat.prototype.listChannels = function (name, options) { return __awaiter(this, void 0, void 0, function () { var optionsWithDefaults, res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); optionsWithDefaults = __assign(__assign({}, options), { name: name, membersType: options && options.membersType ? options.membersType : 'team' }); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'listconvsonname', options: optionsWithDefaults, })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat list convs on name returned nothing.'); } return [2 /*return*/, res.conversations || []]; } }); }); }; Chat.prototype.getChannelOrConversationId = function (channelOrConversationId) { return __assign(__assign({}, (typeof channelOrConversationId === 'string' ? { conversationId: channelOrConversationId } : {})), (typeof channelOrConversationId === 'string' ? {} : { channel: channelOrConversationId })); }; /** * Reads the messages in a channel. You can read with or without marking as read. * @memberof Chat * @param channel - The chat channel to read messages in. * @param options - An object of options that can be passed to the method. * @returns - A summary of data about a message, including who send it, when, the content of the message, etc. If there are no messages in your channel, then an error is thrown. * @example * alice.chat.read(channel).then(messages => console.log(messages)) */ Chat.prototype.read = function (channelOrConversationId, options) { return __awaiter(this, void 0, void 0, function () { var conv, optionsWithDefaults, res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); conv = this.getChannelOrConversationId(channelOrConversationId); optionsWithDefaults = __assign(__assign(__assign({}, options), conv), { peek: options && options.peek ? options.peek : false, unreadOnly: options && options.unreadOnly !== undefined ? options.unreadOnly : false }); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'read', options: optionsWithDefaults })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat read returned nothing.'); } // Pagination gets passed as-is, while the messages get cleaned up return [2 /*return*/, { pagination: res.pagination, messages: res.messages.map(function (message) { return message.msg; }), }]; } }); }); }; /** * Joins a team conversation. * @param channel - The team chat channel to join. * @example * bot.chat.listConvsOnName('team_name').then(async teamConversations => { * for (const conversation of teamConversations) { * if (conversation.memberStatus !== 'active') { * await bot.chat.join(conversation.channel) * console.log('Joined team channel', conversation.channel) * } * } * }) */ Chat.prototype.joinChannel = function (channel) { return __awaiter(this, void 0, void 0, function () { var res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'join', options: { channel: channel, }, })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat join returned nothing'); } return [2 /*return*/]; } }); }); }; /** * Leaves a team conversation. * @param channel - The team chat channel to leave. * @example * bot.chat.listConvsOnName('team_name').then(async teamConversations => { * for (const conversation of teamConversations) { * if (conversation.memberStatus === 'active') { * await bot.chat.leave(conversation.channel) * console.log('Left team channel', conversation.channel) * } * } * }) */ Chat.prototype.leaveChannel = function (channel) { return __awaiter(this, void 0, void 0, function () { var res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'leave', options: { channel: channel, }, })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat leave returned nothing'); } return [2 /*return*/]; } }); }); }; /** * Send a message to a certain channel. * @memberof Chat * @param channel - The chat channel to send the message in. * @param message - The chat message to send. * @param options - An object of options that can be passed to the method. * @example * const channel = {name: 'kbot,' + bot.myInfo().username, public: false, topicType: 'chat'} * const message = {body: 'Hello kbot!'} * bot.chat.send(channel, message).then(() => console.log('message sent!')) */ Chat.prototype.send = function (channelOrConversationId, message, options) { var _a, _b; return __awaiter(this, void 0, void 0, function () { var conv, args, res; return __generator(this, function (_c) { switch (_c.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _c.sent(); conv = this.getChannelOrConversationId(channelOrConversationId); args = __assign(__assign(__assign(__assign({}, options), { explodingLifetime: ((_a = options) === null || _a === void 0 ? void 0 : _a.explodingLifetime) ? ((_b = options) === null || _b === void 0 ? void 0 : _b.explodingLifetime) + "ms" : undefined }), conv), { message: message }); this._adminDebugLogger.info("sending message \"" + message.body + "\" in conversation " + JSON.stringify(conv)); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'send', options: args, })]; case 2: res = _c.sent(); if (!res) { throw new Error('Keybase chat send returned nothing'); } this._adminDebugLogger.info("message sent with id " + res.id); return [2 /*return*/, res]; } }); }); }; /** * Creates a new blank conversation. * @memberof Chat * @param channel - The chat channel to create. * @example * bot.chat.createChannel(channel).then(() => console.log('conversation created')) */ Chat.prototype.createChannel = function (channel) { return __awaiter(this, void 0, void 0, function () { var args, res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); args = { channel: channel, }; return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'newconv', options: args, })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat newconv returned nothing'); } return [2 /*return*/]; } }); }); }; /** * Send a file to a channel. * @memberof Chat * @param channel - The chat channel to send the message in. * @param filename - The absolute path of the file to send. * @param options - An object of options that can be passed to the method. * @example * bot.chat.attach(channel, '/Users/nathan/my_picture.png').then(() => console.log('Sent a picture!')) */ Chat.prototype.attach = function (channelOrConversationId, filename, options) { var _a, _b; return __awaiter(this, void 0, void 0, function () { var conv, args, res; return __generator(this, function (_c) { switch (_c.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _c.sent(); conv = this.getChannelOrConversationId(channelOrConversationId); args = __assign(__assign(__assign(__assign({}, options), { explodingLifetime: ((_a = options) === null || _a === void 0 ? void 0 : _a.explodingLifetime) ? ((_b = options) === null || _b === void 0 ? void 0 : _b.explodingLifetime) + "ms" : undefined }), conv), { filename: filename }); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'attach', options: args })]; case 2: res = _c.sent(); if (!res) { throw new Error('Keybase chat attach returned nothing'); } return [2 /*return*/, res]; } }); }); }; /** * Download a file send via Keybase chat. * @memberof Chat * @param channel - The chat channel that the desired attacment to download is in. * @param messageId - The message id of the attached file. * @param output - The absolute path of where the file should be downloaded to. * @param options - An object of options that can be passed to the method * @example * bot.chat.download(channel, 325, '/Users/nathan/Downloads/file.png') */ Chat.prototype.download = function (channelOrConversationId, messageId, output, options) { return __awaiter(this, void 0, void 0, function () { var conv, args, res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); conv = this.getChannelOrConversationId(channelOrConversationId); args = __assign(__assign(__assign({}, options), conv), { messageId: messageId, output: output }); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'download', options: args })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat download returned nothing'); } return [2 /*return*/]; } }); }); }; /** * Reacts to a given message in a channel. Messages have messageId's associated with * them, which you can learn in `bot.chat.read`. * @memberof Chat * @param channel - The chat channel to send the message in. * @param messageId - The id of the message to react to. * @param reaction - The reaction emoji, in colon form. * @param options - An object of options that can be passed to the method. * @example * bot.chat.react(channel, 314, ':+1:').then(() => console.log('Thumbs up!')) */ Chat.prototype.react = function (channelOrConversationId, messageId, reaction) { return __awaiter(this, void 0, void 0, function () { var conv, args, res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); conv = this.getChannelOrConversationId(channelOrConversationId); args = __assign(__assign({}, conv), { messageId: messageId, message: { body: reaction } }); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'reaction', options: args })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat react returned nothing.'); } return [2 /*return*/, res]; } }); }); }; /** * Deletes a message in a channel. Messages have messageId's associated with * them, which you can learn in `bot.chat.read`. Known bug: the GUI has a cache, * and deleting from the CLI may not become apparent immediately. * @memberof Chat * @param channel - The chat channel to send the message in. * @param messageId - The id of the message to delete. * @param options - An object of options that can be passed to the method. * @example * bot.chat.delete(channel, 314).then(() => console.log('message deleted!')) */ Chat.prototype.delete = function (channelOrConversationId, messageId) { return __awaiter(this, void 0, void 0, function () { var conv, args, res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); conv = this.getChannelOrConversationId(channelOrConversationId); args = __assign(__assign({}, conv), { messageId: messageId }); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'delete', options: args })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat delete returned nothing.'); } return [2 /*return*/]; } }); }); }; /** * Gets current unfurling settings * @example * bot.chat.getUnfurlSettings().then((mode) => console.log(mode)) */ Chat.prototype.getUnfurlSettings = function () { return __awaiter(this, void 0, void 0, function () { var res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'getunfurlsettings', options: {} })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat get unfurl mode returned nothing.'); } return [2 /*return*/, res]; } }); }); }; /** * Sets the unfurling mode * In Keybase, unfurling means generating previews for links that you're sending * in chat messages. If the mode is set to always or the domain in the URL is * present on the whitelist, the Keybase service will automatically send a preview * to the message recipient in a background chat channel. * @param mode - the new unfurl mode * @example * bot.chat.setUnfurlMode({ * "mode": "always", * }).then((mode) => console.log('mode updated!')) */ Chat.prototype.setUnfurlSettings = function (mode) { return __awaiter(this, void 0, void 0, function () { var res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'setunfurlsettings', options: mode })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat set unfurl mode returned nothing.'); } return [2 /*return*/]; } }); }); }; /** * Gets device information for a given username. * This method allows you to see device name, description, type (desktop * or mobile), and creation time for all active devices of a given username. * @param username - the Keybase username to get devices for * @example * bot.chat.getDeviceInfo(username).then((devices) => console.log(devices)) */ Chat.prototype.getDeviceInfo = function (username) { return __awaiter(this, void 0, void 0, function () { var res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'getdeviceinfo', options: { username: username } })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat get device info returned nothing.'); } return [2 /*return*/, res]; } }); }); }; /** * Loads a flip's details * @param conversationID - conversation ID received in API listen. * @param flipConversationID - flipConvID from the message summary. * @param messageID - ID of the message in the conversation. * @param gameID - gameID from the flip message contents. * @example * // check demos/es7/poker-hands.js */ Chat.prototype.loadFlip = function (conversationID, flipConversationID, messageID, gameID) { return __awaiter(this, void 0, void 0, function () { var res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'loadflip', // The flip method uses `msg_id` as a parameter instead of `message_id`, like other chat methods // eslint-disable-next-line @typescript-eslint/camelcase options: utils_1.formatAPIObjectInput({ conversationID: conversationID, flipConversationID: flipConversationID, msg_id: messageID, gameID: gameID }, 'chat'), timeout: 2000, })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat load flip returned nothing.'); } return [2 /*return*/, res.status]; } }); }); }; /** * Publishes a commands advertisement which is shown in the "!" chat autocomplete. * @param advertisement - details of the advertisement * @example * await bot.chat.advertiseCommands({ * advertisements: [ * { * type: 'public', * commands: [ * { * name: '!echo', * description: 'Sends out your message to the current channel.', * usage: '[your text]', * }, * ] * } * ], * }) */ Chat.prototype.advertiseCommands = function (advertisement) { return __awaiter(this, void 0, void 0, function () { var res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'advertisecommands', options: advertisement })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat advertise commands returned nothing.'); } return [2 /*return*/]; } }); }); }; /** * Clears all published commands advertisements. * @param advertisement - advertisement parameters * @example * await bot.chat.clearCommands() */ Chat.prototype.clearCommands = function () { return __awaiter(this, void 0, void 0, function () { var res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'clearcommands' })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat clear commands returned nothing.'); } return [2 /*return*/]; } }); }); }; /** * Let's a conversation partner back in after they've reset their account. You can * get a list of such candidates with getResetConvMembers() * @param username - the username of the user who has reset * @param conversationId * @example * await bot.chat.addResetConvMember({username: "chris", conversationId: "abc1234567"}) */ Chat.prototype.addResetConvMember = function (param) { return __awaiter(this, void 0, void 0, function () { var res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'addresetconvmember', options: param })]; case 2: res = _a.sent(); if (!res) { throw new Error('addResetConvMember returned nothing.'); } return [2 /*return*/, res]; } }); }); }; /** * Lists all the direct (non-team) conversations your bot has, in * which their partner has "reset" their account and needs to be let back in * @example * await bot.chat.getResetConvMembers() */ Chat.prototype.getResetConvMembers = function () { return __awaiter(this, void 0, void 0, function () { var res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'getresetconvmembers' })]; case 2: res = _a.sent(); if (!res) { throw new Error('getResetConvMembers returned nothing.'); } return [2 /*return*/, res]; } }); }); }; /** * Lists all commands advertised in a channel. * @param lookup - either conversation id or channel * @example * const commandsList = await bot.chat.listCommands({ * channel: channel, * }) * console.log(commandsList) * // prints out something like: * // { * // commands: [ * // { * // name: '!helloworld', * // description: 'sample description', * // usage: '[command arguments]', * // username: 'userwhopublished', * // } * // ] * // } */ Chat.prototype.listCommands = function (lookup) { return __awaiter(this, void 0, void 0, function () { var res; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [4 /*yield*/, this._runApiCommand({ apiName: 'chat', method: 'listcommands', options: lookup })]; case 2: res = _a.sent(); if (!res) { throw new Error('Keybase chat list commands returned nothing.'); } return [2 /*return*/, { commands: res.commands || [] }]; } }); }); }; /** * Listens for new chat messages on a specified channel. The `onMessage` function is called for every message your bot receives. This is pretty similar to `watchAllChannelsForNewMessages`, except it specifically checks one channel. Note that it receives messages your own bot posts, but from other devices. You can filter out your own messages by looking at a message's sender object. * Hides exploding messages by default. * @memberof Chat * @param channel - The chat channel to watch. * @param onMessage - A callback that is triggered on every message your bot receives. * @param onError - A callback that is triggered on any error that occurs while the method is executing. * @param options - Options for the listen method. * @example * // Reply to all messages between you and `kbot` with 'thanks!' * const channel = {name: 'kbot,' + bot.myInfo().username, public: false, topicType: 'chat'} * const onMessage = message => { * const channel = message.channel * bot.chat.send(channel, {body: 'thanks!!!'}) * } * bot.chat.watchChannelForNewMessages(channel, onMessage) */ Chat.prototype.watchChannelForNewMessages = function (channel, onMessage, onError, options) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [2 /*return*/, this._chatListenMessage(onMessage, onError, channel, options)]; } }); }); }; /** * This function will put your bot into full-read mode, where it reads * everything it can and every new message it finds it will pass to you, so * you can do what you want with it. For example, if you want to write a * Keybase bot that talks shit at anyone who dares approach it, this is the * function to use. Note that it receives messages your own bot posts, but from other devices. * You can filter out your own messages by looking at a message's sender object. * Hides exploding messages by default. * @memberof Chat * @param onMessage - A callback that is triggered on every message your bot receives. * @param onError - A callback that is triggered on any error that occurs while the method is executing. * @param options - Options for the listen method. * @example * // Reply to incoming traffic on all channels with 'thanks!' * const onMessage = message => { * const channel = message.channel * bot.chat.send(channel, {body: 'thanks!!!'}) * } * bot.chat.watchAllChannelsForNewMessages(onMessage) * */ Chat.prototype.watchAllChannelsForNewMessages = function (onMessage, onError, options) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [2 /*return*/, this._chatListenMessage(onMessage, onError, undefined, options)]; } }); }); }; /** * This function watches for new conversations your bot is added into. This gives your bot a chance to say hi when it's added/installed into a conversation. * @param onConv - A callback that is triggered when the bot is added into a conversation. * @param onError - A callback that is triggered on any error that occurs while the method is executing. * @example * // Say hi * const onConv = conv => { * const channel = conv.channel * bot.chat.send(channel, {body: 'Hi!'}) * } * bot.chat.watchForNewConversation(onConv) * */ Chat.prototype.watchForNewConversation = function (onConv, onError) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._guardInitialized()]; case 1: _a.sent(); return [2 /*return*/, this._chatListenConvs(onConv, onError)]; } }); }); }; Chat.prototype._spawnChatListenChild = function (args, onLine) { var _this = this; return new Promise(function (resolve, reject) { var child = child_process_1.spawn(_this._pathToKeybaseBinary(), args); _this._spawnedProcesses.push(child); var cmdSample = _this._pathToKeybaseBinary() + ' ' + args.join(' '); _this._adminDebugLogger.info("beginning listen using " + cmdSample); var lineReaderStderr = readline_1.default.createInterface({ input: child.stderr }); var stdErrBuffer = []; child.on('error', function (err) { _this._adminDebugLogger.error("got listen error " + err.message); }); child.on('exit', function () { _this._adminDebugLogger.info("got listen exit"); }); child.on('close', function (code) { _this._adminDebugLogger.info("got listen close, code " + code); if (code) { return _this._deinitializing ? resolve() : reject(new Error(stdErrBuffer.join('\n'))); } resolve(); }); child.on('disconnect', function () { _this._adminDebugLogger.info("got listen disconnect"); }); lineReaderStderr.on('line', function (line) { stdErrBuffer.push(line); _this._adminDebugLogger.error("stderr from listener: " + line); }); var lineReaderStdout = readline_1.default.createInterface({ input: child.stdout }); lineReaderStdout.on('line', onLine); }); }; Chat.prototype._getChatListenArgs = function (channel, options) { var args = ['chat', 'api-listen']; if (this.homeDir) { args.unshift('--home', this.homeDir); } if (!options || (options && options.hideExploding !== false)) { args.push('--hide-exploding'); } if (options && options.showLocal === true) { args.push('--local'); } if (channel) { args.push('--filter-channel', JSON.stringify(utils_1.formatAPIObjectInput(channel, 'chat'))); } return args; }; /** * Spawns the chat listen process and handles the calling of onMessage, onError, and filtering for a specific channel. * @memberof Chat * @ignore * @param onMessage - A callback that is triggered on every message your bot receives. * @param onError - A callback that is triggered on any error that occurs while the method is executing. * @param channel - The chat channel to watch. * @param options - Options for the listen method. * @example * this._chatListenMessage(onMessage, onError) */ Chat.prototype._chatListenMessage = function (onMessage, onError, channel, options) { var _this = this; var args = this._getChatListenArgs(channel, options); var onLine = function (line) { _this._adminDebugLogger.info("stdout from listener: " + line); try { var messageObject = utils_1.formatAPIObjectOutput(JSON.parse(line)); if (messageObject.hasOwnProperty('error')) { throw new Error(messageObject.error); } if (messageObject.type !== 'chat' || !messageObject.msg) { return; } var msgNotification = messageObject; if ( // fire onMessage if it was from a different sender or at least a different device // from this sender. Bots can filter out their own messages from other devices. (options && options.showLocal) || (_this.username && _this.devicename && (msgNotification.msg.sender.username !== _this.username.toLowerCase() || msgNotification.msg.sender.deviceName !== _this.devicename))) { onMessage(msgNotification.msg); } } catch (error) { if (onError) { onError(error); } } }; this._adminDebugLogger.info("spawningChatListenChild on channel=" + JSON.stringify(channel || 'ALL')); return this._spawnChatListenChild(args, onLine); }; /** * Spawns the chat listen process for new channels and handles the calling of onConv, and onError. * @memberof Chat * @ignore * @param onConv - A callback that is triggered on every new channel your bot is added to. * @param onError - A callback that is triggered on any error that occurs while the method is executing. * @example * this._chatListenConvs(onConv, onError) */ Chat.prototype._chatListenConvs = function (onConv, onError) { var _this = this; var args = this._getChatListenArgs(); args.push('--convs'); this._adminDebugLogger.info("spawningChatListenChild for convs"); return this._spawnChatListenChild(args, function (line) { _this._adminDebugLogger.info("stdout from listener: " + line); try { var messageObject = utils_1.formatAPIObjectOutput(JSON.parse(line)); if (messageObject.hasOwnProperty('error')) { throw new Error(messageObject.error); } if (messageObject.type !== 'chat_conv' || !messageObject.conv) { return; } var convNotification = messageObject; convNotification.conv && onConv(convNotification.conv); } catch (error) { if (onError) { onError(error); } } }); }; return Chat; }(client_base_1.default)); exports.default = Chat; //# sourceMappingURL=index.js.map