UNPKG

magically-sdk

Version:

Official SDK for Magically - Build mobile apps with AI

249 lines (248 loc) â€ĸ 9.13 kB
"use strict"; /** * Simple, formatted logger for Magically SDK * Provides clean, readable debug output */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Logger = void 0; class Logger { constructor(isDebugEnabled = false, prefix = 'MagicallySDK') { this.requestCounter = 0; this.isDebugEnabled = isDebugEnabled; this.prefix = prefix; } /** * Log debug information (only when debug is enabled) */ debug(step, data) { if (!this.isDebugEnabled) return; const timestamp = new Date().toISOString().split('T')[1].split('.')[0]; console.log(`🔧 [${this.prefix}] ${timestamp} - ${step}`); if (data) { console.log(' 📄 Data:', this.sanitizeData(data)); } } /** * Log success steps */ success(step, data) { if (!this.isDebugEnabled) return; const timestamp = new Date().toISOString().split('T')[1].split('.')[0]; console.log(`✅ [${this.prefix}] ${timestamp} - ${step}`); if (data) { console.log(' 📄 Data:', this.sanitizeData(data)); } } /** * Log errors (always shown, regardless of debug flag) */ error(step, error) { const timestamp = new Date().toISOString().split('T')[1].split('.')[0]; console.error(`❌ [${this.prefix}] ${timestamp} - ${step}`); console.error(' 🚨 Error:', error); } /** * Log warnings */ warn(step, data) { if (!this.isDebugEnabled) return; const timestamp = new Date().toISOString().split('T')[1].split('.')[0]; console.warn(`âš ī¸ [${this.prefix}] ${timestamp} - ${step}`); if (data) { console.warn(' 📄 Data:', this.sanitizeData(data)); } } /** * Log info (always shown) */ info(step, data) { const timestamp = new Date().toISOString().split('T')[1].split('.')[0]; console.log(`â„šī¸ [${this.prefix}] ${timestamp} - ${step}`); if (data) { console.log(' 📄 Data:', this.sanitizeData(data)); } } /** * Sanitize sensitive data for logging */ sanitizeData(data) { if (typeof data !== 'object' || data === null) { return data; } const sanitized = { ...data }; // Remove sensitive fields const sensitiveFields = [ 'password', 'token', 'accessToken', 'refreshToken', 'access_token', 'refresh_token', 'client_secret', 'authorization', 'auth', 'secret' ]; sensitiveFields.forEach(field => { if (sanitized[field]) { sanitized[field] = '[REDACTED]'; } }); // Truncate long URLs but keep important parts if (sanitized.url && sanitized.url.length > 100) { const url = new URL(sanitized.url); sanitized.url = `${url.origin}${url.pathname}...`; } return sanitized; } /** * Create a scoped logger for a specific component */ scope(scopeName) { return new Logger(this.isDebugEnabled, `${this.prefix}:${scopeName}`); } /** * Generate unique request ID */ generateRequestId() { return `req-${++this.requestCounter}-${Date.now()}`; } /** * Sanitize URLs for logging */ sanitizeUrl(url) { try { const urlObj = new URL(url); // Keep the important parts but remove query params that might contain sensitive data return `${urlObj.origin}${urlObj.pathname}`; } catch { return url.substring(0, 100) + '...'; } } /** * Sanitize headers for logging */ sanitizeHeaders(headers) { const sanitized = { ...headers }; const sensitiveHeaders = ['authorization', 'cookie', 'x-api-key', 'set-cookie']; Object.keys(sanitized).forEach(key => { if (sensitiveHeaders.includes(key.toLowerCase())) { sanitized[key] = '[REDACTED]'; } }); return sanitized; } /** * Log network request */ networkRequest(method, url, options) { const requestId = options?.requestId || this.generateRequestId(); const startTime = Date.now(); if (!this.isDebugEnabled) return requestId; const timestamp = new Date().toISOString().split('T')[1].split('.')[0]; const operation = options?.operation ? `:${options.operation}` : ''; // Send BOTH formats for compatibility // 1. Original string format (for backward compatibility) let message = `[Network] ${this.prefix}${operation} ${timestamp} - Request [${requestId}]\n`; message += ` ${method} ${this.sanitizeUrl(url)}`; if (options?.headers) { message += `\n Headers: ${JSON.stringify(this.sanitizeHeaders(options.headers))}`; } if (options?.body) { message += `\n Body: ${JSON.stringify(this.sanitizeData(options.body))}`; } console.log(message); // 2. Also send structured data with __raw prefix const structuredData = { __raw: true, type: 'network', data: { requestId, method: method, url, startTime, operation: options?.operation, requestHeaders: options?.headers ? this.sanitizeHeaders(options.headers) : undefined, requestBody: options?.body ? this.sanitizeData(options.body) : undefined, } }; console.log(JSON.stringify(structuredData)); return requestId; } /** * Log network response */ networkResponse(requestId, response) { if (!this.isDebugEnabled) return; const timestamp = new Date().toISOString().split('T')[1].split('.')[0]; const durationText = response.duration ? ` (${response.duration}ms)` : ''; const operation = response.operation ? `:${response.operation}` : ''; const endTime = Date.now(); // 1. Original string format let message = `[Network] ${this.prefix}${operation} ${timestamp} - Response [${requestId}]${durationText}\n`; message += ` Status: ${response.status} ${response.statusText || ''}`; if (response.headers) { message += `\n Headers: ${JSON.stringify(this.sanitizeHeaders(response.headers))}`; } if (response.data !== undefined) { message += `\n Data: ${JSON.stringify(this.sanitizeData(response.data))}`; } // Use appropriate console method based on status if (response.status >= 400) { console.error(message); } else { console.log(message); } // 2. Also send structured data with __raw prefix const structuredData = { __raw: true, type: 'network_response', data: { requestId, status: response.status, statusText: response.statusText, endTime, duration: response.duration, operation: response.operation, responseHeaders: response.headers ? this.sanitizeHeaders(response.headers) : undefined, responseBody: response.data !== undefined ? this.sanitizeData(response.data) : undefined, responseSize: response.data ? JSON.stringify(response.data).length : 0, } }; // Use appropriate console method based on status if (response.status >= 400) { console.error(JSON.stringify(structuredData)); } else { console.log(JSON.stringify(structuredData)); } } /** * Log network error */ networkError(requestId, error, options) { const timestamp = new Date().toISOString().split('T')[1].split('.')[0]; const durationText = options?.duration ? ` (${options.duration}ms)` : ''; const operation = options?.operation ? `:${options.operation}` : ''; const endTime = Date.now(); const errorMessage = error?.message || error?.toString() || 'Unknown error'; // 1. Original string format const message = `[Network] ${this.prefix}${operation} ${timestamp} - Error [${requestId}]${durationText}\n Error: ${errorMessage}`; console.error(message); // 2. Also send structured data with __raw prefix const structuredData = { __raw: true, type: 'network_error', data: { requestId, error: error?.responseData || error, // Pass the full error/response data errorStack: error?.stack, endTime, duration: options?.duration, operation: options?.operation, } }; console.error(JSON.stringify(structuredData)); } } exports.Logger = Logger;