UNPKG

@meshed-monitor/sdk

Version:

Official JavaScript/TypeScript SDK for MeshedMonitor - All-in-one monitoring platform. Supports both CommonJS and ES Modules.

378 lines (376 loc) 12.6 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { MeshedMonitor: () => MeshedMonitor, SupportWidget: () => SupportWidget, default: () => index_default }); module.exports = __toCommonJS(index_exports); var MeshedMonitor = class { constructor(config) { this.logQueue = []; this.config = { apiUrl: "https://api.meshedmonitor.com", environment: "production", enableErrorTracking: true, enableLogStreaming: true, enableSupport: true, maxBatchSize: 50, flushInterval: 5e3, // 5 seconds ...config }; this.initialize(); } initialize() { if (this.config.enableErrorTracking && typeof window !== "undefined") { this.setupGlobalErrorHandling(); } if (this.config.enableLogStreaming) { this.startLogFlushTimer(); } } setupGlobalErrorHandling() { if (typeof window === "undefined") return; window.addEventListener("error", (event) => { this.captureError({ message: event.message, stack: event.error?.stack, level: "ERROR", file: event.filename, line: event.lineno, column: event.colno, url: window.location.href, userAgent: navigator.userAgent }); }); window.addEventListener("unhandledrejection", (event) => { this.captureError({ message: event.reason?.message || "Unhandled Promise Rejection", stack: event.reason?.stack, level: "ERROR", url: window.location.href, userAgent: navigator.userAgent, context: { type: "unhandledrejection", reason: event.reason } }); }); } startLogFlushTimer() { if (this.flushTimer) { clearInterval(this.flushTimer); } this.flushTimer = setInterval(() => { this.flushLogs(); }, this.config.flushInterval); } // Error tracking methods async captureError(error) { if (!this.config.enableErrorTracking) return; try { const errorData = { ...error, environment: error.context?.environment || this.config.environment, release: error.context?.release || this.config.release, userId: error.userId || this.config.userId, timestamp: (/* @__PURE__ */ new Date()).toISOString() }; await this.sendRequest("/api/sdk/errors", errorData); } catch (err) { if (this.config.debug) { console.error("Failed to capture error:", err); } } } captureException(error, context) { return this.captureError({ message: error.message, stack: error.stack, level: "ERROR", context, url: typeof window !== "undefined" ? window.location.href : void 0, userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0 }); } // Logging methods log(level, message, context) { if (!this.config.enableLogStreaming) return; const logData = { level, message, userId: this.config.userId, context, timestamp: /* @__PURE__ */ new Date() }; this.logQueue.push(logData); if (this.logQueue.length >= this.config.maxBatchSize) { this.flushLogs(); } } debug(message, context) { this.log("DEBUG", message, context); } info(message, context) { this.log("INFO", message, context); } warn(message, context) { this.log("WARN", message, context); } error(message, context) { this.log("ERROR", message, context); } // Manually flush all queued logs async flush() { await this.flushLogs(); } async flushLogs() { if (this.logQueue.length === 0) return; const logs = this.logQueue.splice(0, this.config.maxBatchSize); try { await this.sendRequest("/api/sdk/logs/batch", { logs }); } catch (err) { if (this.config.debug) { console.error("Failed to flush logs:", err); } this.logQueue.unshift(...logs); } } // Support ticket methods async createSupportTicket(ticket) { if (!this.config.enableSupport) { throw new Error("Support is not enabled"); } const ticketData = { ...ticket, userId: ticket.userId || this.config.userId, environment: ticket.metadata?.environment || this.config.environment, userAgent: ticket.userAgent || (typeof navigator !== "undefined" ? navigator.userAgent : void 0), url: ticket.url || (typeof window !== "undefined" ? window.location.href : void 0) }; return this.sendRequest("/api/sdk/support/tickets", ticketData); } // Metric tracking methods async trackMetric(metric) { try { await this.sendRequest("/api/metrics/track", metric); } catch (err) { if (this.config.debug) { console.error("Failed to track metric:", err); } } } async trackMetrics(metrics) { try { await this.sendRequest("/api/metrics/track/batch", { metrics }); } catch (err) { if (this.config.debug) { console.error("Failed to track metrics:", err); } } } // User context methods setUser(userId) { this.config.userId = userId; } setEnvironment(environment) { this.config.environment = environment; } setRelease(release) { this.config.release = release; } // Utility methods async health() { return this.sendRequest("/api/sdk/health", {}, "GET"); } async sendRequest(endpoint, data = {}, method = "POST") { const url = `${this.config.apiUrl}${endpoint}`; const options = { method, headers: { "Content-Type": "application/json", "Authorization": `Bearer ${this.config.apiKey}` } }; if (method === "POST") { options.body = JSON.stringify(data); } const response = await fetch(url, options); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return response.json(); } // Cleanup destroy() { if (this.flushTimer) { clearInterval(this.flushTimer); } this.flushLogs(); } }; var SupportWidget = class { constructor(monitor) { this.monitor = monitor; } show(options) { if (typeof document === "undefined") return; this.hide(); const position = options?.position || "bottom-right"; const theme = options?.theme || "light"; this.container = document.createElement("div"); this.container.id = "meshed-support-widget"; this.container.innerHTML = this.getWidgetHTML(theme); this.container.style.cssText = this.getWidgetCSS(position); document.body.appendChild(this.container); this.attachEventListeners(); } hide() { if (this.container) { this.container.remove(); this.container = void 0; } } getWidgetHTML(theme) { return ` <div class="widget-button ${theme}"> <span>\u{1F4AC}</span> </div> <div class="widget-panel ${theme}" style="display: none;"> <div class="widget-header"> <h3>Need Help?</h3> <button class="close-btn">\xD7</button> </div> <div class="widget-content"> <div class="ticket-type-selection"> <h4>What can we help you with?</h4> <button class="ticket-type-btn" data-type="SUPPORT_REQUEST">\u{1F4AC} Get Support</button> <button class="ticket-type-btn" data-type="BUG_REPORT">\u{1F41B} Report Bug</button> <button class="ticket-type-btn" data-type="FEATURE_REQUEST">\u{1F4A1} Request Feature</button> </div> <div class="ticket-form" style="display: none;"> <form id="support-form"> <input type="hidden" id="ticket-type" /> <div class="form-group"> <label for="user-name">Name</label> <input type="text" id="user-name" required /> </div> <div class="form-group"> <label for="user-email">Email</label> <input type="email" id="user-email" required /> </div> <div class="form-group"> <label for="ticket-title">Title</label> <input type="text" id="ticket-title" required /> </div> <div class="form-group"> <label for="ticket-description">Description</label> <textarea id="ticket-description" rows="4" required></textarea> </div> <div class="form-actions"> <button type="button" class="back-btn">Back</button> <button type="submit">Submit</button> </div> </form> </div> </div> </div> `; } getWidgetCSS(position) { const positions = { "bottom-right": "bottom: 20px; right: 20px;", "bottom-left": "bottom: 20px; left: 20px;", "top-right": "top: 20px; right: 20px;", "top-left": "top: 20px; left: 20px;" }; return ` position: fixed; ${positions[position]} z-index: 10000; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; `; } attachEventListeners() { if (!this.container) return; const button = this.container.querySelector(".widget-button"); const panel = this.container.querySelector(".widget-panel"); const closeBtn = this.container.querySelector(".close-btn"); const typeButtons = this.container.querySelectorAll(".ticket-type-btn"); const backBtn = this.container.querySelector(".back-btn"); const form = this.container.querySelector("#support-form"); button?.addEventListener("click", () => { if (panel) { const panelElement = panel; panelElement.style.display = panelElement.style.display === "none" ? "block" : "none"; } }); closeBtn?.addEventListener("click", () => { if (panel) panel.style.display = "none"; }); typeButtons.forEach((btn) => { btn.addEventListener("click", () => { const type = btn.getAttribute("data-type"); const typeInput = this.container?.querySelector("#ticket-type"); const typeSelection = this.container?.querySelector(".ticket-type-selection"); const ticketForm = this.container?.querySelector(".ticket-form"); if (typeInput) typeInput.value = type || ""; if (typeSelection) typeSelection.style.display = "none"; if (ticketForm) ticketForm.style.display = "block"; }); }); backBtn?.addEventListener("click", () => { const typeSelection = this.container?.querySelector(".ticket-type-selection"); const ticketForm = this.container?.querySelector(".ticket-form"); if (typeSelection) typeSelection.style.display = "block"; if (ticketForm) ticketForm.style.display = "none"; }); form?.addEventListener("submit", async (e) => { e.preventDefault(); await this.handleFormSubmit(); }); } async handleFormSubmit() { if (!this.container) return; const form = this.container.querySelector("#support-form"); const ticket = { type: this.container.querySelector("#ticket-type").value, title: this.container.querySelector("#ticket-title").value, description: this.container.querySelector("#ticket-description").value, userName: this.container.querySelector("#user-name").value, userEmail: this.container.querySelector("#user-email").value }; try { await this.monitor.createSupportTicket(ticket); alert("Thank you! Your ticket has been submitted successfully."); this.hide(); } catch (error) { alert("Sorry, there was an error submitting your ticket. Please try again."); } } }; var index_default = MeshedMonitor; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { MeshedMonitor, SupportWidget });