UNPKG

@idoctor-devs/event-logger

Version:

NPM библиотека для отправки событий и сообщений в мессенджеры из веб-приложений

217 lines (216 loc) 7.23 kB
function escapeMarkdownV2(text) { const specialChars = /[().-]/g; return text.replace(specialChars, "\\$&"); } async function sendTelegramMessage(botToken, chatId, message, options = {}) { const { timeout = 5e3, retryAttempts = 3 } = options; const url = `https://api.telegram.org/bot${botToken}/sendMessage`; const payload = { chat_id: chatId, text: escapeMarkdownV2(message), parse_mode: "MarkdownV2" }; for (let attempt = 1; attempt <= retryAttempts; attempt++) { try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), signal: controller.signal }); clearTimeout(timeoutId); if (response.ok) { return true; } const errorData = await response.json().catch(() => ({})); console.warn(`Telegram API error (attempt ${attempt}):`, { status: response.status, statusText: response.statusText, error: errorData }); if (attempt === retryAttempts) { return false; } await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 1e3)); } catch (error) { console.warn(`Network error (attempt ${attempt}):`, error); if (attempt === retryAttempts) { return false; } await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 1e3)); } } return false; } class BaseProvider { } class TelegramProvider extends BaseProvider { constructor(config) { super(); this.config = config; } async send(message, level, metadata) { try { const formattedMessage = this.formatMessage(message, level, metadata); const success = await sendTelegramMessage(this.config.botToken, this.config.chatId, formattedMessage, { timeout: this.config.timeout || 5e3, retryAttempts: this.config.retryAttempts || 3 }); return success; } catch (error) { console.error("TelegramProvider send error:", error); return false; } } getBotToken() { return this.config.botToken; } getChatId() { return this.config.chatId; } formatDate(date = /* @__PURE__ */ new Date()) { const data = typeof date === "string" ? new Date(date) : date; const day = String(data.getDate()).padStart(2, "0"); const month = String(data.getMonth() + 1).padStart(2, "0"); const year = data.getFullYear(); const hours = String(data.getHours()).padStart(2, "0"); const minutes = String(data.getMinutes()).padStart(2, "0"); const seconds = String(data.getSeconds()).padStart(2, "0"); return `${day}.${month}.${year} ${hours}.${minutes}.${seconds}`; } formatMessage(message, level, metadata) { const timestamp = this.formatDate(); const levelEmoji = this.getLevelEmoji(level); let formattedMessage = `${levelEmoji} [${level.toUpperCase()}] ${timestamp}`; if (metadata && Object.keys(metadata).length > 0) { formattedMessage += "\n\n*METADATA*\n"; for (const [key, value] of Object.entries(metadata)) { formattedMessage += ` *${key}*: ${value}`; } formattedMessage += "\n"; } formattedMessage += ` ${message}`; return formattedMessage; } getLevelEmoji(level) { const emojiMap = { log: "📝", info: "ℹ️", warn: "⚠️", error: "❌" }; return emojiMap[level]; } } class ValidationError extends Error { constructor(message) { super(message); this.name = "ValidationError"; } } function validateEventLoggerConfig(config) { if (!config) { throw new ValidationError("Configuration is required"); } if (!config.environment) { throw new ValidationError("Environment is required"); } if (config.environment !== "browser") { throw new ValidationError('Only "browser" environment is supported'); } if (!config.providers || !Array.isArray(config.providers)) { throw new ValidationError("Providers array is required"); } if (config.providers.length === 0) { throw new ValidationError("At least one provider is required"); } config.providers.forEach((provider, index) => { validateTelegramProviderConfig(provider, index); }); } function validateTelegramProviderConfig(config, index) { const providerPrefix = index !== void 0 ? `Provider[${index}]: ` : ""; if (!config) { throw new ValidationError(`${providerPrefix}Provider configuration is required`); } if (config.type !== "telegram") { throw new ValidationError(`${providerPrefix}Only "telegram" provider type is supported`); } if (!config.botToken || typeof config.botToken !== "string") { throw new ValidationError(`${providerPrefix}Bot token is required and must be a string`); } if (!config.botToken.trim()) { throw new ValidationError(`${providerPrefix}Bot token cannot be empty`); } if (!config.chatId || typeof config.chatId !== "string") { throw new ValidationError(`${providerPrefix}Chat ID is required and must be a string`); } if (!config.chatId.trim()) { throw new ValidationError(`${providerPrefix}Chat ID cannot be empty`); } if (config.timeout !== void 0) { if (typeof config.timeout !== "number" || config.timeout <= 0) { throw new ValidationError(`${providerPrefix}Timeout must be a positive number`); } } if (config.retryAttempts !== void 0) { if (typeof config.retryAttempts !== "number" || config.retryAttempts < 0) { throw new ValidationError(`${providerPrefix}Retry attempts must be a non-negative number`); } } } class EventLogger { constructor(config) { this.providers = []; validateEventLoggerConfig(config); this.config = config; this.initializeProviders(); } initializeProviders() { for (const providerConfig of this.config.providers) { if (providerConfig.type === "telegram") { const provider = new TelegramProvider(providerConfig); this.providers.push(provider); } } } async log(message, metadata) { await this.sendToAllProviders(message, "log", metadata); } async info(message, metadata) { await this.sendToAllProviders(message, "info", metadata); } async warn(message, metadata) { await this.sendToAllProviders(message, "warn", metadata); } async error(message, metadata) { await this.sendToAllProviders(message, "error", metadata); } async sendToAllProviders(message, level, metadata) { if ((!message || typeof message !== "string") && !metadata) { console.warn("EventLogger: Message must be a non-empty string or metadata must be provided"); return; } const sendPromises = this.providers.map(async (provider) => { try { await provider.send(message, level, metadata); } catch (error) { console.error(`EventLogger: Failed to send message via provider:`, error); } }); await Promise.allSettled(sendPromises); } } export { BaseProvider, EventLogger, TelegramProvider, ValidationError }; //# sourceMappingURL=event-logger.es.js.map