UNPKG

freelii-passkey-kit

Version:

A helper library for creating and using smart wallet accounts on the Stellar blockchain.

130 lines (108 loc) 4.26 kB
import type { LoggingConfig, LoggerTransport } from './types'; // Check if we're in a browser environment const isBrowser = typeof window !== 'undefined'; // Browser-compatible logger interface interface BrowserLogger { info: (msg: string, ...args: any[]) => void; error: (msg: string, ...args: any[]) => void; warn: (msg: string, ...args: any[]) => void; debug: (msg: string, ...args: any[]) => void; child: (obj: any) => BrowserLogger; } let logger: any; // Create a browser-compatible console logger function createBrowserLogger(name: string = 'passkey-kit'): BrowserLogger { const prefix = `[${name}]`; return { info: (msg: string, ...args: any[]) => console.info(prefix, msg, ...args), error: (msg: string, ...args: any[]) => console.error(prefix, msg, ...args), warn: (msg: string, ...args: any[]) => console.warn(prefix, msg, ...args), debug: (msg: string, ...args: any[]) => console.debug(prefix, msg, ...args), child: (obj: any) => createBrowserLogger(`${name}:${Object.keys(obj).join(':')}`) }; } function isPinoLogger(obj: any): boolean { return obj && typeof obj === 'object' && typeof obj.info === 'function' && typeof obj.error === 'function' && typeof obj.warn === 'function' && typeof obj.debug === 'function' && typeof obj.child === 'function'; } export class LoggingService { static async init(config: LoggingConfig | any) { if (isPinoLogger(config)) { logger = config; return; } // Always use browser logger first as fallback logger = createBrowserLogger(config.name || 'passkey-kit'); // Only try pino in Node.js environment and if it's available if (!isBrowser) { try { // Check if pino is available without importing it const pinoModule = await import('pino').catch(() => null); if (!pinoModule) return; const prettyModule = await import('pino-pretty').catch(() => null); const { Transform } = await import('stream').catch(() => ({ Transform: null })); if (pinoModule && prettyModule && Transform) { const pinoInstance = pinoModule.default || pinoModule; const prettyInstance = prettyModule.default || prettyModule; const streams: any[] = []; const level = config.level || 'info'; const prettyStream: any = prettyInstance({ colorize: true }); streams.push({ stream: prettyStream, level }); Object.entries(config.transports || {}).forEach(([, stream]) => { streams.push({ stream, level }); }); logger = pinoInstance({ name: config.name || 'passkey-kit', level }, pinoInstance.multistream(streams)); } } catch (error) { // Keep browser logger fallback } } } static get(): any { if (!logger) { logger = createBrowserLogger('passkey-kit'); // Only try pino in Node.js environment if (!isBrowser) { import('pino').then(async (pinoModule) => { try { const pinoInstance = pinoModule.default || pinoModule; const prettyModule = await import('pino-pretty'); const prettyInstance = prettyModule.default || prettyModule; logger = pinoInstance({ name: 'passkey-kit' }, pinoInstance.multistream([ { stream: prettyInstance({ colorize: true }) } ])); } catch (error) { // Keep existing browser logger } }).catch(() => { // Keep existing browser logger }); } } return logger; } } export function createCustomTransport(transform: any): LoggerTransport { if (isBrowser) { // In browser, return a simple writable stream-like object return { write: (chunk: any) => console.log(chunk), retrieveLogs: () => { throw new Error('retrieveLogs not implemented for browser transport'); } } as LoggerTransport; } const transport = transform as LoggerTransport; // Add optional retrieveLogs method if not present if (!transport.retrieveLogs) { transport.retrieveLogs = () => { throw new Error('retrieveLogs not implemented for this transport'); }; } return transport; }