emitochondria 1.2.2 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,7 +31,7 @@ var require_package = __commonJS({
31
31
  "package.json"(exports2, module2) {
32
32
  module2.exports = {
33
33
  name: "emitochondria",
34
- version: "1.2.2",
34
+ version: "1.2.3",
35
35
  type: "module",
36
36
  description: "The powerhouse of your events \u2014 A tiny, fully-typed event emitter for TypeScript with built-in error handling and memory leak detection",
37
37
  author: "Pablo D\xEDaz A.K.A exudev",
@@ -58,9 +58,9 @@ var require_package = __commonJS({
58
58
  type: "git",
59
59
  url: "https://github.com/Exudev/emitochondria.git"
60
60
  },
61
- main: "./dist/index.js",
61
+ main: "./dist/index.cjs",
62
62
  module: "./dist/index.mjs",
63
- types: "./dist/index.d.ts",
63
+ types: "./dist/index.d.cts",
64
64
  exports: {
65
65
  ".": {
66
66
  import: {
@@ -68,8 +68,8 @@ var require_package = __commonJS({
68
68
  default: "./dist/index.mjs"
69
69
  },
70
70
  require: {
71
- types: "./dist/index.d.ts",
72
- default: "./dist/index.js"
71
+ types: "./dist/index.d.cts",
72
+ default: "./dist/index.cjs"
73
73
  }
74
74
  },
75
75
  "./schema.json": "./schema.json"
package/dist/index.cjs ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";var x=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var W=Object.prototype.hasOwnProperty;var $=(o,t)=>{for(var n in t)x(o,n,{get:t[n],enumerable:!0})},K=(o,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of R(t))!W.call(o,i)&&i!==n&&x(o,i,{get:()=>t[i],enumerable:!(r=P(t,i))||r.enumerable});return o};var A=o=>K(x({},"__esModule",{value:!0}),o);var Q={};$(Q,{clearConfigCache:()=>j,createEmitochondria:()=>F,default:()=>F});module.exports=A(Q);var S={},C="emitochondria.config.json",B=typeof globalThis.process<"u"&&globalThis.process?.versions?.node!=null;function D(){if(!B)return null;if(typeof globalThis.require=="function")return globalThis.require;try{let o=Function('return typeof require !== "undefined" ? require : null')();if(o)return o}catch{}try{let{createRequire:o}=Function('return require("node:module")')(),t=typeof S?.url=="string"&&S.url?S.url:"file://"+globalThis.process?.cwd?.()+"/";return o(t)}catch{return null}}var y=D(),f=null,u=null;function O(){if(u!==null)return u;let o=globalThis.process;if(typeof o>"u"||!o?.versions?.node)return u="","";try{if(!y){let l=o.cwd();return u=l,l}let t=y("path"),n=y("fs"),r=o.cwd();for(;r!==t.dirname(r);){if(n.existsSync(t.join(r,"package.json")))return u=r,r;r=t.dirname(r)}let i=o.cwd();return u=i,i}catch{let t=o.cwd();return u=t,t}}function z(){return O()}function I(){if(f!==null)return f;let o=globalThis.process;if(typeof o>"u"||!o?.versions?.node)return f={},f;try{if(!y)return f={},f;let t=y("fs"),n=y("path"),r=O(),i=n.join(r,C);if(!t.existsSync(i)){let E=n.join(o.cwd(),C);if(t.existsSync(E)){let h=t.readFileSync(E,"utf-8");return f=JSON.parse(h),o.env?.NODE_ENV!=="production"&&console.log(`[Emitochondria] Config loaded from: ${E}`),f}return f={},f}let l=t.readFileSync(i,"utf-8");return f=JSON.parse(l),o.env?.NODE_ENV!=="production"&&console.log(`[Emitochondria] Config loaded from: ${i}`),f}catch(t){return t?.code!=="ENOENT"&&console.warn(`[Emitochondria] Failed to load config: ${t?.message}`),f={},f}}function M(o,t){let n={...o};for(let r in t)t[r]!==void 0&&(typeof t[r]=="object"&&t[r]!==null&&!Array.isArray(t[r])&&typeof n[r]=="object"&&n[r]!==null?n[r]=M(n[r],t[r]):n[r]=t[r]);return n}function q(o={}){let t=I();return M(t,o)}function j(){f=null,u=null}var L={},k=typeof globalThis.process<"u"&&globalThis.process?.versions?.node!=null,J=typeof globalThis.window<"u";function U(){if(!k)return null;if(typeof globalThis.require=="function")return globalThis.require;try{let o=Function('return typeof require !== "undefined" ? require : null')();if(o)return o}catch{}try{let{createRequire:o}=Function('return require("node:module")')(),t=typeof L?.url=="string"&&L.url?L.url:"file://"+globalThis.process?.cwd?.()+"/";return o(t)}catch{return null}}var b=U();function G(o,t){let n=new Date;switch(o){case"unix":return String(n.getTime());case"human":return n.toLocaleString("en-US",{timeZone:t==="utc"?"UTC":void 0,month:"short",day:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit",hour12:!0});default:return t==="utc"?n.toISOString():new Date(n.getTime()-n.getTimezoneOffset()*6e4).toISOString().slice(0,-1)}}function V(o){let t=o.match(/^(\d+(?:\.\d+)?)\s*(KB|MB|GB)$/i);if(!t)return 10*1024*1024;let n=parseFloat(t[1]),r=t[2].toUpperCase(),i={KB:1024,MB:1024*1024,GB:1024*1024*1024};return n*(i[r]??10*1024*1024)}var T=class{options;maxSizeBytes;browserWarned=!1;fs=null;path=null;constructor(t={}){this.options={timestamps:t.timestamps??!1,timestampFormat:t.timestampFormat??"iso",timezone:t.timezone??"utc",persist:t.persist??!1,path:t.path??"./logs/emitochondria.log",format:t.format??"text",maxSize:t.maxSize??"10MB",logEvents:t.logEvents??!1,logErrors:t.logErrors??!0,logWarnings:t.logWarnings??!0},this.maxSizeBytes=V(this.options.maxSize),this.options.persist&&this.initFileLogging()}initFileLogging(){if(J){this.browserWarned||(console.warn("[Emitochondria] File logging is not available in browser environments. Logs will only be written to console."),this.browserWarned=!0);return}if(k)try{if(b){this.fs=b("fs"),this.path=b("path");let t=z(),n=this.path.isAbsolute(this.options.path)?this.options.path:this.path.join(t,this.options.path);this.options.path=n;let r=this.path.dirname(n);this.fs.existsSync(r)||this.fs.mkdirSync(r,{recursive:!0}),globalThis.process?.env?.NODE_ENV!=="production"&&console.log(`[Emitochondria] Logs will be written to: ${n}`)}}catch(t){console.error("[Emitochondria] Failed to initialize file logging:",t)}}getTimestamp(){if(this.options.timestamps)return G(this.options.timestampFormat,this.options.timezone)}formatEntry(t){let n=this.getTimestamp();if(this.options.format==="json"){let i={level:t.level,type:t.type,message:t.message};return n&&(i.timestamp=n),t.event&&(i.event=t.event),t.payload!==void 0&&(i.payload=t.payload),t.error&&(i.error=String(t.error)),JSON.stringify(i)}let r=[];return n&&r.push(`[${n}]`),r.push(`[${t.level.toUpperCase()}]`),t.event&&r.push(`[${t.event}]`),r.push(t.message),t.payload!==void 0&&r.push(`| Payload: ${JSON.stringify(t.payload)}`),t.error&&r.push(`| Error: ${t.error}`),r.join(" ")}writeToFile(t){if(!(!this.fs||!this.path||!k))try{let n=t+`
2
+ `;this.fs.existsSync(this.options.path)&&this.fs.statSync(this.options.path).size>=this.maxSizeBytes&&this.rotateLog(),this.fs.appendFileSync(this.options.path,n,"utf8")}catch(n){console.error("[Emitochondria] Failed to write to log file:",n)}}rotateLog(){if(!(!this.fs||!this.path))try{let t=1;for(;this.fs.existsSync(`${this.options.path}.${t}`);)t++;this.fs.renameSync(this.options.path,`${this.options.path}.${t}`)}catch(t){console.error("[Emitochondria] Failed to rotate log file:",t)}}logEvent(t,n){if(!this.options.logEvents)return;let r={level:"info",type:"event",event:t,message:"Event emitted",payload:n},i=this.formatEntry(r);console.log(i),this.options.persist&&this.writeToFile(i)}logError(t,n,r){if(!this.options.logErrors)return;let i={level:"error",type:"error",event:t,message:"Handler threw an error",error:n},l=this.formatEntry(i);console.error(l),this.options.persist&&this.writeToFile(l)}logWarning(t,n,r){if(!this.options.logWarnings)return;let i={level:"warn",type:"warning",event:t,message:n,payload:r},l=this.formatEntry(i);console.warn(l),this.options.persist&&this.writeToFile(l)}};var Z=(o,t,n)=>{};function F(o={}){let t=q(o),n=new T(t.logging),r=new Map,i=new Set,l=t.maxListeners??10,E=o.onMaxListenersExceeded??Z,h=t.onError??"default",p=new Set,m=e=>r.get(e)??r.set(e,new Set).get(e),w=(e,a,s)=>{if(n.logError(a,e,s),h==="throw")throw e;typeof h=="function"&&h(e,a,s)},H=(e,a,s)=>{try{let c=e(s);if(c instanceof Promise)return c.catch(d=>w(d,a,e))}catch(c){w(c,a,e)}},N=(e,a)=>{if(l>0&&a>l&&!p.has(e)){p.add(e);let s=`Possible memory leak: ${a} listeners (max: ${l})`;n.logWarning(e,s,{count:a,max:l}),E(e,a,l)}},v={on(e,a){let s=m(e);return s.add(a),N(e,s.size),()=>v.off(e,a)},off(e,a){let s=m(e);if(s.delete(a)){s.size<=l&&p.delete(e);return}for(let c of s)if(c.__original===a){s.delete(c),s.size<=l&&p.delete(e);break}},once(e,a){let s=(c=>(v.off(e,s),a(c)));return s.__original=a,v.on(e,s)},emit(e,...a){let s=a[0];n.logEvent(e,s),m(e).forEach(c=>H(c,e,s)),i.forEach(c=>{try{c(e,s)}catch(d){w(d,e,c)}})},async emitAsync(e,...a){let s=a[0],c=[];n.logEvent(e,s),m(e).forEach(d=>{let g=H(d,e,s);g instanceof Promise&&c.push(g)}),i.forEach(d=>{try{let g=d(e,s);g instanceof Promise&&c.push(g.catch(_=>w(_,e,d)))}catch(g){w(g,e,d)}}),await Promise.all(c)},onAny(e){return i.add(e),()=>v.offAny(e)},offAny(e){i.delete(e)},clear(e){e?(r.delete(e),p.delete(e)):(r.clear(),i.clear(),p.clear())},listenerCount(e){return m(e).size},setErrorHandler(e){h=e},setMaxListeners(e){l=e,e===0&&p.clear()},getMaxListeners(){return l},eventNames(){return Array.from(r.keys()).filter(e=>r.get(e).size>0)},listeners(e){let a=m(e);return Array.from(a).map(s=>s.__original||s)},wildcardListeners(){return Array.from(i)},hasListener(e,a){let s=m(e);if(s.has(a))return!0;for(let c of s)if(c.__original===a)return!0;return!1}};return v}0&&(module.exports={clearConfigCache,createEmitochondria});
3
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/logger.ts","../src/emitter.ts"],"sourcesContent":["// Core\nexport { createEmitochondria } from './emitter.js';\n\n// Types\nexport type {\n EventMap,\n EventKey,\n EventHandler,\n WildcardHandler,\n ErrorHandler,\n MaxListenersHandler,\n EmitochondriaConfig,\n EmitochondriaOptions,\n Emitochondria,\n LoggingOptions,\n TimestampFormat,\n Timezone,\n LogFormat,\n} from './types.js';\n\n// Utilities (for testing/advanced use)\nexport { clearConfigCache } from './config.js';\n\n// Default export\nexport { createEmitochondria as default } from './emitter.js';\n","import { EmitochondriaConfig, EmitochondriaOptions, EventMap } from './types.js';\n\n// ============================================================\n// CONFIG FILE LOADING\n// ============================================================\n\nconst CONFIG_FILENAME = 'emitochondria.config.json';\n\n// Environment detection\nconst isNode = typeof (globalThis as any).process !== 'undefined'\n && (globalThis as any).process?.versions?.node != null;\n\n// Get require function - works in both ESM and CJS\nfunction getRequireFunction(): ((id: string) => any) | null {\n if (!isNode) return null;\n\n // CJS: globalThis.require is available (bundlers like tsup inject this)\n if (typeof (globalThis as any).require === 'function') {\n return (globalThis as any).require;\n }\n\n // Try Function constructor to get require in CJS context\n try {\n const req = Function('return typeof require !== \"undefined\" ? require : null')();\n if (req) return req;\n } catch {\n // Ignore\n }\n\n // ESM: use createRequire\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { createRequire } = Function('return require(\"node:module\")')();\n // import.meta.url might be empty in CJS, use a fallback\n const url = typeof import.meta?.url === 'string' && import.meta.url\n ? import.meta.url\n : 'file://' + (globalThis as any).process?.cwd?.() + '/';\n return createRequire(url);\n } catch {\n return null;\n }\n}\n\nconst nodeRequire = getRequireFunction();\n\nlet cachedConfig: EmitochondriaConfig | null = null;\nlet cachedProjectRoot: string | null = null;\n\n/**\n * Find project root by walking up directories looking for package.json.\n */\nfunction findProjectRoot(): string {\n if (cachedProjectRoot !== null) return cachedProjectRoot;\n\n const proc = (globalThis as any).process;\n if (typeof proc === 'undefined' || !proc?.versions?.node) {\n cachedProjectRoot = '';\n return '';\n }\n\n try {\n if (!nodeRequire) {\n const cwd: string = proc.cwd();\n cachedProjectRoot = cwd;\n return cwd;\n }\n\n const path = nodeRequire('path');\n const fs = nodeRequire('fs');\n\n let dir: string = proc.cwd();\n\n // Walk up looking for package.json\n while (dir !== path.dirname(dir)) {\n if (fs.existsSync(path.join(dir, 'package.json'))) {\n cachedProjectRoot = dir;\n return dir;\n }\n dir = path.dirname(dir);\n }\n\n // Fallback to cwd if no package.json found\n const cwd: string = proc.cwd();\n cachedProjectRoot = cwd;\n return cwd;\n } catch {\n const cwd: string = proc.cwd();\n cachedProjectRoot = cwd;\n return cwd;\n }\n}\n\n/**\n * Get the cached project root (for use by logger).\n */\nexport function getProjectRoot(): string {\n return findProjectRoot();\n}\n\n/**\n * Synchronous version for initial load.\n * Falls back to empty config if loading fails.\n */\nfunction loadConfigFileSync(): EmitochondriaConfig {\n if (cachedConfig !== null) return cachedConfig;\n\n const proc = (globalThis as any).process;\n if (typeof proc === 'undefined' || !proc?.versions?.node) {\n cachedConfig = {};\n return cachedConfig;\n }\n\n try {\n if (!nodeRequire) {\n cachedConfig = {};\n return cachedConfig;\n }\n\n const fs = nodeRequire('fs');\n const path = nodeRequire('path');\n\n // Look for config in project root first\n const projectRoot = findProjectRoot();\n const configPath = path.join(projectRoot, CONFIG_FILENAME);\n\n if (!fs.existsSync(configPath)) {\n // Also try cwd as fallback\n const cwdPath = path.join(proc.cwd(), CONFIG_FILENAME);\n if (fs.existsSync(cwdPath)) {\n const content = fs.readFileSync(cwdPath, 'utf-8');\n cachedConfig = JSON.parse(content) as EmitochondriaConfig;\n\n if (proc.env?.NODE_ENV !== 'production') {\n console.log(`[Emitochondria] Config loaded from: ${cwdPath}`);\n }\n\n return cachedConfig;\n }\n\n cachedConfig = {};\n return cachedConfig;\n }\n\n const content = fs.readFileSync(configPath, 'utf-8');\n cachedConfig = JSON.parse(content) as EmitochondriaConfig;\n\n if (proc.env?.NODE_ENV !== 'production') {\n console.log(`[Emitochondria] Config loaded from: ${configPath}`);\n }\n\n return cachedConfig;\n } catch (err: any) {\n if (err?.code !== 'ENOENT') {\n console.warn(`[Emitochondria] Failed to load config: ${err?.message}`);\n }\n cachedConfig = {};\n return cachedConfig;\n }\n}\n\n// ============================================================\n// CONFIG MERGING\n// ============================================================\n\n/**\n * Deep merge two objects, with second taking precedence.\n */\nfunction deepMerge<T extends Record<string, any>>(base: T, override: Partial<T>): T {\n const result = { ...base };\n\n for (const key in override) {\n if (override[key] !== undefined) {\n if (\n typeof override[key] === 'object' &&\n override[key] !== null &&\n !Array.isArray(override[key]) &&\n typeof result[key] === 'object' &&\n result[key] !== null\n ) {\n result[key] = deepMerge(result[key], override[key]);\n } else {\n result[key] = override[key] as T[typeof key];\n }\n }\n }\n\n return result;\n}\n\n/**\n * Merge file config with options.\n * Options take precedence over file config.\n */\nexport function mergeConfig<T extends EventMap>(\n options: EmitochondriaOptions<T> = {}\n): EmitochondriaOptions<T> {\n const fileConfig = loadConfigFileSync();\n // Type assertion is safe here because we control both inputs\n const merged = deepMerge(fileConfig as any, options as any);\n return merged as EmitochondriaOptions<T>;\n}\n\n/**\n * Clear cached config (useful for testing).\n */\nexport function clearConfigCache(): void {\n cachedConfig = null;\n cachedProjectRoot = null;\n}\n","import { LoggingOptions, TimestampFormat, Timezone } from './types.js';\nimport { getProjectRoot } from './config.js';\n\n// ============================================================\n// ENVIRONMENT DETECTION\n// ============================================================\n\nconst isNode = typeof (globalThis as any).process !== 'undefined'\n && (globalThis as any).process?.versions?.node != null;\n\nconst isBrowser = typeof (globalThis as any).window !== 'undefined';\n\n// Get require function - works in both ESM and CJS\nfunction getRequireFunction(): ((id: string) => any) | null {\n if (!isNode) return null;\n\n // CJS: globalThis.require is available (bundlers like tsup inject this)\n if (typeof (globalThis as any).require === 'function') {\n return (globalThis as any).require;\n }\n\n // Try Function constructor to get require in CJS context\n try {\n const req = Function('return typeof require !== \"undefined\" ? require : null')();\n if (req) return req;\n } catch {\n // Ignore\n }\n\n // ESM: use createRequire\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { createRequire } = Function('return require(\"node:module\")')();\n // import.meta.url might be empty in CJS, use a fallback\n const url = typeof import.meta?.url === 'string' && import.meta.url\n ? import.meta.url\n : 'file://' + (globalThis as any).process?.cwd?.() + '/';\n return createRequire(url);\n } catch {\n return null;\n }\n}\n\nconst nodeRequire = getRequireFunction();\n\n// ============================================================\n// TIMESTAMP FORMATTING\n// ============================================================\n\nfunction formatTimestamp(format: TimestampFormat, timezone: Timezone): string {\n const date = new Date();\n\n switch (format) {\n case 'unix':\n return String(date.getTime());\n\n case 'human':\n return date.toLocaleString('en-US', {\n timeZone: timezone === 'utc' ? 'UTC' : undefined,\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n hour12: true,\n });\n\n case 'iso':\n default:\n return timezone === 'utc'\n ? date.toISOString()\n : new Date(date.getTime() - date.getTimezoneOffset() * 60000)\n .toISOString()\n .slice(0, -1); // Remove 'Z' for local\n }\n}\n\n// ============================================================\n// SIZE PARSING\n// ============================================================\n\nfunction parseSize(size: string): number {\n const match = size.match(/^(\\d+(?:\\.\\d+)?)\\s*(KB|MB|GB)$/i);\n if (!match) return 10 * 1024 * 1024; // Default 10MB\n\n const value = parseFloat(match[1]!);\n const unit = match[2]!.toUpperCase();\n\n const multipliers: Record<string, number> = {\n 'KB': 1024,\n 'MB': 1024 * 1024,\n 'GB': 1024 * 1024 * 1024,\n };\n\n return value * (multipliers[unit] ?? 10 * 1024 * 1024);\n}\n\n// ============================================================\n// LOG ENTRY TYPES\n// ============================================================\n\nexport type LogLevel = 'info' | 'warn' | 'error';\n\nexport interface LogEntry {\n level: LogLevel;\n type: 'event' | 'error' | 'warning';\n event?: string;\n message: string;\n payload?: unknown;\n error?: unknown;\n}\n\n// ============================================================\n// LOGGER CLASS\n// ============================================================\n\nexport class Logger {\n private options: Required<LoggingOptions>;\n private maxSizeBytes: number;\n private browserWarned = false;\n private fs: any = null;\n private path: any = null;\n\n constructor(options: LoggingOptions = {}) {\n this.options = {\n timestamps: options.timestamps ?? false,\n timestampFormat: options.timestampFormat ?? 'iso',\n timezone: options.timezone ?? 'utc',\n persist: options.persist ?? false,\n path: options.path ?? './logs/emitochondria.log',\n format: options.format ?? 'text',\n maxSize: options.maxSize ?? '10MB',\n logEvents: options.logEvents ?? false,\n logErrors: options.logErrors ?? true,\n logWarnings: options.logWarnings ?? true,\n };\n\n this.maxSizeBytes = parseSize(this.options.maxSize);\n\n if (this.options.persist) {\n this.initFileLogging();\n }\n }\n\n private initFileLogging(): void {\n if (isBrowser) {\n if (!this.browserWarned) {\n console.warn(\n '[Emitochondria] File logging is not available in browser environments. ' +\n 'Logs will only be written to console.'\n );\n this.browserWarned = true;\n }\n return;\n }\n\n if (!isNode) return;\n\n try {\n // Require fs and path synchronously using ESM-compatible require\n if (nodeRequire) {\n this.fs = nodeRequire('fs');\n this.path = nodeRequire('path');\n\n // Resolve path relative to project root (where package.json is)\n const projectRoot = getProjectRoot();\n const resolvedPath = this.path.isAbsolute(this.options.path)\n ? this.options.path\n : this.path.join(projectRoot, this.options.path);\n\n // Update options with resolved path\n this.options.path = resolvedPath;\n\n // Create directory if needed\n const dir = this.path.dirname(resolvedPath);\n if (!this.fs.existsSync(dir)) {\n this.fs.mkdirSync(dir, { recursive: true });\n }\n\n // Log where logs are being written (helpful for debugging)\n const proc = (globalThis as any).process;\n if (proc?.env?.NODE_ENV !== 'production') {\n console.log(`[Emitochondria] Logs will be written to: ${resolvedPath}`);\n }\n }\n } catch (err) {\n console.error('[Emitochondria] Failed to initialize file logging:', err);\n }\n }\n\n private getTimestamp(): string | undefined {\n if (!this.options.timestamps) return undefined;\n return formatTimestamp(this.options.timestampFormat, this.options.timezone);\n }\n\n private formatEntry(entry: LogEntry): string {\n const timestamp = this.getTimestamp();\n\n if (this.options.format === 'json') {\n const obj: any = {\n level: entry.level,\n type: entry.type,\n message: entry.message,\n };\n if (timestamp) obj.timestamp = timestamp;\n if (entry.event) obj.event = entry.event;\n if (entry.payload !== undefined) obj.payload = entry.payload;\n if (entry.error) obj.error = String(entry.error);\n return JSON.stringify(obj);\n }\n\n // Text format\n const parts: string[] = [];\n if (timestamp) parts.push(`[${timestamp}]`);\n parts.push(`[${entry.level.toUpperCase()}]`);\n if (entry.event) parts.push(`[${entry.event}]`);\n parts.push(entry.message);\n if (entry.payload !== undefined) {\n parts.push(`| Payload: ${JSON.stringify(entry.payload)}`);\n }\n if (entry.error) {\n parts.push(`| Error: ${entry.error}`);\n }\n\n return parts.join(' ');\n }\n\n private writeToFile(content: string): void {\n if (!this.fs || !this.path || !isNode) return;\n\n try {\n const line = content + '\\n';\n\n // Check if rotation needed\n if (this.fs.existsSync(this.options.path)) {\n const stats = this.fs.statSync(this.options.path);\n if (stats.size >= this.maxSizeBytes) {\n this.rotateLog();\n }\n }\n\n // Sync write — simple, ordered, reliable\n this.fs.appendFileSync(this.options.path, line, 'utf8');\n } catch (err) {\n console.error('[Emitochondria] Failed to write to log file:', err);\n }\n }\n\n private rotateLog(): void {\n if (!this.fs || !this.path) return;\n\n try {\n // Find next rotation number\n let rotationNum = 1;\n while (this.fs.existsSync(`${this.options.path}.${rotationNum}`)) {\n rotationNum++;\n }\n\n // Rename current file\n this.fs.renameSync(this.options.path, `${this.options.path}.${rotationNum}`);\n } catch (err) {\n console.error('[Emitochondria] Failed to rotate log file:', err);\n }\n }\n\n // ============================================================\n // PUBLIC LOGGING METHODS\n // ============================================================\n\n logEvent(event: string, payload: unknown): void {\n if (!this.options.logEvents) return;\n\n const entry: LogEntry = {\n level: 'info',\n type: 'event',\n event,\n message: 'Event emitted',\n payload,\n };\n\n const formatted = this.formatEntry(entry);\n console.log(formatted);\n\n if (this.options.persist) {\n this.writeToFile(formatted);\n }\n }\n\n logError(event: string, error: unknown, _handler?: unknown): void {\n if (!this.options.logErrors) return;\n\n const entry: LogEntry = {\n level: 'error',\n type: 'error',\n event,\n message: 'Handler threw an error',\n error,\n };\n\n const formatted = this.formatEntry(entry);\n console.error(formatted);\n\n if (this.options.persist) {\n this.writeToFile(formatted);\n }\n }\n\n logWarning(event: string, message: string, details?: Record<string, unknown>): void {\n if (!this.options.logWarnings) return;\n\n const entry: LogEntry = {\n level: 'warn',\n type: 'warning',\n event,\n message,\n payload: details,\n };\n\n const formatted = this.formatEntry(entry);\n console.warn(formatted);\n\n if (this.options.persist) {\n this.writeToFile(formatted);\n }\n }\n}\n","import {\n EventMap,\n EventKey,\n EventHandler,\n WildcardHandler,\n ErrorHandler,\n EmitochondriaOptions,\n Emitochondria,\n} from './types.js';\nimport { Logger } from './logger.js';\nimport { mergeConfig } from './config.js';\n\n// ============================================================\n// DEFAULT HANDLERS\n// ============================================================\n\nconst defaultMaxListenersHandler = <T extends EventMap>(\n _event: EventKey<T>,\n _count: number,\n _max: number\n): void => {\n // Handled by logger\n};\n\n// ============================================================\n// FACTORY FUNCTION\n// ============================================================\n\nexport function createEmitochondria<T extends EventMap>(\n options: EmitochondriaOptions<T> = {}\n): Emitochondria<T> {\n // Merge file config with options\n const config = mergeConfig(options);\n\n // Initialize logger\n const logger = new Logger(config.logging);\n\n // Handler storage\n const handlers: Map<string, Set<EventHandler<unknown>>> = new Map();\n const wildcards: Set<WildcardHandler<T>> = new Set();\n\n // Configuration state\n let maxListeners = config.maxListeners ?? 10;\n let onMaxListenersExceeded = options.onMaxListenersExceeded ?? defaultMaxListenersHandler;\n let errorHandler: ErrorHandler<T> | 'throw' | 'default' = config.onError ?? 'default';\n\n // Memory leak tracking\n const warned = new Set<string>();\n\n // ============================================================\n // HELPER FUNCTIONS\n // ============================================================\n\n // Track original handlers for once() wrappers\n type WrappedHandler<T> = EventHandler<T> & { __original?: EventHandler<T> };\n\n const get = (e: string) => handlers.get(e) ?? handlers.set(e, new Set()).get(e)!;\n\n const handleError = <K extends EventKey<T>>(\n error: unknown,\n event: K,\n handler: EventHandler<unknown>\n ): void => {\n logger.logError(event, error, handler);\n\n if (errorHandler === 'throw') {\n throw error;\n } else if (typeof errorHandler === 'function') {\n errorHandler(error, event, handler);\n }\n // 'default' = just log (already done above)\n };\n\n const safeCall = <K extends EventKey<T>>(\n handler: EventHandler<unknown>,\n event: K,\n payload: unknown\n ): void | Promise<void> => {\n try {\n const result = handler(payload);\n if (result instanceof Promise) {\n return result.catch((err) => handleError(err, event, handler));\n }\n } catch (err) {\n handleError(err, event, handler);\n }\n };\n\n const checkMaxListeners = <K extends EventKey<T>>(event: K, count: number): void => {\n if (maxListeners > 0 && count > maxListeners && !warned.has(event)) {\n warned.add(event);\n\n const message = `Possible memory leak: ${count} listeners (max: ${maxListeners})`;\n logger.logWarning(event, message, { count, max: maxListeners });\n\n onMaxListenersExceeded(event, count, maxListeners);\n }\n };\n\n // ============================================================\n // EMITTER IMPLEMENTATION\n // ============================================================\n\n const emitter: Emitochondria<T> = {\n on(event, handler) {\n const set = get(event);\n set.add(handler as EventHandler<unknown>);\n checkMaxListeners(event, set.size);\n return () => emitter.off(event, handler);\n },\n\n off(event, handler) {\n const set = get(event);\n\n // Try direct removal first\n if (set.delete(handler as EventHandler<unknown>)) {\n if (set.size <= maxListeners) {\n warned.delete(event);\n }\n return;\n }\n\n // Search for wrapped handler (for once handlers)\n for (const wrapped of set) {\n const w = wrapped as WrappedHandler<unknown>;\n if (w.__original === handler) {\n set.delete(wrapped);\n if (set.size <= maxListeners) {\n warned.delete(event);\n }\n break;\n }\n }\n },\n\n once(event, handler) {\n const wrapper = ((payload: T[typeof event]) => {\n emitter.off(event, wrapper as EventHandler<T[typeof event]>);\n return handler(payload);\n }) as WrappedHandler<T[typeof event]>;\n\n // Store original reference for manual removal\n wrapper.__original = handler;\n\n return emitter.on(event, wrapper);\n },\n\n emit(event, ...payload) {\n const data = payload[0];\n\n logger.logEvent(event, data);\n\n get(event).forEach((h) => safeCall(h, event, data));\n wildcards.forEach((h) => {\n try {\n h(event, data as T[typeof event]);\n } catch (err) {\n handleError(err, event, h as unknown as EventHandler<unknown>);\n }\n });\n },\n\n async emitAsync(event, ...payload) {\n const data = payload[0];\n const promises: Promise<void>[] = [];\n\n logger.logEvent(event, data);\n\n get(event).forEach((h) => {\n const result = safeCall(h, event, data);\n if (result instanceof Promise) promises.push(result);\n });\n\n wildcards.forEach((h) => {\n try {\n const result = h(event, data as T[typeof event]);\n if (result instanceof Promise) {\n promises.push(result.catch((err) =>\n handleError(err, event, h as unknown as EventHandler<unknown>)\n ));\n }\n } catch (err) {\n handleError(err, event, h as unknown as EventHandler<unknown>);\n }\n });\n\n await Promise.all(promises);\n },\n\n onAny(handler) {\n wildcards.add(handler);\n return () => emitter.offAny(handler);\n },\n\n offAny(handler) {\n wildcards.delete(handler);\n },\n\n clear(event?) {\n if (event) {\n handlers.delete(event);\n warned.delete(event);\n } else {\n handlers.clear();\n wildcards.clear();\n warned.clear();\n }\n },\n\n listenerCount(event) {\n return get(event).size;\n },\n\n setErrorHandler(handler) {\n errorHandler = handler;\n },\n\n setMaxListeners(n) {\n maxListeners = n;\n if (n === 0) warned.clear();\n },\n\n getMaxListeners() {\n return maxListeners;\n },\n\n eventNames() {\n return Array.from(handlers.keys()).filter(\n (k) => handlers.get(k)!.size > 0\n ) as EventKey<T>[];\n },\n\n listeners(event) {\n const set = get(event);\n // Return unwrapped handlers for better debugging\n return Array.from(set).map(handler => {\n const wrapped = handler as WrappedHandler<unknown>;\n return (wrapped.__original || handler) as EventHandler<T[typeof event]>;\n });\n },\n\n wildcardListeners() {\n return Array.from(wildcards);\n },\n\n hasListener(event, handler) {\n const set = get(event);\n\n // Check direct match\n if (set.has(handler as EventHandler<unknown>)) {\n return true;\n }\n\n // Check wrapped handlers (once)\n for (const wrapped of set) {\n const w = wrapped as WrappedHandler<unknown>;\n if (w.__original === handler) {\n return true;\n }\n }\n\n return false;\n },\n };\n\n return emitter;\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,sBAAAE,EAAA,wBAAAC,EAAA,YAAAA,IAAA,eAAAC,EAAAJ,GCAA,IAAAK,EAAA,GAMMC,EAAkB,4BAGlBC,EAAS,OAAQ,WAAmB,QAAY,KAChD,WAAmB,SAAS,UAAU,MAAQ,KAGpD,SAASC,GAAmD,CAC1D,GAAI,CAACD,EAAQ,OAAO,KAGpB,GAAI,OAAQ,WAAmB,SAAY,WACzC,OAAQ,WAAmB,QAI7B,GAAI,CACF,IAAME,EAAM,SAAS,wDAAwD,EAAE,EAC/E,GAAIA,EAAK,OAAOA,CAClB,MAAQ,CAER,CAGA,GAAI,CAEF,GAAM,CAAE,cAAAC,CAAc,EAAI,SAAS,+BAA+B,EAAE,EAE9DC,EAAM,OAAON,GAAa,KAAQ,UAAYA,EAAY,IAC5DA,EAAY,IACZ,UAAa,WAAmB,SAAS,MAAM,EAAI,IACvD,OAAOK,EAAcC,CAAG,CAC1B,MAAQ,CACN,OAAO,IACT,CACF,CAEA,IAAMC,EAAcJ,EAAmB,EAEnCK,EAA2C,KAC3CC,EAAmC,KAKvC,SAASC,GAA0B,CACjC,GAAID,IAAsB,KAAM,OAAOA,EAEvC,IAAME,EAAQ,WAAmB,QACjC,GAAI,OAAOA,EAAS,KAAe,CAACA,GAAM,UAAU,KAClD,OAAAF,EAAoB,GACb,GAGT,GAAI,CACF,GAAI,CAACF,EAAa,CAChB,IAAMK,EAAcD,EAAK,IAAI,EAC7B,OAAAF,EAAoBG,EACbA,CACT,CAEA,IAAMC,EAAON,EAAY,MAAM,EACzBO,EAAKP,EAAY,IAAI,EAEvBQ,EAAcJ,EAAK,IAAI,EAG3B,KAAOI,IAAQF,EAAK,QAAQE,CAAG,GAAG,CAChC,GAAID,EAAG,WAAWD,EAAK,KAAKE,EAAK,cAAc,CAAC,EAC9C,OAAAN,EAAoBM,EACbA,EAETA,EAAMF,EAAK,QAAQE,CAAG,CACxB,CAGA,IAAMH,EAAcD,EAAK,IAAI,EAC7B,OAAAF,EAAoBG,EACbA,CACT,MAAQ,CACN,IAAMA,EAAcD,EAAK,IAAI,EAC7B,OAAAF,EAAoBG,EACbA,CACT,CACF,CAKO,SAASI,GAAyB,CACvC,OAAON,EAAgB,CACzB,CAMA,SAASO,GAA0C,CACjD,GAAIT,IAAiB,KAAM,OAAOA,EAElC,IAAMG,EAAQ,WAAmB,QACjC,GAAI,OAAOA,EAAS,KAAe,CAACA,GAAM,UAAU,KAClD,OAAAH,EAAe,CAAC,EACTA,EAGT,GAAI,CACF,GAAI,CAACD,EACH,OAAAC,EAAe,CAAC,EACTA,EAGT,IAAMM,EAAKP,EAAY,IAAI,EACrBM,EAAON,EAAY,MAAM,EAGzBW,EAAcR,EAAgB,EAC9BS,EAAaN,EAAK,KAAKK,EAAajB,CAAe,EAEzD,GAAI,CAACa,EAAG,WAAWK,CAAU,EAAG,CAE9B,IAAMC,EAAUP,EAAK,KAAKF,EAAK,IAAI,EAAGV,CAAe,EACrD,GAAIa,EAAG,WAAWM,CAAO,EAAG,CAC1B,IAAMC,EAAUP,EAAG,aAAaM,EAAS,OAAO,EAChD,OAAAZ,EAAe,KAAK,MAAMa,CAAO,EAE7BV,EAAK,KAAK,WAAa,cACzB,QAAQ,IAAI,uCAAuCS,CAAO,EAAE,EAGvDZ,CACT,CAEA,OAAAA,EAAe,CAAC,EACTA,CACT,CAEA,IAAMa,EAAUP,EAAG,aAAaK,EAAY,OAAO,EACnD,OAAAX,EAAe,KAAK,MAAMa,CAAO,EAE7BV,EAAK,KAAK,WAAa,cACzB,QAAQ,IAAI,uCAAuCQ,CAAU,EAAE,EAG1DX,CACT,OAASc,EAAU,CACjB,OAAIA,GAAK,OAAS,UAChB,QAAQ,KAAK,0CAA0CA,GAAK,OAAO,EAAE,EAEvEd,EAAe,CAAC,EACTA,CACT,CACF,CASA,SAASe,EAAyCC,EAASC,EAAyB,CAClF,IAAMC,EAAS,CAAE,GAAGF,CAAK,EAEzB,QAAWG,KAAOF,EACZA,EAASE,CAAG,IAAM,SAElB,OAAOF,EAASE,CAAG,GAAM,UACzBF,EAASE,CAAG,IAAM,MAClB,CAAC,MAAM,QAAQF,EAASE,CAAG,CAAC,GAC5B,OAAOD,EAAOC,CAAG,GAAM,UACvBD,EAAOC,CAAG,IAAM,KAEhBD,EAAOC,CAAG,EAAIJ,EAAUG,EAAOC,CAAG,EAAGF,EAASE,CAAG,CAAC,EAElDD,EAAOC,CAAG,EAAIF,EAASE,CAAG,GAKhC,OAAOD,CACT,CAMO,SAASE,EACdC,EAAmC,CAAC,EACX,CACzB,IAAMC,EAAab,EAAmB,EAGtC,OADeM,EAAUO,EAAmBD,CAAc,CAE5D,CAKO,SAASE,GAAyB,CACvCvB,EAAe,KACfC,EAAoB,IACtB,CChNA,IAAAuB,EAAA,GAOMC,EAAS,OAAQ,WAAmB,QAAY,KAChD,WAAmB,SAAS,UAAU,MAAQ,KAE9CC,EAAY,OAAQ,WAAmB,OAAW,IAGxD,SAASC,GAAmD,CAC1D,GAAI,CAACF,EAAQ,OAAO,KAGpB,GAAI,OAAQ,WAAmB,SAAY,WACzC,OAAQ,WAAmB,QAI7B,GAAI,CACF,IAAMG,EAAM,SAAS,wDAAwD,EAAE,EAC/E,GAAIA,EAAK,OAAOA,CAClB,MAAQ,CAER,CAGA,GAAI,CAEF,GAAM,CAAE,cAAAC,CAAc,EAAI,SAAS,+BAA+B,EAAE,EAE9DC,EAAM,OAAON,GAAa,KAAQ,UAAYA,EAAY,IAC5DA,EAAY,IACZ,UAAa,WAAmB,SAAS,MAAM,EAAI,IACvD,OAAOK,EAAcC,CAAG,CAC1B,MAAQ,CACN,OAAO,IACT,CACF,CAEA,IAAMC,EAAcJ,EAAmB,EAMvC,SAASK,EAAgBC,EAAyBC,EAA4B,CAC5E,IAAMC,EAAO,IAAI,KAEjB,OAAQF,EAAQ,CACd,IAAK,OACH,OAAO,OAAOE,EAAK,QAAQ,CAAC,EAE9B,IAAK,QACH,OAAOA,EAAK,eAAe,QAAS,CAClC,SAAUD,IAAa,MAAQ,MAAQ,OACvC,MAAO,QACP,IAAK,UACL,KAAM,UACN,OAAQ,UACR,OAAQ,UACR,OAAQ,EACV,CAAC,EAGH,QACE,OAAOA,IAAa,MAChBC,EAAK,YAAY,EACjB,IAAI,KAAKA,EAAK,QAAQ,EAAIA,EAAK,kBAAkB,EAAI,GAAK,EACvD,YAAY,EACZ,MAAM,EAAG,EAAE,CACtB,CACF,CAMA,SAASC,EAAUC,EAAsB,CACvC,IAAMC,EAAQD,EAAK,MAAM,iCAAiC,EAC1D,GAAI,CAACC,EAAO,MAAO,IAAK,KAAO,KAE/B,IAAMC,EAAQ,WAAWD,EAAM,CAAC,CAAE,EAC5BE,EAAOF,EAAM,CAAC,EAAG,YAAY,EAE7BG,EAAsC,CAC1C,GAAM,KACN,GAAM,KAAO,KACb,GAAM,KAAO,KAAO,IACtB,EAEA,OAAOF,GAASE,EAAYD,CAAI,GAAK,GAAK,KAAO,KACnD,CAqBO,IAAME,EAAN,KAAa,CACV,QACA,aACA,cAAgB,GAChB,GAAU,KACV,KAAY,KAEpB,YAAYC,EAA0B,CAAC,EAAG,CACxC,KAAK,QAAU,CACb,WAAYA,EAAQ,YAAc,GAClC,gBAAiBA,EAAQ,iBAAmB,MAC5C,SAAUA,EAAQ,UAAY,MAC9B,QAASA,EAAQ,SAAW,GAC5B,KAAMA,EAAQ,MAAQ,2BACtB,OAAQA,EAAQ,QAAU,OAC1B,QAASA,EAAQ,SAAW,OAC5B,UAAWA,EAAQ,WAAa,GAChC,UAAWA,EAAQ,WAAa,GAChC,YAAaA,EAAQ,aAAe,EACtC,EAEA,KAAK,aAAeP,EAAU,KAAK,QAAQ,OAAO,EAE9C,KAAK,QAAQ,SACf,KAAK,gBAAgB,CAEzB,CAEQ,iBAAwB,CAC9B,GAAIV,EAAW,CACR,KAAK,gBACR,QAAQ,KACN,8GAEF,EACA,KAAK,cAAgB,IAEvB,MACF,CAEA,GAAKD,EAEL,GAAI,CAEF,GAAIM,EAAa,CACf,KAAK,GAAKA,EAAY,IAAI,EAC1B,KAAK,KAAOA,EAAY,MAAM,EAG9B,IAAMa,EAAcC,EAAe,EAC7BC,EAAe,KAAK,KAAK,WAAW,KAAK,QAAQ,IAAI,EACvD,KAAK,QAAQ,KACb,KAAK,KAAK,KAAKF,EAAa,KAAK,QAAQ,IAAI,EAGjD,KAAK,QAAQ,KAAOE,EAGpB,IAAMC,EAAM,KAAK,KAAK,QAAQD,CAAY,EACrC,KAAK,GAAG,WAAWC,CAAG,GACzB,KAAK,GAAG,UAAUA,EAAK,CAAE,UAAW,EAAK,CAAC,EAI9B,WAAmB,SACvB,KAAK,WAAa,cAC1B,QAAQ,IAAI,4CAA4CD,CAAY,EAAE,CAE1E,CACF,OAASE,EAAK,CACZ,QAAQ,MAAM,qDAAsDA,CAAG,CACzE,CACF,CAEQ,cAAmC,CACzC,GAAK,KAAK,QAAQ,WAClB,OAAOhB,EAAgB,KAAK,QAAQ,gBAAiB,KAAK,QAAQ,QAAQ,CAC5E,CAEQ,YAAYiB,EAAyB,CAC3C,IAAMC,EAAY,KAAK,aAAa,EAEpC,GAAI,KAAK,QAAQ,SAAW,OAAQ,CAClC,IAAMC,EAAW,CACf,MAAOF,EAAM,MACb,KAAMA,EAAM,KACZ,QAASA,EAAM,OACjB,EACA,OAAIC,IAAWC,EAAI,UAAYD,GAC3BD,EAAM,QAAOE,EAAI,MAAQF,EAAM,OAC/BA,EAAM,UAAY,SAAWE,EAAI,QAAUF,EAAM,SACjDA,EAAM,QAAOE,EAAI,MAAQ,OAAOF,EAAM,KAAK,GACxC,KAAK,UAAUE,CAAG,CAC3B,CAGA,IAAMC,EAAkB,CAAC,EACzB,OAAIF,GAAWE,EAAM,KAAK,IAAIF,CAAS,GAAG,EAC1CE,EAAM,KAAK,IAAIH,EAAM,MAAM,YAAY,CAAC,GAAG,EACvCA,EAAM,OAAOG,EAAM,KAAK,IAAIH,EAAM,KAAK,GAAG,EAC9CG,EAAM,KAAKH,EAAM,OAAO,EACpBA,EAAM,UAAY,QACpBG,EAAM,KAAK,cAAc,KAAK,UAAUH,EAAM,OAAO,CAAC,EAAE,EAEtDA,EAAM,OACRG,EAAM,KAAK,YAAYH,EAAM,KAAK,EAAE,EAG/BG,EAAM,KAAK,GAAG,CACvB,CAEQ,YAAYC,EAAuB,CACzC,GAAI,GAAC,KAAK,IAAM,CAAC,KAAK,MAAQ,CAAC5B,GAE/B,GAAI,CACF,IAAM6B,EAAOD,EAAU;AAAA,EAGnB,KAAK,GAAG,WAAW,KAAK,QAAQ,IAAI,GACxB,KAAK,GAAG,SAAS,KAAK,QAAQ,IAAI,EACtC,MAAQ,KAAK,cACrB,KAAK,UAAU,EAKnB,KAAK,GAAG,eAAe,KAAK,QAAQ,KAAMC,EAAM,MAAM,CACxD,OAASN,EAAK,CACZ,QAAQ,MAAM,+CAAgDA,CAAG,CACnE,CACF,CAEQ,WAAkB,CACxB,GAAI,GAAC,KAAK,IAAM,CAAC,KAAK,MAEtB,GAAI,CAEF,IAAIO,EAAc,EAClB,KAAO,KAAK,GAAG,WAAW,GAAG,KAAK,QAAQ,IAAI,IAAIA,CAAW,EAAE,GAC7DA,IAIF,KAAK,GAAG,WAAW,KAAK,QAAQ,KAAM,GAAG,KAAK,QAAQ,IAAI,IAAIA,CAAW,EAAE,CAC7E,OAASP,EAAK,CACZ,QAAQ,MAAM,6CAA8CA,CAAG,CACjE,CACF,CAMA,SAASQ,EAAeC,EAAwB,CAC9C,GAAI,CAAC,KAAK,QAAQ,UAAW,OAE7B,IAAMR,EAAkB,CACtB,MAAO,OACP,KAAM,QACN,MAAAO,EACA,QAAS,gBACT,QAAAC,CACF,EAEMC,EAAY,KAAK,YAAYT,CAAK,EACxC,QAAQ,IAAIS,CAAS,EAEjB,KAAK,QAAQ,SACf,KAAK,YAAYA,CAAS,CAE9B,CAEA,SAASF,EAAeG,EAAgBC,EAA0B,CAChE,GAAI,CAAC,KAAK,QAAQ,UAAW,OAE7B,IAAMX,EAAkB,CACtB,MAAO,QACP,KAAM,QACN,MAAAO,EACA,QAAS,yBACT,MAAAG,CACF,EAEMD,EAAY,KAAK,YAAYT,CAAK,EACxC,QAAQ,MAAMS,CAAS,EAEnB,KAAK,QAAQ,SACf,KAAK,YAAYA,CAAS,CAE9B,CAEA,WAAWF,EAAeK,EAAiBC,EAAyC,CAClF,GAAI,CAAC,KAAK,QAAQ,YAAa,OAE/B,IAAMb,EAAkB,CACtB,MAAO,OACP,KAAM,UACN,MAAAO,EACA,QAAAK,EACA,QAASC,CACX,EAEMJ,EAAY,KAAK,YAAYT,CAAK,EACxC,QAAQ,KAAKS,CAAS,EAElB,KAAK,QAAQ,SACf,KAAK,YAAYA,CAAS,CAE9B,CACF,ECrTA,IAAMK,EAA6B,CACjCC,EACAC,EACAC,IACS,CAEX,EAMO,SAASC,EACdC,EAAmC,CAAC,EAClB,CAElB,IAAMC,EAASC,EAAYF,CAAO,EAG5BG,EAAS,IAAIC,EAAOH,EAAO,OAAO,EAGlCI,EAAoD,IAAI,IACxDC,EAAqC,IAAI,IAG3CC,EAAeN,EAAO,cAAgB,GACtCO,EAAyBR,EAAQ,wBAA0BL,EAC3Dc,EAAsDR,EAAO,SAAW,UAGtES,EAAS,IAAI,IASbC,EAAO,GAAcN,EAAS,IAAI,CAAC,GAAKA,EAAS,IAAI,EAAG,IAAI,GAAK,EAAE,IAAI,CAAC,EAExEO,EAAc,CAClBC,EACAC,EACAC,IACS,CAGT,GAFAZ,EAAO,SAASW,EAAOD,EAAOE,CAAO,EAEjCN,IAAiB,QACnB,MAAMI,EACG,OAAOJ,GAAiB,YACjCA,EAAaI,EAAOC,EAAOC,CAAO,CAGtC,EAEMC,EAAW,CACfD,EACAD,EACAG,IACyB,CACzB,GAAI,CACF,IAAMC,EAASH,EAAQE,CAAO,EAC9B,GAAIC,aAAkB,QACpB,OAAOA,EAAO,MAAOC,GAAQP,EAAYO,EAAKL,EAAOC,CAAO,CAAC,CAEjE,OAASI,EAAK,CACZP,EAAYO,EAAKL,EAAOC,CAAO,CACjC,CACF,EAEMK,EAAoB,CAAwBN,EAAUO,IAAwB,CAClF,GAAId,EAAe,GAAKc,EAAQd,GAAgB,CAACG,EAAO,IAAII,CAAK,EAAG,CAClEJ,EAAO,IAAII,CAAK,EAEhB,IAAMQ,EAAU,yBAAyBD,CAAK,oBAAoBd,CAAY,IAC9EJ,EAAO,WAAWW,EAAOQ,EAAS,CAAE,MAAAD,EAAO,IAAKd,CAAa,CAAC,EAE9DC,EAAuBM,EAAOO,EAAOd,CAAY,CACnD,CACF,EAMMgB,EAA4B,CAChC,GAAGT,EAAOC,EAAS,CACjB,IAAMS,EAAMb,EAAIG,CAAK,EACrB,OAAAU,EAAI,IAAIT,CAAgC,EACxCK,EAAkBN,EAAOU,EAAI,IAAI,EAC1B,IAAMD,EAAQ,IAAIT,EAAOC,CAAO,CACzC,EAEA,IAAID,EAAOC,EAAS,CAClB,IAAMS,EAAMb,EAAIG,CAAK,EAGrB,GAAIU,EAAI,OAAOT,CAAgC,EAAG,CAC5CS,EAAI,MAAQjB,GACdG,EAAO,OAAOI,CAAK,EAErB,MACF,CAGA,QAAWW,KAAWD,EAEpB,GADUC,EACJ,aAAeV,EAAS,CAC5BS,EAAI,OAAOC,CAAO,EACdD,EAAI,MAAQjB,GACdG,EAAO,OAAOI,CAAK,EAErB,KACF,CAEJ,EAEA,KAAKA,EAAOC,EAAS,CACnB,IAAMW,GAAYT,IAChBM,EAAQ,IAAIT,EAAOY,CAAwC,EACpDX,EAAQE,CAAO,IAIxB,OAAAS,EAAQ,WAAaX,EAEdQ,EAAQ,GAAGT,EAAOY,CAAO,CAClC,EAEA,KAAKZ,KAAUG,EAAS,CACtB,IAAMU,EAAOV,EAAQ,CAAC,EAEtBd,EAAO,SAASW,EAAOa,CAAI,EAE3BhB,EAAIG,CAAK,EAAE,QAASc,GAAMZ,EAASY,EAAGd,EAAOa,CAAI,CAAC,EAClDrB,EAAU,QAASsB,GAAM,CACvB,GAAI,CACFA,EAAEd,EAAOa,CAAuB,CAClC,OAASR,EAAK,CACZP,EAAYO,EAAKL,EAAOc,CAAqC,CAC/D,CACF,CAAC,CACH,EAEA,MAAM,UAAUd,KAAUG,EAAS,CACjC,IAAMU,EAAOV,EAAQ,CAAC,EAChBY,EAA4B,CAAC,EAEnC1B,EAAO,SAASW,EAAOa,CAAI,EAE3BhB,EAAIG,CAAK,EAAE,QAASc,GAAM,CACxB,IAAMV,EAASF,EAASY,EAAGd,EAAOa,CAAI,EAClCT,aAAkB,SAASW,EAAS,KAAKX,CAAM,CACrD,CAAC,EAEDZ,EAAU,QAASsB,GAAM,CACvB,GAAI,CACF,IAAMV,EAASU,EAAEd,EAAOa,CAAuB,EAC3CT,aAAkB,SACpBW,EAAS,KAAKX,EAAO,MAAOC,GAC1BP,EAAYO,EAAKL,EAAOc,CAAqC,CAC/D,CAAC,CAEL,OAAST,EAAK,CACZP,EAAYO,EAAKL,EAAOc,CAAqC,CAC/D,CACF,CAAC,EAED,MAAM,QAAQ,IAAIC,CAAQ,CAC5B,EAEA,MAAMd,EAAS,CACb,OAAAT,EAAU,IAAIS,CAAO,EACd,IAAMQ,EAAQ,OAAOR,CAAO,CACrC,EAEA,OAAOA,EAAS,CACdT,EAAU,OAAOS,CAAO,CAC1B,EAEA,MAAMD,EAAQ,CACRA,GACFT,EAAS,OAAOS,CAAK,EACrBJ,EAAO,OAAOI,CAAK,IAEnBT,EAAS,MAAM,EACfC,EAAU,MAAM,EAChBI,EAAO,MAAM,EAEjB,EAEA,cAAcI,EAAO,CACnB,OAAOH,EAAIG,CAAK,EAAE,IACpB,EAEA,gBAAgBC,EAAS,CACvBN,EAAeM,CACjB,EAEA,gBAAgBe,EAAG,CACjBvB,EAAeuB,EACXA,IAAM,GAAGpB,EAAO,MAAM,CAC5B,EAEA,iBAAkB,CAChB,OAAOH,CACT,EAEA,YAAa,CACX,OAAO,MAAM,KAAKF,EAAS,KAAK,CAAC,EAAE,OAChC0B,GAAM1B,EAAS,IAAI0B,CAAC,EAAG,KAAO,CACjC,CACF,EAEA,UAAUjB,EAAO,CACf,IAAMU,EAAMb,EAAIG,CAAK,EAErB,OAAO,MAAM,KAAKU,CAAG,EAAE,IAAIT,GACTA,EACA,YAAcA,CAC/B,CACH,EAEA,mBAAoB,CAClB,OAAO,MAAM,KAAKT,CAAS,CAC7B,EAEA,YAAYQ,EAAOC,EAAS,CAC1B,IAAMS,EAAMb,EAAIG,CAAK,EAGrB,GAAIU,EAAI,IAAIT,CAAgC,EAC1C,MAAO,GAIT,QAAWU,KAAWD,EAEpB,GADUC,EACJ,aAAeV,EACnB,MAAO,GAIX,MAAO,EACT,CACF,EAEA,OAAOQ,CACT","names":["index_exports","__export","clearConfigCache","createEmitochondria","__toCommonJS","import_meta","CONFIG_FILENAME","isNode","getRequireFunction","req","createRequire","url","nodeRequire","cachedConfig","cachedProjectRoot","findProjectRoot","proc","cwd","path","fs","dir","getProjectRoot","loadConfigFileSync","projectRoot","configPath","cwdPath","content","err","deepMerge","base","override","result","key","mergeConfig","options","fileConfig","clearConfigCache","import_meta","isNode","isBrowser","getRequireFunction","req","createRequire","url","nodeRequire","formatTimestamp","format","timezone","date","parseSize","size","match","value","unit","multipliers","Logger","options","projectRoot","getProjectRoot","resolvedPath","dir","err","entry","timestamp","obj","parts","content","line","rotationNum","event","payload","formatted","error","_handler","message","details","defaultMaxListenersHandler","_event","_count","_max","createEmitochondria","options","config","mergeConfig","logger","Logger","handlers","wildcards","maxListeners","onMaxListenersExceeded","errorHandler","warned","get","handleError","error","event","handler","safeCall","payload","result","err","checkMaxListeners","count","message","emitter","set","wrapped","wrapper","data","h","promises","n","k"]}
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- var x="emitochondria.config.json",d=null,m=null;function S(){if(m!==null)return m;let a=globalThis.process;if(typeof a>"u"||!a?.versions?.node)return m="","";try{let t=globalThis.require;if(!t){let E=a.cwd();return m=E,E}let n=t("path"),o=t("fs"),r=a.cwd();for(;r!==n.dirname(r);){if(o.existsSync(n.join(r,"package.json")))return m=r,r;r=n.dirname(r)}let c=a.cwd();return m=c,c}catch{let t=a.cwd();return m=t,t}}function L(){return S()}function z(){if(d!==null)return d;let a=globalThis.process;if(typeof a>"u"||!a?.versions?.node)return d={},d;try{let t=globalThis.require;if(!t)return d={},d;let n=t("fs"),o=t("path"),r=S(),c=o.join(r,x);if(!n.existsSync(c)){let g=o.join(a.cwd(),x);if(n.existsSync(g)){let p=n.readFileSync(g,"utf-8");return d=JSON.parse(p),a.env?.NODE_ENV!=="production"&&console.log(`[Emitochondria] Config loaded from: ${g}`),d}return d={},d}let E=n.readFileSync(c,"utf-8");return d=JSON.parse(E),a.env?.NODE_ENV!=="production"&&console.log(`[Emitochondria] Config loaded from: ${c}`),d}catch(t){return t?.code!=="ENOENT"&&console.warn(`[Emitochondria] Failed to load config: ${t?.message}`),d={},d}}function k(a,t){let n={...a};for(let o in t)t[o]!==void 0&&(typeof t[o]=="object"&&t[o]!==null&&!Array.isArray(t[o])&&typeof n[o]=="object"&&n[o]!==null?n[o]=k(n[o],t[o]):n[o]=t[o]);return n}function H(a={}){let t=z();return k(t,a)}function M(){d=null,m=null}var b=typeof globalThis.process<"u"&&globalThis.process?.versions?.node!=null,j=typeof globalThis.window<"u";function _(a,t){let n=new Date;switch(a){case"unix":return String(n.getTime());case"human":return n.toLocaleString("en-US",{timeZone:t==="utc"?"UTC":void 0,month:"short",day:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit",hour12:!0});default:return t==="utc"?n.toISOString():new Date(n.getTime()-n.getTimezoneOffset()*6e4).toISOString().slice(0,-1)}}function N(a){let t=a.match(/^(\d+(?:\.\d+)?)\s*(KB|MB|GB)$/i);if(!t)return 10*1024*1024;let n=parseFloat(t[1]),o=t[2].toUpperCase(),r={KB:1024,MB:1024*1024,GB:1024*1024*1024};return n*(r[o]??10*1024*1024)}var v=class{options;maxSizeBytes;browserWarned=!1;fs=null;path=null;constructor(t={}){this.options={timestamps:t.timestamps??!1,timestampFormat:t.timestampFormat??"iso",timezone:t.timezone??"utc",persist:t.persist??!1,path:t.path??"./logs/emitochondria.log",format:t.format??"text",maxSize:t.maxSize??"10MB",logEvents:t.logEvents??!1,logErrors:t.logErrors??!0,logWarnings:t.logWarnings??!0},this.maxSizeBytes=N(this.options.maxSize),this.options.persist&&this.initFileLogging()}initFileLogging(){if(j){this.browserWarned||(console.warn("[Emitochondria] File logging is not available in browser environments. Logs will only be written to console."),this.browserWarned=!0);return}if(b)try{let t=globalThis.require;if(t){this.fs=t("fs"),this.path=t("path");let n=L(),o=this.path.isAbsolute(this.options.path)?this.options.path:this.path.join(n,this.options.path);this.options.path=o;let r=this.path.dirname(o);this.fs.existsSync(r)||this.fs.mkdirSync(r,{recursive:!0}),globalThis.process?.env?.NODE_ENV!=="production"&&console.log(`[Emitochondria] Logs will be written to: ${o}`)}}catch(t){console.error("[Emitochondria] Failed to initialize file logging:",t)}}getTimestamp(){if(this.options.timestamps)return _(this.options.timestampFormat,this.options.timezone)}formatEntry(t){let n=this.getTimestamp();if(this.options.format==="json"){let r={level:t.level,type:t.type,message:t.message};return n&&(r.timestamp=n),t.event&&(r.event=t.event),t.payload!==void 0&&(r.payload=t.payload),t.error&&(r.error=String(t.error)),JSON.stringify(r)}let o=[];return n&&o.push(`[${n}]`),o.push(`[${t.level.toUpperCase()}]`),t.event&&o.push(`[${t.event}]`),o.push(t.message),t.payload!==void 0&&o.push(`| Payload: ${JSON.stringify(t.payload)}`),t.error&&o.push(`| Error: ${t.error}`),o.join(" ")}writeToFile(t){if(!(!this.fs||!this.path||!b))try{let n=t+`
2
- `;this.fs.existsSync(this.options.path)&&this.fs.statSync(this.options.path).size>=this.maxSizeBytes&&this.rotateLog(),this.fs.appendFileSync(this.options.path,n,"utf8")}catch(n){console.error("[Emitochondria] Failed to write to log file:",n)}}rotateLog(){if(!(!this.fs||!this.path))try{let t=1;for(;this.fs.existsSync(`${this.options.path}.${t}`);)t++;this.fs.renameSync(this.options.path,`${this.options.path}.${t}`)}catch(t){console.error("[Emitochondria] Failed to rotate log file:",t)}}logEvent(t,n){if(!this.options.logEvents)return;let o={level:"info",type:"event",event:t,message:"Event emitted",payload:n},r=this.formatEntry(o);console.log(r),this.options.persist&&this.writeToFile(r)}logError(t,n,o){if(!this.options.logErrors)return;let r={level:"error",type:"error",event:t,message:"Handler threw an error",error:n},c=this.formatEntry(r);console.error(c),this.options.persist&&this.writeToFile(c)}logWarning(t,n,o){if(!this.options.logWarnings)return;let r={level:"warn",type:"warning",event:t,message:n,payload:o},c=this.formatEntry(r);console.warn(c),this.options.persist&&this.writeToFile(c)}};var P=(a,t,n)=>{};function F(a={}){let t=H(a),n=new v(t.logging),o=new Map,r=new Set,c=t.maxListeners??10,E=a.onMaxListenersExceeded??P,g=t.onError??"default",p=new Set,u=e=>o.get(e)??o.set(e,new Set).get(e),y=(e,s,i)=>{if(n.logError(s,e,i),g==="throw")throw e;typeof g=="function"&&g(e,s,i)},T=(e,s,i)=>{try{let l=e(i);if(l instanceof Promise)return l.catch(f=>y(f,s,e))}catch(l){y(l,s,e)}},C=(e,s)=>{if(c>0&&s>c&&!p.has(e)){p.add(e);let i=`Possible memory leak: ${s} listeners (max: ${c})`;n.logWarning(e,i,{count:s,max:c}),E(e,s,c)}},w={on(e,s){let i=u(e);return i.add(s),C(e,i.size),()=>w.off(e,s)},off(e,s){let i=u(e);if(i.delete(s)){i.size<=c&&p.delete(e);return}for(let l of i)if(l.__original===s){i.delete(l),i.size<=c&&p.delete(e);break}},once(e,s){let i=(l=>(w.off(e,i),s(l)));return i.__original=s,w.on(e,i)},emit(e,...s){let i=s[0];n.logEvent(e,i),u(e).forEach(l=>T(l,e,i)),r.forEach(l=>{try{l(e,i)}catch(f){y(f,e,l)}})},async emitAsync(e,...s){let i=s[0],l=[];n.logEvent(e,i),u(e).forEach(f=>{let h=T(f,e,i);h instanceof Promise&&l.push(h)}),r.forEach(f=>{try{let h=f(e,i);h instanceof Promise&&l.push(h.catch(O=>y(O,e,f)))}catch(h){y(h,e,f)}}),await Promise.all(l)},onAny(e){return r.add(e),()=>w.offAny(e)},offAny(e){r.delete(e)},clear(e){e?(o.delete(e),p.delete(e)):(o.clear(),r.clear(),p.clear())},listenerCount(e){return u(e).size},setErrorHandler(e){g=e},setMaxListeners(e){c=e,e===0&&p.clear()},getMaxListeners(){return c},eventNames(){return Array.from(o.keys()).filter(e=>o.get(e).size>0)},listeners(e){let s=u(e);return Array.from(s).map(i=>i.__original||i)},wildcardListeners(){return Array.from(r)},hasListener(e,s){let i=u(e);if(i.has(s))return!0;for(let l of i)if(l.__original===s)return!0;return!1}};return w}export{M as clearConfigCache,F as createEmitochondria,F as default};
1
+ var L="emitochondria.config.json",q=typeof globalThis.process<"u"&&globalThis.process?.versions?.node!=null;function j(){if(!q)return null;if(typeof globalThis.require=="function")return globalThis.require;try{let o=Function('return typeof require !== "undefined" ? require : null')();if(o)return o}catch{}try{let{createRequire:o}=Function('return require("node:module")')(),t=typeof import.meta?.url=="string"&&import.meta.url?import.meta.url:"file://"+globalThis.process?.cwd?.()+"/";return o(t)}catch{return null}}var y=j(),f=null,u=null;function k(){if(u!==null)return u;let o=globalThis.process;if(typeof o>"u"||!o?.versions?.node)return u="","";try{if(!y){let l=o.cwd();return u=l,l}let t=y("path"),r=y("fs"),n=o.cwd();for(;n!==t.dirname(n);){if(r.existsSync(t.join(n,"package.json")))return u=n,n;n=t.dirname(n)}let s=o.cwd();return u=s,s}catch{let t=o.cwd();return u=t,t}}function F(){return k()}function N(){if(f!==null)return f;let o=globalThis.process;if(typeof o>"u"||!o?.versions?.node)return f={},f;try{if(!y)return f={},f;let t=y("fs"),r=y("path"),n=k(),s=r.join(n,L);if(!t.existsSync(s)){let E=r.join(o.cwd(),L);if(t.existsSync(E)){let h=t.readFileSync(E,"utf-8");return f=JSON.parse(h),o.env?.NODE_ENV!=="production"&&console.log(`[Emitochondria] Config loaded from: ${E}`),f}return f={},f}let l=t.readFileSync(s,"utf-8");return f=JSON.parse(l),o.env?.NODE_ENV!=="production"&&console.log(`[Emitochondria] Config loaded from: ${s}`),f}catch(t){return t?.code!=="ENOENT"&&console.warn(`[Emitochondria] Failed to load config: ${t?.message}`),f={},f}}function H(o,t){let r={...o};for(let n in t)t[n]!==void 0&&(typeof t[n]=="object"&&t[n]!==null&&!Array.isArray(t[n])&&typeof r[n]=="object"&&r[n]!==null?r[n]=H(r[n],t[n]):r[n]=t[n]);return r}function C(o={}){let t=N();return H(t,o)}function _(){f=null,u=null}var S=typeof globalThis.process<"u"&&globalThis.process?.versions?.node!=null,P=typeof globalThis.window<"u";function R(){if(!S)return null;if(typeof globalThis.require=="function")return globalThis.require;try{let o=Function('return typeof require !== "undefined" ? require : null')();if(o)return o}catch{}try{let{createRequire:o}=Function('return require("node:module")')(),t=typeof import.meta?.url=="string"&&import.meta.url?import.meta.url:"file://"+globalThis.process?.cwd?.()+"/";return o(t)}catch{return null}}var x=R();function W(o,t){let r=new Date;switch(o){case"unix":return String(r.getTime());case"human":return r.toLocaleString("en-US",{timeZone:t==="utc"?"UTC":void 0,month:"short",day:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit",hour12:!0});default:return t==="utc"?r.toISOString():new Date(r.getTime()-r.getTimezoneOffset()*6e4).toISOString().slice(0,-1)}}function $(o){let t=o.match(/^(\d+(?:\.\d+)?)\s*(KB|MB|GB)$/i);if(!t)return 10*1024*1024;let r=parseFloat(t[1]),n=t[2].toUpperCase(),s={KB:1024,MB:1024*1024,GB:1024*1024*1024};return r*(s[n]??10*1024*1024)}var T=class{options;maxSizeBytes;browserWarned=!1;fs=null;path=null;constructor(t={}){this.options={timestamps:t.timestamps??!1,timestampFormat:t.timestampFormat??"iso",timezone:t.timezone??"utc",persist:t.persist??!1,path:t.path??"./logs/emitochondria.log",format:t.format??"text",maxSize:t.maxSize??"10MB",logEvents:t.logEvents??!1,logErrors:t.logErrors??!0,logWarnings:t.logWarnings??!0},this.maxSizeBytes=$(this.options.maxSize),this.options.persist&&this.initFileLogging()}initFileLogging(){if(P){this.browserWarned||(console.warn("[Emitochondria] File logging is not available in browser environments. Logs will only be written to console."),this.browserWarned=!0);return}if(S)try{if(x){this.fs=x("fs"),this.path=x("path");let t=F(),r=this.path.isAbsolute(this.options.path)?this.options.path:this.path.join(t,this.options.path);this.options.path=r;let n=this.path.dirname(r);this.fs.existsSync(n)||this.fs.mkdirSync(n,{recursive:!0}),globalThis.process?.env?.NODE_ENV!=="production"&&console.log(`[Emitochondria] Logs will be written to: ${r}`)}}catch(t){console.error("[Emitochondria] Failed to initialize file logging:",t)}}getTimestamp(){if(this.options.timestamps)return W(this.options.timestampFormat,this.options.timezone)}formatEntry(t){let r=this.getTimestamp();if(this.options.format==="json"){let s={level:t.level,type:t.type,message:t.message};return r&&(s.timestamp=r),t.event&&(s.event=t.event),t.payload!==void 0&&(s.payload=t.payload),t.error&&(s.error=String(t.error)),JSON.stringify(s)}let n=[];return r&&n.push(`[${r}]`),n.push(`[${t.level.toUpperCase()}]`),t.event&&n.push(`[${t.event}]`),n.push(t.message),t.payload!==void 0&&n.push(`| Payload: ${JSON.stringify(t.payload)}`),t.error&&n.push(`| Error: ${t.error}`),n.join(" ")}writeToFile(t){if(!(!this.fs||!this.path||!S))try{let r=t+`
2
+ `;this.fs.existsSync(this.options.path)&&this.fs.statSync(this.options.path).size>=this.maxSizeBytes&&this.rotateLog(),this.fs.appendFileSync(this.options.path,r,"utf8")}catch(r){console.error("[Emitochondria] Failed to write to log file:",r)}}rotateLog(){if(!(!this.fs||!this.path))try{let t=1;for(;this.fs.existsSync(`${this.options.path}.${t}`);)t++;this.fs.renameSync(this.options.path,`${this.options.path}.${t}`)}catch(t){console.error("[Emitochondria] Failed to rotate log file:",t)}}logEvent(t,r){if(!this.options.logEvents)return;let n={level:"info",type:"event",event:t,message:"Event emitted",payload:r},s=this.formatEntry(n);console.log(s),this.options.persist&&this.writeToFile(s)}logError(t,r,n){if(!this.options.logErrors)return;let s={level:"error",type:"error",event:t,message:"Handler threw an error",error:r},l=this.formatEntry(s);console.error(l),this.options.persist&&this.writeToFile(l)}logWarning(t,r,n){if(!this.options.logWarnings)return;let s={level:"warn",type:"warning",event:t,message:r,payload:n},l=this.formatEntry(s);console.warn(l),this.options.persist&&this.writeToFile(l)}};var K=(o,t,r)=>{};function O(o={}){let t=C(o),r=new T(t.logging),n=new Map,s=new Set,l=t.maxListeners??10,E=o.onMaxListenersExceeded??K,h=t.onError??"default",p=new Set,m=e=>n.get(e)??n.set(e,new Set).get(e),w=(e,a,i)=>{if(r.logError(a,e,i),h==="throw")throw e;typeof h=="function"&&h(e,a,i)},b=(e,a,i)=>{try{let c=e(i);if(c instanceof Promise)return c.catch(d=>w(d,a,e))}catch(c){w(c,a,e)}},z=(e,a)=>{if(l>0&&a>l&&!p.has(e)){p.add(e);let i=`Possible memory leak: ${a} listeners (max: ${l})`;r.logWarning(e,i,{count:a,max:l}),E(e,a,l)}},v={on(e,a){let i=m(e);return i.add(a),z(e,i.size),()=>v.off(e,a)},off(e,a){let i=m(e);if(i.delete(a)){i.size<=l&&p.delete(e);return}for(let c of i)if(c.__original===a){i.delete(c),i.size<=l&&p.delete(e);break}},once(e,a){let i=(c=>(v.off(e,i),a(c)));return i.__original=a,v.on(e,i)},emit(e,...a){let i=a[0];r.logEvent(e,i),m(e).forEach(c=>b(c,e,i)),s.forEach(c=>{try{c(e,i)}catch(d){w(d,e,c)}})},async emitAsync(e,...a){let i=a[0],c=[];r.logEvent(e,i),m(e).forEach(d=>{let g=b(d,e,i);g instanceof Promise&&c.push(g)}),s.forEach(d=>{try{let g=d(e,i);g instanceof Promise&&c.push(g.catch(M=>w(M,e,d)))}catch(g){w(g,e,d)}}),await Promise.all(c)},onAny(e){return s.add(e),()=>v.offAny(e)},offAny(e){s.delete(e)},clear(e){e?(n.delete(e),p.delete(e)):(n.clear(),s.clear(),p.clear())},listenerCount(e){return m(e).size},setErrorHandler(e){h=e},setMaxListeners(e){l=e,e===0&&p.clear()},getMaxListeners(){return l},eventNames(){return Array.from(n.keys()).filter(e=>n.get(e).size>0)},listeners(e){let a=m(e);return Array.from(a).map(i=>i.__original||i)},wildcardListeners(){return Array.from(s)},hasListener(e,a){let i=m(e);if(i.has(a))return!0;for(let c of i)if(c.__original===a)return!0;return!1}};return v}export{_ as clearConfigCache,O as createEmitochondria,O as default};
3
3
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/logger.ts","../src/emitter.ts"],"sourcesContent":["import { EmitochondriaConfig, EmitochondriaOptions, EventMap } from './types.js';\n\n// ============================================================\n// CONFIG FILE LOADING\n// ============================================================\n\nconst CONFIG_FILENAME = 'emitochondria.config.json';\n\nlet cachedConfig: EmitochondriaConfig | null = null;\nlet cachedProjectRoot: string | null = null;\n\n/**\n * Find project root by walking up directories looking for package.json.\n */\nfunction findProjectRoot(): string {\n if (cachedProjectRoot !== null) return cachedProjectRoot;\n\n const proc = (globalThis as any).process;\n if (typeof proc === 'undefined' || !proc?.versions?.node) {\n cachedProjectRoot = '';\n return '';\n }\n\n try {\n const req = (globalThis as any).require;\n if (!req) {\n const cwd: string = proc.cwd();\n cachedProjectRoot = cwd;\n return cwd;\n }\n\n const path = req('path');\n const fs = req('fs');\n\n let dir: string = proc.cwd();\n\n // Walk up looking for package.json\n while (dir !== path.dirname(dir)) {\n if (fs.existsSync(path.join(dir, 'package.json'))) {\n cachedProjectRoot = dir;\n return dir;\n }\n dir = path.dirname(dir);\n }\n\n // Fallback to cwd if no package.json found\n const cwd: string = proc.cwd();\n cachedProjectRoot = cwd;\n return cwd;\n } catch {\n const cwd: string = proc.cwd();\n cachedProjectRoot = cwd;\n return cwd;\n }\n}\n\n/**\n * Get the cached project root (for use by logger).\n */\nexport function getProjectRoot(): string {\n return findProjectRoot();\n}\n\n/**\n * Synchronous version for initial load.\n * Falls back to empty config if loading fails.\n */\nfunction loadConfigFileSync(): EmitochondriaConfig {\n if (cachedConfig !== null) return cachedConfig;\n\n const proc = (globalThis as any).process;\n if (typeof proc === 'undefined' || !proc?.versions?.node) {\n cachedConfig = {};\n return cachedConfig;\n }\n\n try {\n const req = (globalThis as any).require;\n if (!req) {\n cachedConfig = {};\n return cachedConfig;\n }\n\n const fs = req('fs');\n const path = req('path');\n\n // Look for config in project root first\n const projectRoot = findProjectRoot();\n const configPath = path.join(projectRoot, CONFIG_FILENAME);\n\n if (!fs.existsSync(configPath)) {\n // Also try cwd as fallback\n const cwdPath = path.join(proc.cwd(), CONFIG_FILENAME);\n if (fs.existsSync(cwdPath)) {\n const content = fs.readFileSync(cwdPath, 'utf-8');\n cachedConfig = JSON.parse(content) as EmitochondriaConfig;\n\n if (proc.env?.NODE_ENV !== 'production') {\n console.log(`[Emitochondria] Config loaded from: ${cwdPath}`);\n }\n\n return cachedConfig;\n }\n\n cachedConfig = {};\n return cachedConfig;\n }\n\n const content = fs.readFileSync(configPath, 'utf-8');\n cachedConfig = JSON.parse(content) as EmitochondriaConfig;\n\n if (proc.env?.NODE_ENV !== 'production') {\n console.log(`[Emitochondria] Config loaded from: ${configPath}`);\n }\n\n return cachedConfig;\n } catch (err: any) {\n if (err?.code !== 'ENOENT') {\n console.warn(`[Emitochondria] Failed to load config: ${err?.message}`);\n }\n cachedConfig = {};\n return cachedConfig;\n }\n}\n\n// ============================================================\n// CONFIG MERGING\n// ============================================================\n\n/**\n * Deep merge two objects, with second taking precedence.\n */\nfunction deepMerge<T extends Record<string, any>>(base: T, override: Partial<T>): T {\n const result = { ...base };\n\n for (const key in override) {\n if (override[key] !== undefined) {\n if (\n typeof override[key] === 'object' &&\n override[key] !== null &&\n !Array.isArray(override[key]) &&\n typeof result[key] === 'object' &&\n result[key] !== null\n ) {\n result[key] = deepMerge(result[key], override[key]);\n } else {\n result[key] = override[key] as T[typeof key];\n }\n }\n }\n\n return result;\n}\n\n/**\n * Merge file config with options.\n * Options take precedence over file config.\n */\nexport function mergeConfig<T extends EventMap>(\n options: EmitochondriaOptions<T> = {}\n): EmitochondriaOptions<T> {\n const fileConfig = loadConfigFileSync();\n // Type assertion is safe here because we control both inputs\n const merged = deepMerge(fileConfig as any, options as any);\n return merged as EmitochondriaOptions<T>;\n}\n\n/**\n * Clear cached config (useful for testing).\n */\nexport function clearConfigCache(): void {\n cachedConfig = null;\n cachedProjectRoot = null;\n}\n","import { LoggingOptions, TimestampFormat, Timezone } from './types.js';\nimport { getProjectRoot } from './config.js';\n\n// ============================================================\n// ENVIRONMENT DETECTION\n// ============================================================\n\nconst isNode = typeof (globalThis as any).process !== 'undefined'\n && (globalThis as any).process?.versions?.node != null;\n\nconst isBrowser = typeof (globalThis as any).window !== 'undefined';\n\n// ============================================================\n// TIMESTAMP FORMATTING\n// ============================================================\n\nfunction formatTimestamp(format: TimestampFormat, timezone: Timezone): string {\n const date = new Date();\n\n switch (format) {\n case 'unix':\n return String(date.getTime());\n\n case 'human':\n return date.toLocaleString('en-US', {\n timeZone: timezone === 'utc' ? 'UTC' : undefined,\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n hour12: true,\n });\n\n case 'iso':\n default:\n return timezone === 'utc'\n ? date.toISOString()\n : new Date(date.getTime() - date.getTimezoneOffset() * 60000)\n .toISOString()\n .slice(0, -1); // Remove 'Z' for local\n }\n}\n\n// ============================================================\n// SIZE PARSING\n// ============================================================\n\nfunction parseSize(size: string): number {\n const match = size.match(/^(\\d+(?:\\.\\d+)?)\\s*(KB|MB|GB)$/i);\n if (!match) return 10 * 1024 * 1024; // Default 10MB\n\n const value = parseFloat(match[1]!);\n const unit = match[2]!.toUpperCase();\n\n const multipliers: Record<string, number> = {\n 'KB': 1024,\n 'MB': 1024 * 1024,\n 'GB': 1024 * 1024 * 1024,\n };\n\n return value * (multipliers[unit] ?? 10 * 1024 * 1024);\n}\n\n// ============================================================\n// LOG ENTRY TYPES\n// ============================================================\n\nexport type LogLevel = 'info' | 'warn' | 'error';\n\nexport interface LogEntry {\n level: LogLevel;\n type: 'event' | 'error' | 'warning';\n event?: string;\n message: string;\n payload?: unknown;\n error?: unknown;\n}\n\n// ============================================================\n// LOGGER CLASS\n// ============================================================\n\nexport class Logger {\n private options: Required<LoggingOptions>;\n private maxSizeBytes: number;\n private browserWarned = false;\n private fs: any = null;\n private path: any = null;\n\n constructor(options: LoggingOptions = {}) {\n this.options = {\n timestamps: options.timestamps ?? false,\n timestampFormat: options.timestampFormat ?? 'iso',\n timezone: options.timezone ?? 'utc',\n persist: options.persist ?? false,\n path: options.path ?? './logs/emitochondria.log',\n format: options.format ?? 'text',\n maxSize: options.maxSize ?? '10MB',\n logEvents: options.logEvents ?? false,\n logErrors: options.logErrors ?? true,\n logWarnings: options.logWarnings ?? true,\n };\n\n this.maxSizeBytes = parseSize(this.options.maxSize);\n\n if (this.options.persist) {\n this.initFileLogging();\n }\n }\n\n private initFileLogging(): void {\n if (isBrowser) {\n if (!this.browserWarned) {\n console.warn(\n '[Emitochondria] File logging is not available in browser environments. ' +\n 'Logs will only be written to console.'\n );\n this.browserWarned = true;\n }\n return;\n }\n\n if (!isNode) return;\n\n try {\n // Require fs and path synchronously\n const req = (globalThis as any).require;\n if (req) {\n this.fs = req('fs');\n this.path = req('path');\n\n // Resolve path relative to project root (where package.json is)\n const projectRoot = getProjectRoot();\n const resolvedPath = this.path.isAbsolute(this.options.path)\n ? this.options.path\n : this.path.join(projectRoot, this.options.path);\n\n // Update options with resolved path\n this.options.path = resolvedPath;\n\n // Create directory if needed\n const dir = this.path.dirname(resolvedPath);\n if (!this.fs.existsSync(dir)) {\n this.fs.mkdirSync(dir, { recursive: true });\n }\n\n // Log where logs are being written (helpful for debugging)\n const proc = (globalThis as any).process;\n if (proc?.env?.NODE_ENV !== 'production') {\n console.log(`[Emitochondria] Logs will be written to: ${resolvedPath}`);\n }\n }\n } catch (err) {\n console.error('[Emitochondria] Failed to initialize file logging:', err);\n }\n }\n\n private getTimestamp(): string | undefined {\n if (!this.options.timestamps) return undefined;\n return formatTimestamp(this.options.timestampFormat, this.options.timezone);\n }\n\n private formatEntry(entry: LogEntry): string {\n const timestamp = this.getTimestamp();\n\n if (this.options.format === 'json') {\n const obj: any = {\n level: entry.level,\n type: entry.type,\n message: entry.message,\n };\n if (timestamp) obj.timestamp = timestamp;\n if (entry.event) obj.event = entry.event;\n if (entry.payload !== undefined) obj.payload = entry.payload;\n if (entry.error) obj.error = String(entry.error);\n return JSON.stringify(obj);\n }\n\n // Text format\n const parts: string[] = [];\n if (timestamp) parts.push(`[${timestamp}]`);\n parts.push(`[${entry.level.toUpperCase()}]`);\n if (entry.event) parts.push(`[${entry.event}]`);\n parts.push(entry.message);\n if (entry.payload !== undefined) {\n parts.push(`| Payload: ${JSON.stringify(entry.payload)}`);\n }\n if (entry.error) {\n parts.push(`| Error: ${entry.error}`);\n }\n\n return parts.join(' ');\n }\n\n private writeToFile(content: string): void {\n if (!this.fs || !this.path || !isNode) return;\n\n try {\n const line = content + '\\n';\n\n // Check if rotation needed\n if (this.fs.existsSync(this.options.path)) {\n const stats = this.fs.statSync(this.options.path);\n if (stats.size >= this.maxSizeBytes) {\n this.rotateLog();\n }\n }\n\n // Sync write — simple, ordered, reliable\n this.fs.appendFileSync(this.options.path, line, 'utf8');\n } catch (err) {\n console.error('[Emitochondria] Failed to write to log file:', err);\n }\n }\n\n private rotateLog(): void {\n if (!this.fs || !this.path) return;\n\n try {\n // Find next rotation number\n let rotationNum = 1;\n while (this.fs.existsSync(`${this.options.path}.${rotationNum}`)) {\n rotationNum++;\n }\n\n // Rename current file\n this.fs.renameSync(this.options.path, `${this.options.path}.${rotationNum}`);\n } catch (err) {\n console.error('[Emitochondria] Failed to rotate log file:', err);\n }\n }\n\n // ============================================================\n // PUBLIC LOGGING METHODS\n // ============================================================\n\n logEvent(event: string, payload: unknown): void {\n if (!this.options.logEvents) return;\n\n const entry: LogEntry = {\n level: 'info',\n type: 'event',\n event,\n message: 'Event emitted',\n payload,\n };\n\n const formatted = this.formatEntry(entry);\n console.log(formatted);\n\n if (this.options.persist) {\n this.writeToFile(formatted);\n }\n }\n\n logError(event: string, error: unknown, _handler?: unknown): void {\n if (!this.options.logErrors) return;\n\n const entry: LogEntry = {\n level: 'error',\n type: 'error',\n event,\n message: 'Handler threw an error',\n error,\n };\n\n const formatted = this.formatEntry(entry);\n console.error(formatted);\n\n if (this.options.persist) {\n this.writeToFile(formatted);\n }\n }\n\n logWarning(event: string, message: string, details?: Record<string, unknown>): void {\n if (!this.options.logWarnings) return;\n\n const entry: LogEntry = {\n level: 'warn',\n type: 'warning',\n event,\n message,\n payload: details,\n };\n\n const formatted = this.formatEntry(entry);\n console.warn(formatted);\n\n if (this.options.persist) {\n this.writeToFile(formatted);\n }\n }\n}\n","import {\n EventMap,\n EventKey,\n EventHandler,\n WildcardHandler,\n ErrorHandler,\n EmitochondriaOptions,\n Emitochondria,\n} from './types.js';\nimport { Logger } from './logger.js';\nimport { mergeConfig } from './config.js';\n\n// ============================================================\n// DEFAULT HANDLERS\n// ============================================================\n\nconst defaultMaxListenersHandler = <T extends EventMap>(\n _event: EventKey<T>,\n _count: number,\n _max: number\n): void => {\n // Handled by logger\n};\n\n// ============================================================\n// FACTORY FUNCTION\n// ============================================================\n\nexport function createEmitochondria<T extends EventMap>(\n options: EmitochondriaOptions<T> = {}\n): Emitochondria<T> {\n // Merge file config with options\n const config = mergeConfig(options);\n\n // Initialize logger\n const logger = new Logger(config.logging);\n\n // Handler storage\n const handlers: Map<string, Set<EventHandler<unknown>>> = new Map();\n const wildcards: Set<WildcardHandler<T>> = new Set();\n\n // Configuration state\n let maxListeners = config.maxListeners ?? 10;\n let onMaxListenersExceeded = options.onMaxListenersExceeded ?? defaultMaxListenersHandler;\n let errorHandler: ErrorHandler<T> | 'throw' | 'default' = config.onError ?? 'default';\n\n // Memory leak tracking\n const warned = new Set<string>();\n\n // ============================================================\n // HELPER FUNCTIONS\n // ============================================================\n\n // Track original handlers for once() wrappers\n type WrappedHandler<T> = EventHandler<T> & { __original?: EventHandler<T> };\n\n const get = (e: string) => handlers.get(e) ?? handlers.set(e, new Set()).get(e)!;\n\n const handleError = <K extends EventKey<T>>(\n error: unknown,\n event: K,\n handler: EventHandler<unknown>\n ): void => {\n logger.logError(event, error, handler);\n\n if (errorHandler === 'throw') {\n throw error;\n } else if (typeof errorHandler === 'function') {\n errorHandler(error, event, handler);\n }\n // 'default' = just log (already done above)\n };\n\n const safeCall = <K extends EventKey<T>>(\n handler: EventHandler<unknown>,\n event: K,\n payload: unknown\n ): void | Promise<void> => {\n try {\n const result = handler(payload);\n if (result instanceof Promise) {\n return result.catch((err) => handleError(err, event, handler));\n }\n } catch (err) {\n handleError(err, event, handler);\n }\n };\n\n const checkMaxListeners = <K extends EventKey<T>>(event: K, count: number): void => {\n if (maxListeners > 0 && count > maxListeners && !warned.has(event)) {\n warned.add(event);\n\n const message = `Possible memory leak: ${count} listeners (max: ${maxListeners})`;\n logger.logWarning(event, message, { count, max: maxListeners });\n\n onMaxListenersExceeded(event, count, maxListeners);\n }\n };\n\n // ============================================================\n // EMITTER IMPLEMENTATION\n // ============================================================\n\n const emitter: Emitochondria<T> = {\n on(event, handler) {\n const set = get(event);\n set.add(handler as EventHandler<unknown>);\n checkMaxListeners(event, set.size);\n return () => emitter.off(event, handler);\n },\n\n off(event, handler) {\n const set = get(event);\n\n // Try direct removal first\n if (set.delete(handler as EventHandler<unknown>)) {\n if (set.size <= maxListeners) {\n warned.delete(event);\n }\n return;\n }\n\n // Search for wrapped handler (for once handlers)\n for (const wrapped of set) {\n const w = wrapped as WrappedHandler<unknown>;\n if (w.__original === handler) {\n set.delete(wrapped);\n if (set.size <= maxListeners) {\n warned.delete(event);\n }\n break;\n }\n }\n },\n\n once(event, handler) {\n const wrapper = ((payload: T[typeof event]) => {\n emitter.off(event, wrapper as EventHandler<T[typeof event]>);\n return handler(payload);\n }) as WrappedHandler<T[typeof event]>;\n\n // Store original reference for manual removal\n wrapper.__original = handler;\n\n return emitter.on(event, wrapper);\n },\n\n emit(event, ...payload) {\n const data = payload[0];\n\n logger.logEvent(event, data);\n\n get(event).forEach((h) => safeCall(h, event, data));\n wildcards.forEach((h) => {\n try {\n h(event, data as T[typeof event]);\n } catch (err) {\n handleError(err, event, h as unknown as EventHandler<unknown>);\n }\n });\n },\n\n async emitAsync(event, ...payload) {\n const data = payload[0];\n const promises: Promise<void>[] = [];\n\n logger.logEvent(event, data);\n\n get(event).forEach((h) => {\n const result = safeCall(h, event, data);\n if (result instanceof Promise) promises.push(result);\n });\n\n wildcards.forEach((h) => {\n try {\n const result = h(event, data as T[typeof event]);\n if (result instanceof Promise) {\n promises.push(result.catch((err) =>\n handleError(err, event, h as unknown as EventHandler<unknown>)\n ));\n }\n } catch (err) {\n handleError(err, event, h as unknown as EventHandler<unknown>);\n }\n });\n\n await Promise.all(promises);\n },\n\n onAny(handler) {\n wildcards.add(handler);\n return () => emitter.offAny(handler);\n },\n\n offAny(handler) {\n wildcards.delete(handler);\n },\n\n clear(event?) {\n if (event) {\n handlers.delete(event);\n warned.delete(event);\n } else {\n handlers.clear();\n wildcards.clear();\n warned.clear();\n }\n },\n\n listenerCount(event) {\n return get(event).size;\n },\n\n setErrorHandler(handler) {\n errorHandler = handler;\n },\n\n setMaxListeners(n) {\n maxListeners = n;\n if (n === 0) warned.clear();\n },\n\n getMaxListeners() {\n return maxListeners;\n },\n\n eventNames() {\n return Array.from(handlers.keys()).filter(\n (k) => handlers.get(k)!.size > 0\n ) as EventKey<T>[];\n },\n\n listeners(event) {\n const set = get(event);\n // Return unwrapped handlers for better debugging\n return Array.from(set).map(handler => {\n const wrapped = handler as WrappedHandler<unknown>;\n return (wrapped.__original || handler) as EventHandler<T[typeof event]>;\n });\n },\n\n wildcardListeners() {\n return Array.from(wildcards);\n },\n\n hasListener(event, handler) {\n const set = get(event);\n\n // Check direct match\n if (set.has(handler as EventHandler<unknown>)) {\n return true;\n }\n\n // Check wrapped handlers (once)\n for (const wrapped of set) {\n const w = wrapped as WrappedHandler<unknown>;\n if (w.__original === handler) {\n return true;\n }\n }\n\n return false;\n },\n };\n\n return emitter;\n}\n"],"mappings":"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","names":["CONFIG_FILENAME","cachedConfig","cachedProjectRoot","findProjectRoot","proc","req","cwd","path","fs","dir","getProjectRoot","loadConfigFileSync","projectRoot","configPath","cwdPath","content","err","deepMerge","base","override","result","key","mergeConfig","options","fileConfig","clearConfigCache","isNode","isBrowser","formatTimestamp","format","timezone","date","parseSize","size","match","value","unit","multipliers","Logger","options","req","projectRoot","getProjectRoot","resolvedPath","dir","err","entry","timestamp","obj","parts","content","line","rotationNum","event","payload","formatted","error","_handler","message","details","defaultMaxListenersHandler","_event","_count","_max","createEmitochondria","options","config","mergeConfig","logger","Logger","handlers","wildcards","maxListeners","onMaxListenersExceeded","errorHandler","warned","get","handleError","error","event","handler","safeCall","payload","result","err","checkMaxListeners","count","message","emitter","set","wrapped","wrapper","data","h","promises","n","k"]}
1
+ {"version":3,"sources":["../src/config.ts","../src/logger.ts","../src/emitter.ts"],"sourcesContent":["import { EmitochondriaConfig, EmitochondriaOptions, EventMap } from './types.js';\n\n// ============================================================\n// CONFIG FILE LOADING\n// ============================================================\n\nconst CONFIG_FILENAME = 'emitochondria.config.json';\n\n// Environment detection\nconst isNode = typeof (globalThis as any).process !== 'undefined'\n && (globalThis as any).process?.versions?.node != null;\n\n// Get require function - works in both ESM and CJS\nfunction getRequireFunction(): ((id: string) => any) | null {\n if (!isNode) return null;\n\n // CJS: globalThis.require is available (bundlers like tsup inject this)\n if (typeof (globalThis as any).require === 'function') {\n return (globalThis as any).require;\n }\n\n // Try Function constructor to get require in CJS context\n try {\n const req = Function('return typeof require !== \"undefined\" ? require : null')();\n if (req) return req;\n } catch {\n // Ignore\n }\n\n // ESM: use createRequire\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { createRequire } = Function('return require(\"node:module\")')();\n // import.meta.url might be empty in CJS, use a fallback\n const url = typeof import.meta?.url === 'string' && import.meta.url\n ? import.meta.url\n : 'file://' + (globalThis as any).process?.cwd?.() + '/';\n return createRequire(url);\n } catch {\n return null;\n }\n}\n\nconst nodeRequire = getRequireFunction();\n\nlet cachedConfig: EmitochondriaConfig | null = null;\nlet cachedProjectRoot: string | null = null;\n\n/**\n * Find project root by walking up directories looking for package.json.\n */\nfunction findProjectRoot(): string {\n if (cachedProjectRoot !== null) return cachedProjectRoot;\n\n const proc = (globalThis as any).process;\n if (typeof proc === 'undefined' || !proc?.versions?.node) {\n cachedProjectRoot = '';\n return '';\n }\n\n try {\n if (!nodeRequire) {\n const cwd: string = proc.cwd();\n cachedProjectRoot = cwd;\n return cwd;\n }\n\n const path = nodeRequire('path');\n const fs = nodeRequire('fs');\n\n let dir: string = proc.cwd();\n\n // Walk up looking for package.json\n while (dir !== path.dirname(dir)) {\n if (fs.existsSync(path.join(dir, 'package.json'))) {\n cachedProjectRoot = dir;\n return dir;\n }\n dir = path.dirname(dir);\n }\n\n // Fallback to cwd if no package.json found\n const cwd: string = proc.cwd();\n cachedProjectRoot = cwd;\n return cwd;\n } catch {\n const cwd: string = proc.cwd();\n cachedProjectRoot = cwd;\n return cwd;\n }\n}\n\n/**\n * Get the cached project root (for use by logger).\n */\nexport function getProjectRoot(): string {\n return findProjectRoot();\n}\n\n/**\n * Synchronous version for initial load.\n * Falls back to empty config if loading fails.\n */\nfunction loadConfigFileSync(): EmitochondriaConfig {\n if (cachedConfig !== null) return cachedConfig;\n\n const proc = (globalThis as any).process;\n if (typeof proc === 'undefined' || !proc?.versions?.node) {\n cachedConfig = {};\n return cachedConfig;\n }\n\n try {\n if (!nodeRequire) {\n cachedConfig = {};\n return cachedConfig;\n }\n\n const fs = nodeRequire('fs');\n const path = nodeRequire('path');\n\n // Look for config in project root first\n const projectRoot = findProjectRoot();\n const configPath = path.join(projectRoot, CONFIG_FILENAME);\n\n if (!fs.existsSync(configPath)) {\n // Also try cwd as fallback\n const cwdPath = path.join(proc.cwd(), CONFIG_FILENAME);\n if (fs.existsSync(cwdPath)) {\n const content = fs.readFileSync(cwdPath, 'utf-8');\n cachedConfig = JSON.parse(content) as EmitochondriaConfig;\n\n if (proc.env?.NODE_ENV !== 'production') {\n console.log(`[Emitochondria] Config loaded from: ${cwdPath}`);\n }\n\n return cachedConfig;\n }\n\n cachedConfig = {};\n return cachedConfig;\n }\n\n const content = fs.readFileSync(configPath, 'utf-8');\n cachedConfig = JSON.parse(content) as EmitochondriaConfig;\n\n if (proc.env?.NODE_ENV !== 'production') {\n console.log(`[Emitochondria] Config loaded from: ${configPath}`);\n }\n\n return cachedConfig;\n } catch (err: any) {\n if (err?.code !== 'ENOENT') {\n console.warn(`[Emitochondria] Failed to load config: ${err?.message}`);\n }\n cachedConfig = {};\n return cachedConfig;\n }\n}\n\n// ============================================================\n// CONFIG MERGING\n// ============================================================\n\n/**\n * Deep merge two objects, with second taking precedence.\n */\nfunction deepMerge<T extends Record<string, any>>(base: T, override: Partial<T>): T {\n const result = { ...base };\n\n for (const key in override) {\n if (override[key] !== undefined) {\n if (\n typeof override[key] === 'object' &&\n override[key] !== null &&\n !Array.isArray(override[key]) &&\n typeof result[key] === 'object' &&\n result[key] !== null\n ) {\n result[key] = deepMerge(result[key], override[key]);\n } else {\n result[key] = override[key] as T[typeof key];\n }\n }\n }\n\n return result;\n}\n\n/**\n * Merge file config with options.\n * Options take precedence over file config.\n */\nexport function mergeConfig<T extends EventMap>(\n options: EmitochondriaOptions<T> = {}\n): EmitochondriaOptions<T> {\n const fileConfig = loadConfigFileSync();\n // Type assertion is safe here because we control both inputs\n const merged = deepMerge(fileConfig as any, options as any);\n return merged as EmitochondriaOptions<T>;\n}\n\n/**\n * Clear cached config (useful for testing).\n */\nexport function clearConfigCache(): void {\n cachedConfig = null;\n cachedProjectRoot = null;\n}\n","import { LoggingOptions, TimestampFormat, Timezone } from './types.js';\nimport { getProjectRoot } from './config.js';\n\n// ============================================================\n// ENVIRONMENT DETECTION\n// ============================================================\n\nconst isNode = typeof (globalThis as any).process !== 'undefined'\n && (globalThis as any).process?.versions?.node != null;\n\nconst isBrowser = typeof (globalThis as any).window !== 'undefined';\n\n// Get require function - works in both ESM and CJS\nfunction getRequireFunction(): ((id: string) => any) | null {\n if (!isNode) return null;\n\n // CJS: globalThis.require is available (bundlers like tsup inject this)\n if (typeof (globalThis as any).require === 'function') {\n return (globalThis as any).require;\n }\n\n // Try Function constructor to get require in CJS context\n try {\n const req = Function('return typeof require !== \"undefined\" ? require : null')();\n if (req) return req;\n } catch {\n // Ignore\n }\n\n // ESM: use createRequire\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { createRequire } = Function('return require(\"node:module\")')();\n // import.meta.url might be empty in CJS, use a fallback\n const url = typeof import.meta?.url === 'string' && import.meta.url\n ? import.meta.url\n : 'file://' + (globalThis as any).process?.cwd?.() + '/';\n return createRequire(url);\n } catch {\n return null;\n }\n}\n\nconst nodeRequire = getRequireFunction();\n\n// ============================================================\n// TIMESTAMP FORMATTING\n// ============================================================\n\nfunction formatTimestamp(format: TimestampFormat, timezone: Timezone): string {\n const date = new Date();\n\n switch (format) {\n case 'unix':\n return String(date.getTime());\n\n case 'human':\n return date.toLocaleString('en-US', {\n timeZone: timezone === 'utc' ? 'UTC' : undefined,\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n hour12: true,\n });\n\n case 'iso':\n default:\n return timezone === 'utc'\n ? date.toISOString()\n : new Date(date.getTime() - date.getTimezoneOffset() * 60000)\n .toISOString()\n .slice(0, -1); // Remove 'Z' for local\n }\n}\n\n// ============================================================\n// SIZE PARSING\n// ============================================================\n\nfunction parseSize(size: string): number {\n const match = size.match(/^(\\d+(?:\\.\\d+)?)\\s*(KB|MB|GB)$/i);\n if (!match) return 10 * 1024 * 1024; // Default 10MB\n\n const value = parseFloat(match[1]!);\n const unit = match[2]!.toUpperCase();\n\n const multipliers: Record<string, number> = {\n 'KB': 1024,\n 'MB': 1024 * 1024,\n 'GB': 1024 * 1024 * 1024,\n };\n\n return value * (multipliers[unit] ?? 10 * 1024 * 1024);\n}\n\n// ============================================================\n// LOG ENTRY TYPES\n// ============================================================\n\nexport type LogLevel = 'info' | 'warn' | 'error';\n\nexport interface LogEntry {\n level: LogLevel;\n type: 'event' | 'error' | 'warning';\n event?: string;\n message: string;\n payload?: unknown;\n error?: unknown;\n}\n\n// ============================================================\n// LOGGER CLASS\n// ============================================================\n\nexport class Logger {\n private options: Required<LoggingOptions>;\n private maxSizeBytes: number;\n private browserWarned = false;\n private fs: any = null;\n private path: any = null;\n\n constructor(options: LoggingOptions = {}) {\n this.options = {\n timestamps: options.timestamps ?? false,\n timestampFormat: options.timestampFormat ?? 'iso',\n timezone: options.timezone ?? 'utc',\n persist: options.persist ?? false,\n path: options.path ?? './logs/emitochondria.log',\n format: options.format ?? 'text',\n maxSize: options.maxSize ?? '10MB',\n logEvents: options.logEvents ?? false,\n logErrors: options.logErrors ?? true,\n logWarnings: options.logWarnings ?? true,\n };\n\n this.maxSizeBytes = parseSize(this.options.maxSize);\n\n if (this.options.persist) {\n this.initFileLogging();\n }\n }\n\n private initFileLogging(): void {\n if (isBrowser) {\n if (!this.browserWarned) {\n console.warn(\n '[Emitochondria] File logging is not available in browser environments. ' +\n 'Logs will only be written to console.'\n );\n this.browserWarned = true;\n }\n return;\n }\n\n if (!isNode) return;\n\n try {\n // Require fs and path synchronously using ESM-compatible require\n if (nodeRequire) {\n this.fs = nodeRequire('fs');\n this.path = nodeRequire('path');\n\n // Resolve path relative to project root (where package.json is)\n const projectRoot = getProjectRoot();\n const resolvedPath = this.path.isAbsolute(this.options.path)\n ? this.options.path\n : this.path.join(projectRoot, this.options.path);\n\n // Update options with resolved path\n this.options.path = resolvedPath;\n\n // Create directory if needed\n const dir = this.path.dirname(resolvedPath);\n if (!this.fs.existsSync(dir)) {\n this.fs.mkdirSync(dir, { recursive: true });\n }\n\n // Log where logs are being written (helpful for debugging)\n const proc = (globalThis as any).process;\n if (proc?.env?.NODE_ENV !== 'production') {\n console.log(`[Emitochondria] Logs will be written to: ${resolvedPath}`);\n }\n }\n } catch (err) {\n console.error('[Emitochondria] Failed to initialize file logging:', err);\n }\n }\n\n private getTimestamp(): string | undefined {\n if (!this.options.timestamps) return undefined;\n return formatTimestamp(this.options.timestampFormat, this.options.timezone);\n }\n\n private formatEntry(entry: LogEntry): string {\n const timestamp = this.getTimestamp();\n\n if (this.options.format === 'json') {\n const obj: any = {\n level: entry.level,\n type: entry.type,\n message: entry.message,\n };\n if (timestamp) obj.timestamp = timestamp;\n if (entry.event) obj.event = entry.event;\n if (entry.payload !== undefined) obj.payload = entry.payload;\n if (entry.error) obj.error = String(entry.error);\n return JSON.stringify(obj);\n }\n\n // Text format\n const parts: string[] = [];\n if (timestamp) parts.push(`[${timestamp}]`);\n parts.push(`[${entry.level.toUpperCase()}]`);\n if (entry.event) parts.push(`[${entry.event}]`);\n parts.push(entry.message);\n if (entry.payload !== undefined) {\n parts.push(`| Payload: ${JSON.stringify(entry.payload)}`);\n }\n if (entry.error) {\n parts.push(`| Error: ${entry.error}`);\n }\n\n return parts.join(' ');\n }\n\n private writeToFile(content: string): void {\n if (!this.fs || !this.path || !isNode) return;\n\n try {\n const line = content + '\\n';\n\n // Check if rotation needed\n if (this.fs.existsSync(this.options.path)) {\n const stats = this.fs.statSync(this.options.path);\n if (stats.size >= this.maxSizeBytes) {\n this.rotateLog();\n }\n }\n\n // Sync write — simple, ordered, reliable\n this.fs.appendFileSync(this.options.path, line, 'utf8');\n } catch (err) {\n console.error('[Emitochondria] Failed to write to log file:', err);\n }\n }\n\n private rotateLog(): void {\n if (!this.fs || !this.path) return;\n\n try {\n // Find next rotation number\n let rotationNum = 1;\n while (this.fs.existsSync(`${this.options.path}.${rotationNum}`)) {\n rotationNum++;\n }\n\n // Rename current file\n this.fs.renameSync(this.options.path, `${this.options.path}.${rotationNum}`);\n } catch (err) {\n console.error('[Emitochondria] Failed to rotate log file:', err);\n }\n }\n\n // ============================================================\n // PUBLIC LOGGING METHODS\n // ============================================================\n\n logEvent(event: string, payload: unknown): void {\n if (!this.options.logEvents) return;\n\n const entry: LogEntry = {\n level: 'info',\n type: 'event',\n event,\n message: 'Event emitted',\n payload,\n };\n\n const formatted = this.formatEntry(entry);\n console.log(formatted);\n\n if (this.options.persist) {\n this.writeToFile(formatted);\n }\n }\n\n logError(event: string, error: unknown, _handler?: unknown): void {\n if (!this.options.logErrors) return;\n\n const entry: LogEntry = {\n level: 'error',\n type: 'error',\n event,\n message: 'Handler threw an error',\n error,\n };\n\n const formatted = this.formatEntry(entry);\n console.error(formatted);\n\n if (this.options.persist) {\n this.writeToFile(formatted);\n }\n }\n\n logWarning(event: string, message: string, details?: Record<string, unknown>): void {\n if (!this.options.logWarnings) return;\n\n const entry: LogEntry = {\n level: 'warn',\n type: 'warning',\n event,\n message,\n payload: details,\n };\n\n const formatted = this.formatEntry(entry);\n console.warn(formatted);\n\n if (this.options.persist) {\n this.writeToFile(formatted);\n }\n }\n}\n","import {\n EventMap,\n EventKey,\n EventHandler,\n WildcardHandler,\n ErrorHandler,\n EmitochondriaOptions,\n Emitochondria,\n} from './types.js';\nimport { Logger } from './logger.js';\nimport { mergeConfig } from './config.js';\n\n// ============================================================\n// DEFAULT HANDLERS\n// ============================================================\n\nconst defaultMaxListenersHandler = <T extends EventMap>(\n _event: EventKey<T>,\n _count: number,\n _max: number\n): void => {\n // Handled by logger\n};\n\n// ============================================================\n// FACTORY FUNCTION\n// ============================================================\n\nexport function createEmitochondria<T extends EventMap>(\n options: EmitochondriaOptions<T> = {}\n): Emitochondria<T> {\n // Merge file config with options\n const config = mergeConfig(options);\n\n // Initialize logger\n const logger = new Logger(config.logging);\n\n // Handler storage\n const handlers: Map<string, Set<EventHandler<unknown>>> = new Map();\n const wildcards: Set<WildcardHandler<T>> = new Set();\n\n // Configuration state\n let maxListeners = config.maxListeners ?? 10;\n let onMaxListenersExceeded = options.onMaxListenersExceeded ?? defaultMaxListenersHandler;\n let errorHandler: ErrorHandler<T> | 'throw' | 'default' = config.onError ?? 'default';\n\n // Memory leak tracking\n const warned = new Set<string>();\n\n // ============================================================\n // HELPER FUNCTIONS\n // ============================================================\n\n // Track original handlers for once() wrappers\n type WrappedHandler<T> = EventHandler<T> & { __original?: EventHandler<T> };\n\n const get = (e: string) => handlers.get(e) ?? handlers.set(e, new Set()).get(e)!;\n\n const handleError = <K extends EventKey<T>>(\n error: unknown,\n event: K,\n handler: EventHandler<unknown>\n ): void => {\n logger.logError(event, error, handler);\n\n if (errorHandler === 'throw') {\n throw error;\n } else if (typeof errorHandler === 'function') {\n errorHandler(error, event, handler);\n }\n // 'default' = just log (already done above)\n };\n\n const safeCall = <K extends EventKey<T>>(\n handler: EventHandler<unknown>,\n event: K,\n payload: unknown\n ): void | Promise<void> => {\n try {\n const result = handler(payload);\n if (result instanceof Promise) {\n return result.catch((err) => handleError(err, event, handler));\n }\n } catch (err) {\n handleError(err, event, handler);\n }\n };\n\n const checkMaxListeners = <K extends EventKey<T>>(event: K, count: number): void => {\n if (maxListeners > 0 && count > maxListeners && !warned.has(event)) {\n warned.add(event);\n\n const message = `Possible memory leak: ${count} listeners (max: ${maxListeners})`;\n logger.logWarning(event, message, { count, max: maxListeners });\n\n onMaxListenersExceeded(event, count, maxListeners);\n }\n };\n\n // ============================================================\n // EMITTER IMPLEMENTATION\n // ============================================================\n\n const emitter: Emitochondria<T> = {\n on(event, handler) {\n const set = get(event);\n set.add(handler as EventHandler<unknown>);\n checkMaxListeners(event, set.size);\n return () => emitter.off(event, handler);\n },\n\n off(event, handler) {\n const set = get(event);\n\n // Try direct removal first\n if (set.delete(handler as EventHandler<unknown>)) {\n if (set.size <= maxListeners) {\n warned.delete(event);\n }\n return;\n }\n\n // Search for wrapped handler (for once handlers)\n for (const wrapped of set) {\n const w = wrapped as WrappedHandler<unknown>;\n if (w.__original === handler) {\n set.delete(wrapped);\n if (set.size <= maxListeners) {\n warned.delete(event);\n }\n break;\n }\n }\n },\n\n once(event, handler) {\n const wrapper = ((payload: T[typeof event]) => {\n emitter.off(event, wrapper as EventHandler<T[typeof event]>);\n return handler(payload);\n }) as WrappedHandler<T[typeof event]>;\n\n // Store original reference for manual removal\n wrapper.__original = handler;\n\n return emitter.on(event, wrapper);\n },\n\n emit(event, ...payload) {\n const data = payload[0];\n\n logger.logEvent(event, data);\n\n get(event).forEach((h) => safeCall(h, event, data));\n wildcards.forEach((h) => {\n try {\n h(event, data as T[typeof event]);\n } catch (err) {\n handleError(err, event, h as unknown as EventHandler<unknown>);\n }\n });\n },\n\n async emitAsync(event, ...payload) {\n const data = payload[0];\n const promises: Promise<void>[] = [];\n\n logger.logEvent(event, data);\n\n get(event).forEach((h) => {\n const result = safeCall(h, event, data);\n if (result instanceof Promise) promises.push(result);\n });\n\n wildcards.forEach((h) => {\n try {\n const result = h(event, data as T[typeof event]);\n if (result instanceof Promise) {\n promises.push(result.catch((err) =>\n handleError(err, event, h as unknown as EventHandler<unknown>)\n ));\n }\n } catch (err) {\n handleError(err, event, h as unknown as EventHandler<unknown>);\n }\n });\n\n await Promise.all(promises);\n },\n\n onAny(handler) {\n wildcards.add(handler);\n return () => emitter.offAny(handler);\n },\n\n offAny(handler) {\n wildcards.delete(handler);\n },\n\n clear(event?) {\n if (event) {\n handlers.delete(event);\n warned.delete(event);\n } else {\n handlers.clear();\n wildcards.clear();\n warned.clear();\n }\n },\n\n listenerCount(event) {\n return get(event).size;\n },\n\n setErrorHandler(handler) {\n errorHandler = handler;\n },\n\n setMaxListeners(n) {\n maxListeners = n;\n if (n === 0) warned.clear();\n },\n\n getMaxListeners() {\n return maxListeners;\n },\n\n eventNames() {\n return Array.from(handlers.keys()).filter(\n (k) => handlers.get(k)!.size > 0\n ) as EventKey<T>[];\n },\n\n listeners(event) {\n const set = get(event);\n // Return unwrapped handlers for better debugging\n return Array.from(set).map(handler => {\n const wrapped = handler as WrappedHandler<unknown>;\n return (wrapped.__original || handler) as EventHandler<T[typeof event]>;\n });\n },\n\n wildcardListeners() {\n return Array.from(wildcards);\n },\n\n hasListener(event, handler) {\n const set = get(event);\n\n // Check direct match\n if (set.has(handler as EventHandler<unknown>)) {\n return true;\n }\n\n // Check wrapped handlers (once)\n for (const wrapped of set) {\n const w = wrapped as WrappedHandler<unknown>;\n if (w.__original === handler) {\n return true;\n }\n }\n\n return false;\n },\n };\n\n return emitter;\n}\n"],"mappings":"AAMA,IAAMA,EAAkB,4BAGlBC,EAAS,OAAQ,WAAmB,QAAY,KAChD,WAAmB,SAAS,UAAU,MAAQ,KAGpD,SAASC,GAAmD,CAC1D,GAAI,CAACD,EAAQ,OAAO,KAGpB,GAAI,OAAQ,WAAmB,SAAY,WACzC,OAAQ,WAAmB,QAI7B,GAAI,CACF,IAAME,EAAM,SAAS,wDAAwD,EAAE,EAC/E,GAAIA,EAAK,OAAOA,CAClB,MAAQ,CAER,CAGA,GAAI,CAEF,GAAM,CAAE,cAAAC,CAAc,EAAI,SAAS,+BAA+B,EAAE,EAE9DC,EAAM,OAAO,aAAa,KAAQ,UAAY,YAAY,IAC5D,YAAY,IACZ,UAAa,WAAmB,SAAS,MAAM,EAAI,IACvD,OAAOD,EAAcC,CAAG,CAC1B,MAAQ,CACN,OAAO,IACT,CACF,CAEA,IAAMC,EAAcJ,EAAmB,EAEnCK,EAA2C,KAC3CC,EAAmC,KAKvC,SAASC,GAA0B,CACjC,GAAID,IAAsB,KAAM,OAAOA,EAEvC,IAAME,EAAQ,WAAmB,QACjC,GAAI,OAAOA,EAAS,KAAe,CAACA,GAAM,UAAU,KAClD,OAAAF,EAAoB,GACb,GAGT,GAAI,CACF,GAAI,CAACF,EAAa,CAChB,IAAMK,EAAcD,EAAK,IAAI,EAC7B,OAAAF,EAAoBG,EACbA,CACT,CAEA,IAAMC,EAAON,EAAY,MAAM,EACzBO,EAAKP,EAAY,IAAI,EAEvBQ,EAAcJ,EAAK,IAAI,EAG3B,KAAOI,IAAQF,EAAK,QAAQE,CAAG,GAAG,CAChC,GAAID,EAAG,WAAWD,EAAK,KAAKE,EAAK,cAAc,CAAC,EAC9C,OAAAN,EAAoBM,EACbA,EAETA,EAAMF,EAAK,QAAQE,CAAG,CACxB,CAGA,IAAMH,EAAcD,EAAK,IAAI,EAC7B,OAAAF,EAAoBG,EACbA,CACT,MAAQ,CACN,IAAMA,EAAcD,EAAK,IAAI,EAC7B,OAAAF,EAAoBG,EACbA,CACT,CACF,CAKO,SAASI,GAAyB,CACvC,OAAON,EAAgB,CACzB,CAMA,SAASO,GAA0C,CACjD,GAAIT,IAAiB,KAAM,OAAOA,EAElC,IAAMG,EAAQ,WAAmB,QACjC,GAAI,OAAOA,EAAS,KAAe,CAACA,GAAM,UAAU,KAClD,OAAAH,EAAe,CAAC,EACTA,EAGT,GAAI,CACF,GAAI,CAACD,EACH,OAAAC,EAAe,CAAC,EACTA,EAGT,IAAMM,EAAKP,EAAY,IAAI,EACrBM,EAAON,EAAY,MAAM,EAGzBW,EAAcR,EAAgB,EAC9BS,EAAaN,EAAK,KAAKK,EAAajB,CAAe,EAEzD,GAAI,CAACa,EAAG,WAAWK,CAAU,EAAG,CAE9B,IAAMC,EAAUP,EAAK,KAAKF,EAAK,IAAI,EAAGV,CAAe,EACrD,GAAIa,EAAG,WAAWM,CAAO,EAAG,CAC1B,IAAMC,EAAUP,EAAG,aAAaM,EAAS,OAAO,EAChD,OAAAZ,EAAe,KAAK,MAAMa,CAAO,EAE7BV,EAAK,KAAK,WAAa,cACzB,QAAQ,IAAI,uCAAuCS,CAAO,EAAE,EAGvDZ,CACT,CAEA,OAAAA,EAAe,CAAC,EACTA,CACT,CAEA,IAAMa,EAAUP,EAAG,aAAaK,EAAY,OAAO,EACnD,OAAAX,EAAe,KAAK,MAAMa,CAAO,EAE7BV,EAAK,KAAK,WAAa,cACzB,QAAQ,IAAI,uCAAuCQ,CAAU,EAAE,EAG1DX,CACT,OAASc,EAAU,CACjB,OAAIA,GAAK,OAAS,UAChB,QAAQ,KAAK,0CAA0CA,GAAK,OAAO,EAAE,EAEvEd,EAAe,CAAC,EACTA,CACT,CACF,CASA,SAASe,EAAyCC,EAASC,EAAyB,CAClF,IAAMC,EAAS,CAAE,GAAGF,CAAK,EAEzB,QAAWG,KAAOF,EACZA,EAASE,CAAG,IAAM,SAElB,OAAOF,EAASE,CAAG,GAAM,UACzBF,EAASE,CAAG,IAAM,MAClB,CAAC,MAAM,QAAQF,EAASE,CAAG,CAAC,GAC5B,OAAOD,EAAOC,CAAG,GAAM,UACvBD,EAAOC,CAAG,IAAM,KAEhBD,EAAOC,CAAG,EAAIJ,EAAUG,EAAOC,CAAG,EAAGF,EAASE,CAAG,CAAC,EAElDD,EAAOC,CAAG,EAAIF,EAASE,CAAG,GAKhC,OAAOD,CACT,CAMO,SAASE,EACdC,EAAmC,CAAC,EACX,CACzB,IAAMC,EAAab,EAAmB,EAGtC,OADeM,EAAUO,EAAmBD,CAAc,CAE5D,CAKO,SAASE,GAAyB,CACvCvB,EAAe,KACfC,EAAoB,IACtB,CCzMA,IAAMuB,EAAS,OAAQ,WAAmB,QAAY,KAChD,WAAmB,SAAS,UAAU,MAAQ,KAE9CC,EAAY,OAAQ,WAAmB,OAAW,IAGxD,SAASC,GAAmD,CAC1D,GAAI,CAACF,EAAQ,OAAO,KAGpB,GAAI,OAAQ,WAAmB,SAAY,WACzC,OAAQ,WAAmB,QAI7B,GAAI,CACF,IAAMG,EAAM,SAAS,wDAAwD,EAAE,EAC/E,GAAIA,EAAK,OAAOA,CAClB,MAAQ,CAER,CAGA,GAAI,CAEF,GAAM,CAAE,cAAAC,CAAc,EAAI,SAAS,+BAA+B,EAAE,EAE9DC,EAAM,OAAO,aAAa,KAAQ,UAAY,YAAY,IAC5D,YAAY,IACZ,UAAa,WAAmB,SAAS,MAAM,EAAI,IACvD,OAAOD,EAAcC,CAAG,CAC1B,MAAQ,CACN,OAAO,IACT,CACF,CAEA,IAAMC,EAAcJ,EAAmB,EAMvC,SAASK,EAAgBC,EAAyBC,EAA4B,CAC5E,IAAMC,EAAO,IAAI,KAEjB,OAAQF,EAAQ,CACd,IAAK,OACH,OAAO,OAAOE,EAAK,QAAQ,CAAC,EAE9B,IAAK,QACH,OAAOA,EAAK,eAAe,QAAS,CAClC,SAAUD,IAAa,MAAQ,MAAQ,OACvC,MAAO,QACP,IAAK,UACL,KAAM,UACN,OAAQ,UACR,OAAQ,UACR,OAAQ,EACV,CAAC,EAGH,QACE,OAAOA,IAAa,MAChBC,EAAK,YAAY,EACjB,IAAI,KAAKA,EAAK,QAAQ,EAAIA,EAAK,kBAAkB,EAAI,GAAK,EACvD,YAAY,EACZ,MAAM,EAAG,EAAE,CACtB,CACF,CAMA,SAASC,EAAUC,EAAsB,CACvC,IAAMC,EAAQD,EAAK,MAAM,iCAAiC,EAC1D,GAAI,CAACC,EAAO,MAAO,IAAK,KAAO,KAE/B,IAAMC,EAAQ,WAAWD,EAAM,CAAC,CAAE,EAC5BE,EAAOF,EAAM,CAAC,EAAG,YAAY,EAE7BG,EAAsC,CAC1C,GAAM,KACN,GAAM,KAAO,KACb,GAAM,KAAO,KAAO,IACtB,EAEA,OAAOF,GAASE,EAAYD,CAAI,GAAK,GAAK,KAAO,KACnD,CAqBO,IAAME,EAAN,KAAa,CACV,QACA,aACA,cAAgB,GAChB,GAAU,KACV,KAAY,KAEpB,YAAYC,EAA0B,CAAC,EAAG,CACxC,KAAK,QAAU,CACb,WAAYA,EAAQ,YAAc,GAClC,gBAAiBA,EAAQ,iBAAmB,MAC5C,SAAUA,EAAQ,UAAY,MAC9B,QAASA,EAAQ,SAAW,GAC5B,KAAMA,EAAQ,MAAQ,2BACtB,OAAQA,EAAQ,QAAU,OAC1B,QAASA,EAAQ,SAAW,OAC5B,UAAWA,EAAQ,WAAa,GAChC,UAAWA,EAAQ,WAAa,GAChC,YAAaA,EAAQ,aAAe,EACtC,EAEA,KAAK,aAAeP,EAAU,KAAK,QAAQ,OAAO,EAE9C,KAAK,QAAQ,SACf,KAAK,gBAAgB,CAEzB,CAEQ,iBAAwB,CAC9B,GAAIV,EAAW,CACR,KAAK,gBACR,QAAQ,KACN,8GAEF,EACA,KAAK,cAAgB,IAEvB,MACF,CAEA,GAAKD,EAEL,GAAI,CAEF,GAAIM,EAAa,CACf,KAAK,GAAKA,EAAY,IAAI,EAC1B,KAAK,KAAOA,EAAY,MAAM,EAG9B,IAAMa,EAAcC,EAAe,EAC7BC,EAAe,KAAK,KAAK,WAAW,KAAK,QAAQ,IAAI,EACvD,KAAK,QAAQ,KACb,KAAK,KAAK,KAAKF,EAAa,KAAK,QAAQ,IAAI,EAGjD,KAAK,QAAQ,KAAOE,EAGpB,IAAMC,EAAM,KAAK,KAAK,QAAQD,CAAY,EACrC,KAAK,GAAG,WAAWC,CAAG,GACzB,KAAK,GAAG,UAAUA,EAAK,CAAE,UAAW,EAAK,CAAC,EAI9B,WAAmB,SACvB,KAAK,WAAa,cAC1B,QAAQ,IAAI,4CAA4CD,CAAY,EAAE,CAE1E,CACF,OAASE,EAAK,CACZ,QAAQ,MAAM,qDAAsDA,CAAG,CACzE,CACF,CAEQ,cAAmC,CACzC,GAAK,KAAK,QAAQ,WAClB,OAAOhB,EAAgB,KAAK,QAAQ,gBAAiB,KAAK,QAAQ,QAAQ,CAC5E,CAEQ,YAAYiB,EAAyB,CAC3C,IAAMC,EAAY,KAAK,aAAa,EAEpC,GAAI,KAAK,QAAQ,SAAW,OAAQ,CAClC,IAAMC,EAAW,CACf,MAAOF,EAAM,MACb,KAAMA,EAAM,KACZ,QAASA,EAAM,OACjB,EACA,OAAIC,IAAWC,EAAI,UAAYD,GAC3BD,EAAM,QAAOE,EAAI,MAAQF,EAAM,OAC/BA,EAAM,UAAY,SAAWE,EAAI,QAAUF,EAAM,SACjDA,EAAM,QAAOE,EAAI,MAAQ,OAAOF,EAAM,KAAK,GACxC,KAAK,UAAUE,CAAG,CAC3B,CAGA,IAAMC,EAAkB,CAAC,EACzB,OAAIF,GAAWE,EAAM,KAAK,IAAIF,CAAS,GAAG,EAC1CE,EAAM,KAAK,IAAIH,EAAM,MAAM,YAAY,CAAC,GAAG,EACvCA,EAAM,OAAOG,EAAM,KAAK,IAAIH,EAAM,KAAK,GAAG,EAC9CG,EAAM,KAAKH,EAAM,OAAO,EACpBA,EAAM,UAAY,QACpBG,EAAM,KAAK,cAAc,KAAK,UAAUH,EAAM,OAAO,CAAC,EAAE,EAEtDA,EAAM,OACRG,EAAM,KAAK,YAAYH,EAAM,KAAK,EAAE,EAG/BG,EAAM,KAAK,GAAG,CACvB,CAEQ,YAAYC,EAAuB,CACzC,GAAI,GAAC,KAAK,IAAM,CAAC,KAAK,MAAQ,CAAC5B,GAE/B,GAAI,CACF,IAAM6B,EAAOD,EAAU;AAAA,EAGnB,KAAK,GAAG,WAAW,KAAK,QAAQ,IAAI,GACxB,KAAK,GAAG,SAAS,KAAK,QAAQ,IAAI,EACtC,MAAQ,KAAK,cACrB,KAAK,UAAU,EAKnB,KAAK,GAAG,eAAe,KAAK,QAAQ,KAAMC,EAAM,MAAM,CACxD,OAASN,EAAK,CACZ,QAAQ,MAAM,+CAAgDA,CAAG,CACnE,CACF,CAEQ,WAAkB,CACxB,GAAI,GAAC,KAAK,IAAM,CAAC,KAAK,MAEtB,GAAI,CAEF,IAAIO,EAAc,EAClB,KAAO,KAAK,GAAG,WAAW,GAAG,KAAK,QAAQ,IAAI,IAAIA,CAAW,EAAE,GAC7DA,IAIF,KAAK,GAAG,WAAW,KAAK,QAAQ,KAAM,GAAG,KAAK,QAAQ,IAAI,IAAIA,CAAW,EAAE,CAC7E,OAASP,EAAK,CACZ,QAAQ,MAAM,6CAA8CA,CAAG,CACjE,CACF,CAMA,SAASQ,EAAeC,EAAwB,CAC9C,GAAI,CAAC,KAAK,QAAQ,UAAW,OAE7B,IAAMR,EAAkB,CACtB,MAAO,OACP,KAAM,QACN,MAAAO,EACA,QAAS,gBACT,QAAAC,CACF,EAEMC,EAAY,KAAK,YAAYT,CAAK,EACxC,QAAQ,IAAIS,CAAS,EAEjB,KAAK,QAAQ,SACf,KAAK,YAAYA,CAAS,CAE9B,CAEA,SAASF,EAAeG,EAAgBC,EAA0B,CAChE,GAAI,CAAC,KAAK,QAAQ,UAAW,OAE7B,IAAMX,EAAkB,CACtB,MAAO,QACP,KAAM,QACN,MAAAO,EACA,QAAS,yBACT,MAAAG,CACF,EAEMD,EAAY,KAAK,YAAYT,CAAK,EACxC,QAAQ,MAAMS,CAAS,EAEnB,KAAK,QAAQ,SACf,KAAK,YAAYA,CAAS,CAE9B,CAEA,WAAWF,EAAeK,EAAiBC,EAAyC,CAClF,GAAI,CAAC,KAAK,QAAQ,YAAa,OAE/B,IAAMb,EAAkB,CACtB,MAAO,OACP,KAAM,UACN,MAAAO,EACA,QAAAK,EACA,QAASC,CACX,EAEMJ,EAAY,KAAK,YAAYT,CAAK,EACxC,QAAQ,KAAKS,CAAS,EAElB,KAAK,QAAQ,SACf,KAAK,YAAYA,CAAS,CAE9B,CACF,ECrTA,IAAMK,EAA6B,CACjCC,EACAC,EACAC,IACS,CAEX,EAMO,SAASC,EACdC,EAAmC,CAAC,EAClB,CAElB,IAAMC,EAASC,EAAYF,CAAO,EAG5BG,EAAS,IAAIC,EAAOH,EAAO,OAAO,EAGlCI,EAAoD,IAAI,IACxDC,EAAqC,IAAI,IAG3CC,EAAeN,EAAO,cAAgB,GACtCO,EAAyBR,EAAQ,wBAA0BL,EAC3Dc,EAAsDR,EAAO,SAAW,UAGtES,EAAS,IAAI,IASbC,EAAO,GAAcN,EAAS,IAAI,CAAC,GAAKA,EAAS,IAAI,EAAG,IAAI,GAAK,EAAE,IAAI,CAAC,EAExEO,EAAc,CAClBC,EACAC,EACAC,IACS,CAGT,GAFAZ,EAAO,SAASW,EAAOD,EAAOE,CAAO,EAEjCN,IAAiB,QACnB,MAAMI,EACG,OAAOJ,GAAiB,YACjCA,EAAaI,EAAOC,EAAOC,CAAO,CAGtC,EAEMC,EAAW,CACfD,EACAD,EACAG,IACyB,CACzB,GAAI,CACF,IAAMC,EAASH,EAAQE,CAAO,EAC9B,GAAIC,aAAkB,QACpB,OAAOA,EAAO,MAAOC,GAAQP,EAAYO,EAAKL,EAAOC,CAAO,CAAC,CAEjE,OAASI,EAAK,CACZP,EAAYO,EAAKL,EAAOC,CAAO,CACjC,CACF,EAEMK,EAAoB,CAAwBN,EAAUO,IAAwB,CAClF,GAAId,EAAe,GAAKc,EAAQd,GAAgB,CAACG,EAAO,IAAII,CAAK,EAAG,CAClEJ,EAAO,IAAII,CAAK,EAEhB,IAAMQ,EAAU,yBAAyBD,CAAK,oBAAoBd,CAAY,IAC9EJ,EAAO,WAAWW,EAAOQ,EAAS,CAAE,MAAAD,EAAO,IAAKd,CAAa,CAAC,EAE9DC,EAAuBM,EAAOO,EAAOd,CAAY,CACnD,CACF,EAMMgB,EAA4B,CAChC,GAAGT,EAAOC,EAAS,CACjB,IAAMS,EAAMb,EAAIG,CAAK,EACrB,OAAAU,EAAI,IAAIT,CAAgC,EACxCK,EAAkBN,EAAOU,EAAI,IAAI,EAC1B,IAAMD,EAAQ,IAAIT,EAAOC,CAAO,CACzC,EAEA,IAAID,EAAOC,EAAS,CAClB,IAAMS,EAAMb,EAAIG,CAAK,EAGrB,GAAIU,EAAI,OAAOT,CAAgC,EAAG,CAC5CS,EAAI,MAAQjB,GACdG,EAAO,OAAOI,CAAK,EAErB,MACF,CAGA,QAAWW,KAAWD,EAEpB,GADUC,EACJ,aAAeV,EAAS,CAC5BS,EAAI,OAAOC,CAAO,EACdD,EAAI,MAAQjB,GACdG,EAAO,OAAOI,CAAK,EAErB,KACF,CAEJ,EAEA,KAAKA,EAAOC,EAAS,CACnB,IAAMW,GAAYT,IAChBM,EAAQ,IAAIT,EAAOY,CAAwC,EACpDX,EAAQE,CAAO,IAIxB,OAAAS,EAAQ,WAAaX,EAEdQ,EAAQ,GAAGT,EAAOY,CAAO,CAClC,EAEA,KAAKZ,KAAUG,EAAS,CACtB,IAAMU,EAAOV,EAAQ,CAAC,EAEtBd,EAAO,SAASW,EAAOa,CAAI,EAE3BhB,EAAIG,CAAK,EAAE,QAASc,GAAMZ,EAASY,EAAGd,EAAOa,CAAI,CAAC,EAClDrB,EAAU,QAASsB,GAAM,CACvB,GAAI,CACFA,EAAEd,EAAOa,CAAuB,CAClC,OAASR,EAAK,CACZP,EAAYO,EAAKL,EAAOc,CAAqC,CAC/D,CACF,CAAC,CACH,EAEA,MAAM,UAAUd,KAAUG,EAAS,CACjC,IAAMU,EAAOV,EAAQ,CAAC,EAChBY,EAA4B,CAAC,EAEnC1B,EAAO,SAASW,EAAOa,CAAI,EAE3BhB,EAAIG,CAAK,EAAE,QAASc,GAAM,CACxB,IAAMV,EAASF,EAASY,EAAGd,EAAOa,CAAI,EAClCT,aAAkB,SAASW,EAAS,KAAKX,CAAM,CACrD,CAAC,EAEDZ,EAAU,QAASsB,GAAM,CACvB,GAAI,CACF,IAAMV,EAASU,EAAEd,EAAOa,CAAuB,EAC3CT,aAAkB,SACpBW,EAAS,KAAKX,EAAO,MAAOC,GAC1BP,EAAYO,EAAKL,EAAOc,CAAqC,CAC/D,CAAC,CAEL,OAAST,EAAK,CACZP,EAAYO,EAAKL,EAAOc,CAAqC,CAC/D,CACF,CAAC,EAED,MAAM,QAAQ,IAAIC,CAAQ,CAC5B,EAEA,MAAMd,EAAS,CACb,OAAAT,EAAU,IAAIS,CAAO,EACd,IAAMQ,EAAQ,OAAOR,CAAO,CACrC,EAEA,OAAOA,EAAS,CACdT,EAAU,OAAOS,CAAO,CAC1B,EAEA,MAAMD,EAAQ,CACRA,GACFT,EAAS,OAAOS,CAAK,EACrBJ,EAAO,OAAOI,CAAK,IAEnBT,EAAS,MAAM,EACfC,EAAU,MAAM,EAChBI,EAAO,MAAM,EAEjB,EAEA,cAAcI,EAAO,CACnB,OAAOH,EAAIG,CAAK,EAAE,IACpB,EAEA,gBAAgBC,EAAS,CACvBN,EAAeM,CACjB,EAEA,gBAAgBe,EAAG,CACjBvB,EAAeuB,EACXA,IAAM,GAAGpB,EAAO,MAAM,CAC5B,EAEA,iBAAkB,CAChB,OAAOH,CACT,EAEA,YAAa,CACX,OAAO,MAAM,KAAKF,EAAS,KAAK,CAAC,EAAE,OAChC0B,GAAM1B,EAAS,IAAI0B,CAAC,EAAG,KAAO,CACjC,CACF,EAEA,UAAUjB,EAAO,CACf,IAAMU,EAAMb,EAAIG,CAAK,EAErB,OAAO,MAAM,KAAKU,CAAG,EAAE,IAAIT,GACTA,EACA,YAAcA,CAC/B,CACH,EAEA,mBAAoB,CAClB,OAAO,MAAM,KAAKT,CAAS,CAC7B,EAEA,YAAYQ,EAAOC,EAAS,CAC1B,IAAMS,EAAMb,EAAIG,CAAK,EAGrB,GAAIU,EAAI,IAAIT,CAAgC,EAC1C,MAAO,GAIT,QAAWU,KAAWD,EAEpB,GADUC,EACJ,aAAeV,EACnB,MAAO,GAIX,MAAO,EACT,CACF,EAEA,OAAOQ,CACT","names":["CONFIG_FILENAME","isNode","getRequireFunction","req","createRequire","url","nodeRequire","cachedConfig","cachedProjectRoot","findProjectRoot","proc","cwd","path","fs","dir","getProjectRoot","loadConfigFileSync","projectRoot","configPath","cwdPath","content","err","deepMerge","base","override","result","key","mergeConfig","options","fileConfig","clearConfigCache","isNode","isBrowser","getRequireFunction","req","createRequire","url","nodeRequire","formatTimestamp","format","timezone","date","parseSize","size","match","value","unit","multipliers","Logger","options","projectRoot","getProjectRoot","resolvedPath","dir","err","entry","timestamp","obj","parts","content","line","rotationNum","event","payload","formatted","error","_handler","message","details","defaultMaxListenersHandler","_event","_count","_max","createEmitochondria","options","config","mergeConfig","logger","Logger","handlers","wildcards","maxListeners","onMaxListenersExceeded","errorHandler","warned","get","handleError","error","event","handler","safeCall","payload","result","err","checkMaxListeners","count","message","emitter","set","wrapped","wrapper","data","h","promises","n","k"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emitochondria",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "type": "module",
5
5
  "description": "The powerhouse of your events — A tiny, fully-typed event emitter for TypeScript with built-in error handling and memory leak detection",
6
6
  "author": "Pablo Díaz A.K.A exudev",
@@ -27,9 +27,9 @@
27
27
  "type": "git",
28
28
  "url": "https://github.com/Exudev/emitochondria.git"
29
29
  },
30
- "main": "./dist/index.js",
30
+ "main": "./dist/index.cjs",
31
31
  "module": "./dist/index.mjs",
32
- "types": "./dist/index.d.ts",
32
+ "types": "./dist/index.d.cts",
33
33
  "exports": {
34
34
  ".": {
35
35
  "import": {
@@ -37,8 +37,8 @@
37
37
  "default": "./dist/index.mjs"
38
38
  },
39
39
  "require": {
40
- "types": "./dist/index.d.ts",
41
- "default": "./dist/index.js"
40
+ "types": "./dist/index.d.cts",
41
+ "default": "./dist/index.cjs"
42
42
  }
43
43
  },
44
44
  "./schema.json": "./schema.json"
package/dist/index.js DELETED
@@ -1,3 +0,0 @@
1
- "use strict";var T=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var P=(i,t)=>{for(var n in t)T(i,n,{get:t[n],enumerable:!0})},W=(i,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of _(t))!N.call(i,r)&&r!==n&&T(i,r,{get:()=>t[r],enumerable:!(o=j(t,r))||o.enumerable});return i};var $=i=>W(T({},"__esModule",{value:!0}),i);var D={};P(D,{clearConfigCache:()=>C,createEmitochondria:()=>x,default:()=>x});module.exports=$(D);var L="emitochondria.config.json",d=null,m=null;function k(){if(m!==null)return m;let i=globalThis.process;if(typeof i>"u"||!i?.versions?.node)return m="","";try{let t=globalThis.require;if(!t){let E=i.cwd();return m=E,E}let n=t("path"),o=t("fs"),r=i.cwd();for(;r!==n.dirname(r);){if(o.existsSync(n.join(r,"package.json")))return m=r,r;r=n.dirname(r)}let c=i.cwd();return m=c,c}catch{let t=i.cwd();return m=t,t}}function H(){return k()}function K(){if(d!==null)return d;let i=globalThis.process;if(typeof i>"u"||!i?.versions?.node)return d={},d;try{let t=globalThis.require;if(!t)return d={},d;let n=t("fs"),o=t("path"),r=k(),c=o.join(r,L);if(!n.existsSync(c)){let g=o.join(i.cwd(),L);if(n.existsSync(g)){let p=n.readFileSync(g,"utf-8");return d=JSON.parse(p),i.env?.NODE_ENV!=="production"&&console.log(`[Emitochondria] Config loaded from: ${g}`),d}return d={},d}let E=n.readFileSync(c,"utf-8");return d=JSON.parse(E),i.env?.NODE_ENV!=="production"&&console.log(`[Emitochondria] Config loaded from: ${c}`),d}catch(t){return t?.code!=="ENOENT"&&console.warn(`[Emitochondria] Failed to load config: ${t?.message}`),d={},d}}function b(i,t){let n={...i};for(let o in t)t[o]!==void 0&&(typeof t[o]=="object"&&t[o]!==null&&!Array.isArray(t[o])&&typeof n[o]=="object"&&n[o]!==null?n[o]=b(n[o],t[o]):n[o]=t[o]);return n}function F(i={}){let t=K();return b(t,i)}function C(){d=null,m=null}var O=typeof globalThis.process<"u"&&globalThis.process?.versions?.node!=null,A=typeof globalThis.window<"u";function B(i,t){let n=new Date;switch(i){case"unix":return String(n.getTime());case"human":return n.toLocaleString("en-US",{timeZone:t==="utc"?"UTC":void 0,month:"short",day:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit",hour12:!0});default:return t==="utc"?n.toISOString():new Date(n.getTime()-n.getTimezoneOffset()*6e4).toISOString().slice(0,-1)}}function R(i){let t=i.match(/^(\d+(?:\.\d+)?)\s*(KB|MB|GB)$/i);if(!t)return 10*1024*1024;let n=parseFloat(t[1]),o=t[2].toUpperCase(),r={KB:1024,MB:1024*1024,GB:1024*1024*1024};return n*(r[o]??10*1024*1024)}var v=class{options;maxSizeBytes;browserWarned=!1;fs=null;path=null;constructor(t={}){this.options={timestamps:t.timestamps??!1,timestampFormat:t.timestampFormat??"iso",timezone:t.timezone??"utc",persist:t.persist??!1,path:t.path??"./logs/emitochondria.log",format:t.format??"text",maxSize:t.maxSize??"10MB",logEvents:t.logEvents??!1,logErrors:t.logErrors??!0,logWarnings:t.logWarnings??!0},this.maxSizeBytes=R(this.options.maxSize),this.options.persist&&this.initFileLogging()}initFileLogging(){if(A){this.browserWarned||(console.warn("[Emitochondria] File logging is not available in browser environments. Logs will only be written to console."),this.browserWarned=!0);return}if(O)try{let t=globalThis.require;if(t){this.fs=t("fs"),this.path=t("path");let n=H(),o=this.path.isAbsolute(this.options.path)?this.options.path:this.path.join(n,this.options.path);this.options.path=o;let r=this.path.dirname(o);this.fs.existsSync(r)||this.fs.mkdirSync(r,{recursive:!0}),globalThis.process?.env?.NODE_ENV!=="production"&&console.log(`[Emitochondria] Logs will be written to: ${o}`)}}catch(t){console.error("[Emitochondria] Failed to initialize file logging:",t)}}getTimestamp(){if(this.options.timestamps)return B(this.options.timestampFormat,this.options.timezone)}formatEntry(t){let n=this.getTimestamp();if(this.options.format==="json"){let r={level:t.level,type:t.type,message:t.message};return n&&(r.timestamp=n),t.event&&(r.event=t.event),t.payload!==void 0&&(r.payload=t.payload),t.error&&(r.error=String(t.error)),JSON.stringify(r)}let o=[];return n&&o.push(`[${n}]`),o.push(`[${t.level.toUpperCase()}]`),t.event&&o.push(`[${t.event}]`),o.push(t.message),t.payload!==void 0&&o.push(`| Payload: ${JSON.stringify(t.payload)}`),t.error&&o.push(`| Error: ${t.error}`),o.join(" ")}writeToFile(t){if(!(!this.fs||!this.path||!O))try{let n=t+`
2
- `;this.fs.existsSync(this.options.path)&&this.fs.statSync(this.options.path).size>=this.maxSizeBytes&&this.rotateLog(),this.fs.appendFileSync(this.options.path,n,"utf8")}catch(n){console.error("[Emitochondria] Failed to write to log file:",n)}}rotateLog(){if(!(!this.fs||!this.path))try{let t=1;for(;this.fs.existsSync(`${this.options.path}.${t}`);)t++;this.fs.renameSync(this.options.path,`${this.options.path}.${t}`)}catch(t){console.error("[Emitochondria] Failed to rotate log file:",t)}}logEvent(t,n){if(!this.options.logEvents)return;let o={level:"info",type:"event",event:t,message:"Event emitted",payload:n},r=this.formatEntry(o);console.log(r),this.options.persist&&this.writeToFile(r)}logError(t,n,o){if(!this.options.logErrors)return;let r={level:"error",type:"error",event:t,message:"Handler threw an error",error:n},c=this.formatEntry(r);console.error(c),this.options.persist&&this.writeToFile(c)}logWarning(t,n,o){if(!this.options.logWarnings)return;let r={level:"warn",type:"warning",event:t,message:n,payload:o},c=this.formatEntry(r);console.warn(c),this.options.persist&&this.writeToFile(c)}};var q=(i,t,n)=>{};function x(i={}){let t=F(i),n=new v(t.logging),o=new Map,r=new Set,c=t.maxListeners??10,E=i.onMaxListenersExceeded??q,g=t.onError??"default",p=new Set,u=e=>o.get(e)??o.set(e,new Set).get(e),y=(e,a,s)=>{if(n.logError(a,e,s),g==="throw")throw e;typeof g=="function"&&g(e,a,s)},S=(e,a,s)=>{try{let l=e(s);if(l instanceof Promise)return l.catch(f=>y(f,a,e))}catch(l){y(l,a,e)}},z=(e,a)=>{if(c>0&&a>c&&!p.has(e)){p.add(e);let s=`Possible memory leak: ${a} listeners (max: ${c})`;n.logWarning(e,s,{count:a,max:c}),E(e,a,c)}},w={on(e,a){let s=u(e);return s.add(a),z(e,s.size),()=>w.off(e,a)},off(e,a){let s=u(e);if(s.delete(a)){s.size<=c&&p.delete(e);return}for(let l of s)if(l.__original===a){s.delete(l),s.size<=c&&p.delete(e);break}},once(e,a){let s=(l=>(w.off(e,s),a(l)));return s.__original=a,w.on(e,s)},emit(e,...a){let s=a[0];n.logEvent(e,s),u(e).forEach(l=>S(l,e,s)),r.forEach(l=>{try{l(e,s)}catch(f){y(f,e,l)}})},async emitAsync(e,...a){let s=a[0],l=[];n.logEvent(e,s),u(e).forEach(f=>{let h=S(f,e,s);h instanceof Promise&&l.push(h)}),r.forEach(f=>{try{let h=f(e,s);h instanceof Promise&&l.push(h.catch(M=>y(M,e,f)))}catch(h){y(h,e,f)}}),await Promise.all(l)},onAny(e){return r.add(e),()=>w.offAny(e)},offAny(e){r.delete(e)},clear(e){e?(o.delete(e),p.delete(e)):(o.clear(),r.clear(),p.clear())},listenerCount(e){return u(e).size},setErrorHandler(e){g=e},setMaxListeners(e){c=e,e===0&&p.clear()},getMaxListeners(){return c},eventNames(){return Array.from(o.keys()).filter(e=>o.get(e).size>0)},listeners(e){let a=u(e);return Array.from(a).map(s=>s.__original||s)},wildcardListeners(){return Array.from(r)},hasListener(e,a){let s=u(e);if(s.has(a))return!0;for(let l of s)if(l.__original===a)return!0;return!1}};return w}0&&(module.exports={clearConfigCache,createEmitochondria});
3
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../src/config.ts","../src/logger.ts","../src/emitter.ts"],"sourcesContent":["// Core\nexport { createEmitochondria } from './emitter.js';\n\n// Types\nexport type {\n EventMap,\n EventKey,\n EventHandler,\n WildcardHandler,\n ErrorHandler,\n MaxListenersHandler,\n EmitochondriaConfig,\n EmitochondriaOptions,\n Emitochondria,\n LoggingOptions,\n TimestampFormat,\n Timezone,\n LogFormat,\n} from './types.js';\n\n// Utilities (for testing/advanced use)\nexport { clearConfigCache } from './config.js';\n\n// Default export\nexport { createEmitochondria as default } from './emitter.js';\n","import { EmitochondriaConfig, EmitochondriaOptions, EventMap } from './types.js';\n\n// ============================================================\n// CONFIG FILE LOADING\n// ============================================================\n\nconst CONFIG_FILENAME = 'emitochondria.config.json';\n\nlet cachedConfig: EmitochondriaConfig | null = null;\nlet cachedProjectRoot: string | null = null;\n\n/**\n * Find project root by walking up directories looking for package.json.\n */\nfunction findProjectRoot(): string {\n if (cachedProjectRoot !== null) return cachedProjectRoot;\n\n const proc = (globalThis as any).process;\n if (typeof proc === 'undefined' || !proc?.versions?.node) {\n cachedProjectRoot = '';\n return '';\n }\n\n try {\n const req = (globalThis as any).require;\n if (!req) {\n const cwd: string = proc.cwd();\n cachedProjectRoot = cwd;\n return cwd;\n }\n\n const path = req('path');\n const fs = req('fs');\n\n let dir: string = proc.cwd();\n\n // Walk up looking for package.json\n while (dir !== path.dirname(dir)) {\n if (fs.existsSync(path.join(dir, 'package.json'))) {\n cachedProjectRoot = dir;\n return dir;\n }\n dir = path.dirname(dir);\n }\n\n // Fallback to cwd if no package.json found\n const cwd: string = proc.cwd();\n cachedProjectRoot = cwd;\n return cwd;\n } catch {\n const cwd: string = proc.cwd();\n cachedProjectRoot = cwd;\n return cwd;\n }\n}\n\n/**\n * Get the cached project root (for use by logger).\n */\nexport function getProjectRoot(): string {\n return findProjectRoot();\n}\n\n/**\n * Synchronous version for initial load.\n * Falls back to empty config if loading fails.\n */\nfunction loadConfigFileSync(): EmitochondriaConfig {\n if (cachedConfig !== null) return cachedConfig;\n\n const proc = (globalThis as any).process;\n if (typeof proc === 'undefined' || !proc?.versions?.node) {\n cachedConfig = {};\n return cachedConfig;\n }\n\n try {\n const req = (globalThis as any).require;\n if (!req) {\n cachedConfig = {};\n return cachedConfig;\n }\n\n const fs = req('fs');\n const path = req('path');\n\n // Look for config in project root first\n const projectRoot = findProjectRoot();\n const configPath = path.join(projectRoot, CONFIG_FILENAME);\n\n if (!fs.existsSync(configPath)) {\n // Also try cwd as fallback\n const cwdPath = path.join(proc.cwd(), CONFIG_FILENAME);\n if (fs.existsSync(cwdPath)) {\n const content = fs.readFileSync(cwdPath, 'utf-8');\n cachedConfig = JSON.parse(content) as EmitochondriaConfig;\n\n if (proc.env?.NODE_ENV !== 'production') {\n console.log(`[Emitochondria] Config loaded from: ${cwdPath}`);\n }\n\n return cachedConfig;\n }\n\n cachedConfig = {};\n return cachedConfig;\n }\n\n const content = fs.readFileSync(configPath, 'utf-8');\n cachedConfig = JSON.parse(content) as EmitochondriaConfig;\n\n if (proc.env?.NODE_ENV !== 'production') {\n console.log(`[Emitochondria] Config loaded from: ${configPath}`);\n }\n\n return cachedConfig;\n } catch (err: any) {\n if (err?.code !== 'ENOENT') {\n console.warn(`[Emitochondria] Failed to load config: ${err?.message}`);\n }\n cachedConfig = {};\n return cachedConfig;\n }\n}\n\n// ============================================================\n// CONFIG MERGING\n// ============================================================\n\n/**\n * Deep merge two objects, with second taking precedence.\n */\nfunction deepMerge<T extends Record<string, any>>(base: T, override: Partial<T>): T {\n const result = { ...base };\n\n for (const key in override) {\n if (override[key] !== undefined) {\n if (\n typeof override[key] === 'object' &&\n override[key] !== null &&\n !Array.isArray(override[key]) &&\n typeof result[key] === 'object' &&\n result[key] !== null\n ) {\n result[key] = deepMerge(result[key], override[key]);\n } else {\n result[key] = override[key] as T[typeof key];\n }\n }\n }\n\n return result;\n}\n\n/**\n * Merge file config with options.\n * Options take precedence over file config.\n */\nexport function mergeConfig<T extends EventMap>(\n options: EmitochondriaOptions<T> = {}\n): EmitochondriaOptions<T> {\n const fileConfig = loadConfigFileSync();\n // Type assertion is safe here because we control both inputs\n const merged = deepMerge(fileConfig as any, options as any);\n return merged as EmitochondriaOptions<T>;\n}\n\n/**\n * Clear cached config (useful for testing).\n */\nexport function clearConfigCache(): void {\n cachedConfig = null;\n cachedProjectRoot = null;\n}\n","import { LoggingOptions, TimestampFormat, Timezone } from './types.js';\nimport { getProjectRoot } from './config.js';\n\n// ============================================================\n// ENVIRONMENT DETECTION\n// ============================================================\n\nconst isNode = typeof (globalThis as any).process !== 'undefined'\n && (globalThis as any).process?.versions?.node != null;\n\nconst isBrowser = typeof (globalThis as any).window !== 'undefined';\n\n// ============================================================\n// TIMESTAMP FORMATTING\n// ============================================================\n\nfunction formatTimestamp(format: TimestampFormat, timezone: Timezone): string {\n const date = new Date();\n\n switch (format) {\n case 'unix':\n return String(date.getTime());\n\n case 'human':\n return date.toLocaleString('en-US', {\n timeZone: timezone === 'utc' ? 'UTC' : undefined,\n month: 'short',\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n hour12: true,\n });\n\n case 'iso':\n default:\n return timezone === 'utc'\n ? date.toISOString()\n : new Date(date.getTime() - date.getTimezoneOffset() * 60000)\n .toISOString()\n .slice(0, -1); // Remove 'Z' for local\n }\n}\n\n// ============================================================\n// SIZE PARSING\n// ============================================================\n\nfunction parseSize(size: string): number {\n const match = size.match(/^(\\d+(?:\\.\\d+)?)\\s*(KB|MB|GB)$/i);\n if (!match) return 10 * 1024 * 1024; // Default 10MB\n\n const value = parseFloat(match[1]!);\n const unit = match[2]!.toUpperCase();\n\n const multipliers: Record<string, number> = {\n 'KB': 1024,\n 'MB': 1024 * 1024,\n 'GB': 1024 * 1024 * 1024,\n };\n\n return value * (multipliers[unit] ?? 10 * 1024 * 1024);\n}\n\n// ============================================================\n// LOG ENTRY TYPES\n// ============================================================\n\nexport type LogLevel = 'info' | 'warn' | 'error';\n\nexport interface LogEntry {\n level: LogLevel;\n type: 'event' | 'error' | 'warning';\n event?: string;\n message: string;\n payload?: unknown;\n error?: unknown;\n}\n\n// ============================================================\n// LOGGER CLASS\n// ============================================================\n\nexport class Logger {\n private options: Required<LoggingOptions>;\n private maxSizeBytes: number;\n private browserWarned = false;\n private fs: any = null;\n private path: any = null;\n\n constructor(options: LoggingOptions = {}) {\n this.options = {\n timestamps: options.timestamps ?? false,\n timestampFormat: options.timestampFormat ?? 'iso',\n timezone: options.timezone ?? 'utc',\n persist: options.persist ?? false,\n path: options.path ?? './logs/emitochondria.log',\n format: options.format ?? 'text',\n maxSize: options.maxSize ?? '10MB',\n logEvents: options.logEvents ?? false,\n logErrors: options.logErrors ?? true,\n logWarnings: options.logWarnings ?? true,\n };\n\n this.maxSizeBytes = parseSize(this.options.maxSize);\n\n if (this.options.persist) {\n this.initFileLogging();\n }\n }\n\n private initFileLogging(): void {\n if (isBrowser) {\n if (!this.browserWarned) {\n console.warn(\n '[Emitochondria] File logging is not available in browser environments. ' +\n 'Logs will only be written to console.'\n );\n this.browserWarned = true;\n }\n return;\n }\n\n if (!isNode) return;\n\n try {\n // Require fs and path synchronously\n const req = (globalThis as any).require;\n if (req) {\n this.fs = req('fs');\n this.path = req('path');\n\n // Resolve path relative to project root (where package.json is)\n const projectRoot = getProjectRoot();\n const resolvedPath = this.path.isAbsolute(this.options.path)\n ? this.options.path\n : this.path.join(projectRoot, this.options.path);\n\n // Update options with resolved path\n this.options.path = resolvedPath;\n\n // Create directory if needed\n const dir = this.path.dirname(resolvedPath);\n if (!this.fs.existsSync(dir)) {\n this.fs.mkdirSync(dir, { recursive: true });\n }\n\n // Log where logs are being written (helpful for debugging)\n const proc = (globalThis as any).process;\n if (proc?.env?.NODE_ENV !== 'production') {\n console.log(`[Emitochondria] Logs will be written to: ${resolvedPath}`);\n }\n }\n } catch (err) {\n console.error('[Emitochondria] Failed to initialize file logging:', err);\n }\n }\n\n private getTimestamp(): string | undefined {\n if (!this.options.timestamps) return undefined;\n return formatTimestamp(this.options.timestampFormat, this.options.timezone);\n }\n\n private formatEntry(entry: LogEntry): string {\n const timestamp = this.getTimestamp();\n\n if (this.options.format === 'json') {\n const obj: any = {\n level: entry.level,\n type: entry.type,\n message: entry.message,\n };\n if (timestamp) obj.timestamp = timestamp;\n if (entry.event) obj.event = entry.event;\n if (entry.payload !== undefined) obj.payload = entry.payload;\n if (entry.error) obj.error = String(entry.error);\n return JSON.stringify(obj);\n }\n\n // Text format\n const parts: string[] = [];\n if (timestamp) parts.push(`[${timestamp}]`);\n parts.push(`[${entry.level.toUpperCase()}]`);\n if (entry.event) parts.push(`[${entry.event}]`);\n parts.push(entry.message);\n if (entry.payload !== undefined) {\n parts.push(`| Payload: ${JSON.stringify(entry.payload)}`);\n }\n if (entry.error) {\n parts.push(`| Error: ${entry.error}`);\n }\n\n return parts.join(' ');\n }\n\n private writeToFile(content: string): void {\n if (!this.fs || !this.path || !isNode) return;\n\n try {\n const line = content + '\\n';\n\n // Check if rotation needed\n if (this.fs.existsSync(this.options.path)) {\n const stats = this.fs.statSync(this.options.path);\n if (stats.size >= this.maxSizeBytes) {\n this.rotateLog();\n }\n }\n\n // Sync write — simple, ordered, reliable\n this.fs.appendFileSync(this.options.path, line, 'utf8');\n } catch (err) {\n console.error('[Emitochondria] Failed to write to log file:', err);\n }\n }\n\n private rotateLog(): void {\n if (!this.fs || !this.path) return;\n\n try {\n // Find next rotation number\n let rotationNum = 1;\n while (this.fs.existsSync(`${this.options.path}.${rotationNum}`)) {\n rotationNum++;\n }\n\n // Rename current file\n this.fs.renameSync(this.options.path, `${this.options.path}.${rotationNum}`);\n } catch (err) {\n console.error('[Emitochondria] Failed to rotate log file:', err);\n }\n }\n\n // ============================================================\n // PUBLIC LOGGING METHODS\n // ============================================================\n\n logEvent(event: string, payload: unknown): void {\n if (!this.options.logEvents) return;\n\n const entry: LogEntry = {\n level: 'info',\n type: 'event',\n event,\n message: 'Event emitted',\n payload,\n };\n\n const formatted = this.formatEntry(entry);\n console.log(formatted);\n\n if (this.options.persist) {\n this.writeToFile(formatted);\n }\n }\n\n logError(event: string, error: unknown, _handler?: unknown): void {\n if (!this.options.logErrors) return;\n\n const entry: LogEntry = {\n level: 'error',\n type: 'error',\n event,\n message: 'Handler threw an error',\n error,\n };\n\n const formatted = this.formatEntry(entry);\n console.error(formatted);\n\n if (this.options.persist) {\n this.writeToFile(formatted);\n }\n }\n\n logWarning(event: string, message: string, details?: Record<string, unknown>): void {\n if (!this.options.logWarnings) return;\n\n const entry: LogEntry = {\n level: 'warn',\n type: 'warning',\n event,\n message,\n payload: details,\n };\n\n const formatted = this.formatEntry(entry);\n console.warn(formatted);\n\n if (this.options.persist) {\n this.writeToFile(formatted);\n }\n }\n}\n","import {\n EventMap,\n EventKey,\n EventHandler,\n WildcardHandler,\n ErrorHandler,\n EmitochondriaOptions,\n Emitochondria,\n} from './types.js';\nimport { Logger } from './logger.js';\nimport { mergeConfig } from './config.js';\n\n// ============================================================\n// DEFAULT HANDLERS\n// ============================================================\n\nconst defaultMaxListenersHandler = <T extends EventMap>(\n _event: EventKey<T>,\n _count: number,\n _max: number\n): void => {\n // Handled by logger\n};\n\n// ============================================================\n// FACTORY FUNCTION\n// ============================================================\n\nexport function createEmitochondria<T extends EventMap>(\n options: EmitochondriaOptions<T> = {}\n): Emitochondria<T> {\n // Merge file config with options\n const config = mergeConfig(options);\n\n // Initialize logger\n const logger = new Logger(config.logging);\n\n // Handler storage\n const handlers: Map<string, Set<EventHandler<unknown>>> = new Map();\n const wildcards: Set<WildcardHandler<T>> = new Set();\n\n // Configuration state\n let maxListeners = config.maxListeners ?? 10;\n let onMaxListenersExceeded = options.onMaxListenersExceeded ?? defaultMaxListenersHandler;\n let errorHandler: ErrorHandler<T> | 'throw' | 'default' = config.onError ?? 'default';\n\n // Memory leak tracking\n const warned = new Set<string>();\n\n // ============================================================\n // HELPER FUNCTIONS\n // ============================================================\n\n // Track original handlers for once() wrappers\n type WrappedHandler<T> = EventHandler<T> & { __original?: EventHandler<T> };\n\n const get = (e: string) => handlers.get(e) ?? handlers.set(e, new Set()).get(e)!;\n\n const handleError = <K extends EventKey<T>>(\n error: unknown,\n event: K,\n handler: EventHandler<unknown>\n ): void => {\n logger.logError(event, error, handler);\n\n if (errorHandler === 'throw') {\n throw error;\n } else if (typeof errorHandler === 'function') {\n errorHandler(error, event, handler);\n }\n // 'default' = just log (already done above)\n };\n\n const safeCall = <K extends EventKey<T>>(\n handler: EventHandler<unknown>,\n event: K,\n payload: unknown\n ): void | Promise<void> => {\n try {\n const result = handler(payload);\n if (result instanceof Promise) {\n return result.catch((err) => handleError(err, event, handler));\n }\n } catch (err) {\n handleError(err, event, handler);\n }\n };\n\n const checkMaxListeners = <K extends EventKey<T>>(event: K, count: number): void => {\n if (maxListeners > 0 && count > maxListeners && !warned.has(event)) {\n warned.add(event);\n\n const message = `Possible memory leak: ${count} listeners (max: ${maxListeners})`;\n logger.logWarning(event, message, { count, max: maxListeners });\n\n onMaxListenersExceeded(event, count, maxListeners);\n }\n };\n\n // ============================================================\n // EMITTER IMPLEMENTATION\n // ============================================================\n\n const emitter: Emitochondria<T> = {\n on(event, handler) {\n const set = get(event);\n set.add(handler as EventHandler<unknown>);\n checkMaxListeners(event, set.size);\n return () => emitter.off(event, handler);\n },\n\n off(event, handler) {\n const set = get(event);\n\n // Try direct removal first\n if (set.delete(handler as EventHandler<unknown>)) {\n if (set.size <= maxListeners) {\n warned.delete(event);\n }\n return;\n }\n\n // Search for wrapped handler (for once handlers)\n for (const wrapped of set) {\n const w = wrapped as WrappedHandler<unknown>;\n if (w.__original === handler) {\n set.delete(wrapped);\n if (set.size <= maxListeners) {\n warned.delete(event);\n }\n break;\n }\n }\n },\n\n once(event, handler) {\n const wrapper = ((payload: T[typeof event]) => {\n emitter.off(event, wrapper as EventHandler<T[typeof event]>);\n return handler(payload);\n }) as WrappedHandler<T[typeof event]>;\n\n // Store original reference for manual removal\n wrapper.__original = handler;\n\n return emitter.on(event, wrapper);\n },\n\n emit(event, ...payload) {\n const data = payload[0];\n\n logger.logEvent(event, data);\n\n get(event).forEach((h) => safeCall(h, event, data));\n wildcards.forEach((h) => {\n try {\n h(event, data as T[typeof event]);\n } catch (err) {\n handleError(err, event, h as unknown as EventHandler<unknown>);\n }\n });\n },\n\n async emitAsync(event, ...payload) {\n const data = payload[0];\n const promises: Promise<void>[] = [];\n\n logger.logEvent(event, data);\n\n get(event).forEach((h) => {\n const result = safeCall(h, event, data);\n if (result instanceof Promise) promises.push(result);\n });\n\n wildcards.forEach((h) => {\n try {\n const result = h(event, data as T[typeof event]);\n if (result instanceof Promise) {\n promises.push(result.catch((err) =>\n handleError(err, event, h as unknown as EventHandler<unknown>)\n ));\n }\n } catch (err) {\n handleError(err, event, h as unknown as EventHandler<unknown>);\n }\n });\n\n await Promise.all(promises);\n },\n\n onAny(handler) {\n wildcards.add(handler);\n return () => emitter.offAny(handler);\n },\n\n offAny(handler) {\n wildcards.delete(handler);\n },\n\n clear(event?) {\n if (event) {\n handlers.delete(event);\n warned.delete(event);\n } else {\n handlers.clear();\n wildcards.clear();\n warned.clear();\n }\n },\n\n listenerCount(event) {\n return get(event).size;\n },\n\n setErrorHandler(handler) {\n errorHandler = handler;\n },\n\n setMaxListeners(n) {\n maxListeners = n;\n if (n === 0) warned.clear();\n },\n\n getMaxListeners() {\n return maxListeners;\n },\n\n eventNames() {\n return Array.from(handlers.keys()).filter(\n (k) => handlers.get(k)!.size > 0\n ) as EventKey<T>[];\n },\n\n listeners(event) {\n const set = get(event);\n // Return unwrapped handlers for better debugging\n return Array.from(set).map(handler => {\n const wrapped = handler as WrappedHandler<unknown>;\n return (wrapped.__original || handler) as EventHandler<T[typeof event]>;\n });\n },\n\n wildcardListeners() {\n return Array.from(wildcards);\n },\n\n hasListener(event, handler) {\n const set = get(event);\n\n // Check direct match\n if (set.has(handler as EventHandler<unknown>)) {\n return true;\n }\n\n // Check wrapped handlers (once)\n for (const wrapped of set) {\n const w = wrapped as WrappedHandler<unknown>;\n if (w.__original === handler) {\n return true;\n }\n }\n\n return false;\n },\n };\n\n return emitter;\n}\n"],"mappings":"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","names":["index_exports","__export","clearConfigCache","createEmitochondria","__toCommonJS","CONFIG_FILENAME","cachedConfig","cachedProjectRoot","findProjectRoot","proc","req","cwd","path","fs","dir","getProjectRoot","loadConfigFileSync","projectRoot","configPath","cwdPath","content","err","deepMerge","base","override","result","key","mergeConfig","options","fileConfig","clearConfigCache","isNode","isBrowser","formatTimestamp","format","timezone","date","parseSize","size","match","value","unit","multipliers","Logger","options","req","projectRoot","getProjectRoot","resolvedPath","dir","err","entry","timestamp","obj","parts","content","line","rotationNum","event","payload","formatted","error","_handler","message","details","defaultMaxListenersHandler","_event","_count","_max","createEmitochondria","options","config","mergeConfig","logger","Logger","handlers","wildcards","maxListeners","onMaxListenersExceeded","errorHandler","warned","get","handleError","error","event","handler","safeCall","payload","result","err","checkMaxListeners","count","message","emitter","set","wrapped","wrapper","data","h","promises","n","k"]}