@racla-dev/node-iris
Version:
TypeScript port of Python irispy-client module for KakaoTalk bot development
322 lines • 12.1 kB
JavaScript
"use strict";
/**
* Core classes for node-iris: Room, User, Avatar, ChatContext, ErrorContext
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorContext = exports.ChatContext = exports.User = exports.Avatar = exports.Room = void 0;
const utils_1 = require("@/utils");
const logger_1 = require("@/utils/logger");
const message_1 = require("./message");
class Room {
constructor(id, name, api) {
this.id = (0, utils_1.toSafeId)(id);
this.name = name;
this._api = api;
}
/**
* Get ID as string for API compatibility
*/
getIdAsString() {
return (0, utils_1.idToString)(this.id);
}
/**
* Get ID as BigInt for numeric operations
*/
getIdAsBigInt() {
return this.id;
}
async getType() {
if (this._type !== undefined) {
return this._type;
}
try {
const results = await this._api.query('SELECT type FROM chat_rooms WHERE id = ?', [this.getIdAsString()]);
if (results && results[0]) {
this._type = results[0].type;
return this._type;
}
this._type = null;
return null;
}
catch (error) {
this._type = null;
return null;
}
}
toString() {
return `Room(id=${this.getIdAsString()}, name=${this.name})`;
}
}
exports.Room = Room;
class Avatar {
constructor(id, chatId, api) {
this.logger = new logger_1.Logger('Avatar');
this._id = (0, utils_1.toSafeId)(id);
this._chatId = (0, utils_1.toSafeId)(chatId);
this._api = api;
}
getIdAsString() {
return (0, utils_1.idToString)(this._id);
}
getChatIdAsString() {
return (0, utils_1.idToString)(this._chatId);
}
getIdAsBigInt() {
return this._id;
}
async getUrl() {
if (this._url !== undefined) {
return this._url;
}
try {
let results;
if (this.getIdAsBigInt() < 10000000000n) {
results = await this._api.query('SELECT T2.o_profile_image_url FROM chat_rooms AS T1 JOIN db2.open_profile AS T2 ON T1.link_id = T2.link_id WHERE T1.id = ?', [this.getChatIdAsString()]);
this._url = results[0]?.o_profile_image_url || null;
}
else {
results = await this._api.query('SELECT original_profile_image_url, enc FROM db2.open_chat_member WHERE user_id = ?', [this.getIdAsString()]);
this._url = results[0]?.original_profile_image_url || null;
}
return this._url;
}
catch (error) {
this._url = null;
return null;
}
}
async getImg() {
if (this._img !== undefined) {
return this._img;
}
const url = await this.getUrl();
if (!url) {
this._img = null;
return null;
}
try {
const axios = require('axios');
const response = await axios.get(url, {
responseType: 'arraybuffer',
headers: { 'User-Agent': 'Mozilla/5.0 (compatible; node-iris)' },
});
this._img = Buffer.from(response.data);
return this._img;
}
catch (error) {
this.logger.error('Failed to load avatar image:', error);
this._img = null;
return null;
}
}
toString() {
return `Avatar(url=${this._url})`;
}
}
exports.Avatar = Avatar;
class User {
constructor(id, chatId, api, name, botId) {
this.id = (0, utils_1.toSafeId)(id);
this._chatId = (0, utils_1.toSafeId)(chatId);
this._api = api;
this._name = name;
this._botId = botId ? (0, utils_1.toSafeId)(botId) : undefined;
this.avatar = new Avatar(this.id, this._chatId, api);
}
getIdAsString() {
return (0, utils_1.idToString)(this.id);
}
getChatIdAsString() {
return (0, utils_1.idToString)(this._chatId);
}
getIdAsBigInt() {
return this.id;
}
async getName() {
if (this._name !== undefined) {
return this._name;
}
try {
let results;
if (this.id === this._botId) {
results = await this._api.query('SELECT T2.nickname FROM chat_rooms AS T1 JOIN db2.open_profile AS T2 ON T1.link_id = T2.link_id WHERE T1.id = ?', [this._chatId]);
this._name = results[0]?.nickname || null;
}
else if (BigInt(this.id) < 10000000000n) {
results = await this._api.query('SELECT name, enc FROM db2.friends WHERE id = ?', [this.id]);
this._name = results[0]?.name || null;
}
else {
results = await this._api.query('SELECT nickname, enc FROM db2.open_chat_member WHERE user_id = ?', [this.id]);
this._name = results[0]?.nickname || null;
}
return this._name;
}
catch (error) {
this._name = null;
return null;
}
}
async getType() {
if (this._type !== undefined) {
return this._type;
}
try {
let results;
if (this.id === this._botId) {
results = await this._api.query('SELECT T2.link_member_type FROM chat_rooms AS T1 INNER JOIN open_profile AS T2 ON T1.link_id = T2.link_id WHERE T1.id = ?', [this._chatId]);
}
else {
results = await this._api.query('SELECT link_member_type FROM db2.open_chat_member WHERE user_id = ?', [this.id]);
}
const memberType = parseInt(results[0]?.link_member_type || '0');
switch (memberType) {
case 1:
this._type = 'HOST';
break;
case 2:
this._type = 'NORMAL';
break;
case 4:
this._type = 'MANAGER';
break;
case 8:
this._type = 'BOT';
break;
default:
this._type = 'UNKNOWN';
}
return this._type;
}
catch (error) {
this._type = 'REAL_PROFILE';
return this._type;
}
}
toString() {
return `User(name=${this._name})`;
}
}
exports.User = User;
class ChatContext {
constructor(room, sender, message, raw, api) {
this.logger = new logger_1.Logger('ChatContext');
this.room = room;
this.sender = sender;
this.message = message;
this.raw = raw;
this.api = api;
}
async reply(message, roomId) {
const targetRoomId = roomId || this.room.id;
const roomIdString = typeof targetRoomId === 'string' || typeof targetRoomId === 'number'
? (0, utils_1.idToString)(targetRoomId)
: this.room.getIdAsString();
await this.api.reply(roomIdString, message);
}
async replyMedia(files, roomId) {
const targetRoomId = roomId || this.room.id;
const roomIdString = typeof targetRoomId === 'string' || typeof targetRoomId === 'number'
? (0, utils_1.idToString)(targetRoomId)
: this.room.getIdAsString();
await this.api.replyMedia(roomIdString, files);
}
/**
* Reply with images from URLs - automatically downloads and converts to base64
* @param imageUrls - Array of image URLs to download and send
* @param roomId - Optional room ID (defaults to current room)
*/
async replyImageUrls(imageUrls, roomId) {
const targetRoomId = roomId || this.room.id;
// Temporary cast until interface is updated
await this.api.replyImageUrls(targetRoomId, imageUrls);
}
/**
* Reply with a single image from URL
* @param imageUrl - Image URL to download and send
* @param roomId - Optional room ID (defaults to current room)
*/
async replyImageUrl(imageUrl, roomId) {
const targetRoomId = roomId || this.room.id;
// Temporary cast until interface is updated
await this.api.replyImageUrl(targetRoomId, imageUrl);
}
async getSource() {
// Check if this message is a reply
const replyData = this.raw.attachment?.reply;
if (!replyData) {
return null;
}
try {
// Get the source message from the API
const sourceMessage = await this.api.query('SELECT * FROM messages WHERE id = ? AND chat_id = ?', [replyData.src_logId, this.room.id]);
if (!sourceMessage || sourceMessage.length === 0) {
return null;
}
// Create ChatContext for source message
const source = sourceMessage[0];
const sourceRoom = new Room(this.room.id, this.room.name, this.api);
const sourceUser = new User(source.user_id, // parseInt 제거
this.room.id, this.api, source.sender_name);
const sourceMsg = new message_1.Message(source.id, // parseInt 제거
parseInt(source.type), source.message, source.attachment, (0, utils_1.safeJsonParseWithReviver)(source.v || '{}'));
return new ChatContext(sourceRoom, sourceUser, sourceMsg, source, this.api);
}
catch (error) {
this.logger.error('Failed to get source message:', error);
return null;
}
}
async getNextChat(n = 1) {
try {
const nextMessages = await this.api.query('SELECT * FROM messages WHERE chat_id = ? AND id > ? ORDER BY id ASC LIMIT ?', [this.room.id, this.message.id, n]);
if (!nextMessages || nextMessages.length === 0) {
return null;
}
const next = nextMessages[n - 1] || nextMessages[nextMessages.length - 1];
const nextRoom = new Room(this.room.id, this.room.name, this.api);
const nextUser = new User(next.user_id, // parseInt 제거
this.room.id, this.api, next.sender_name);
const nextMsg = new message_1.Message(next.id, // parseInt 제거
parseInt(next.type), next.message, next.attachment, (0, utils_1.safeJsonParseWithReviver)(next.v || '{}'));
return new ChatContext(nextRoom, nextUser, nextMsg, next, this.api);
}
catch (error) {
this.logger.error('Failed to get next chat:', error);
return null;
}
}
async getPreviousChat(n = 1) {
try {
const prevMessages = await this.api.query('SELECT * FROM messages WHERE chat_id = ? AND id < ? ORDER BY id DESC LIMIT ?', [this.room.id, this.message.id, n]);
if (!prevMessages || prevMessages.length === 0) {
return null;
}
const prev = prevMessages[n - 1] || prevMessages[prevMessages.length - 1];
const prevRoom = new Room(this.room.id, this.room.name, this.api);
const prevUser = new User(prev.user_id, // parseInt 제거
this.room.id, this.api, prev.sender_name);
const prevMsg = new message_1.Message(prev.id, // parseInt 제거
parseInt(prev.type), prev.message, prev.attachment, (0, utils_1.safeJsonParseWithReviver)(prev.v || '{}'));
return new ChatContext(prevRoom, prevUser, prevMsg, prev, this.api);
}
catch (error) {
this.logger.error('Failed to get previous chat:', error);
return null;
}
}
}
exports.ChatContext = ChatContext;
class ErrorContext {
constructor(event, func, exception, args) {
this.event = event;
this.func = func;
this.exception = exception;
this.args = args;
}
toString() {
return `ErrorContext(event=${this.event}, error=${this.exception.message})`;
}
}
exports.ErrorContext = ErrorContext;
//# sourceMappingURL=classes.js.map