{"_id":"@beautiful-types/strong-events","_rev":"5-3573ca9936e01e866de7e9c0ecac86c0","name":"@beautiful-types/strong-events","dist-tags":{"latest":"2.1.2"},"versions":{"1.0.0":{"name":"@beautiful-types/strong-events","version":"1.0.0","keywords":["typescript","events","event-emitter","type-safe","strongly-typed","class-based","event-system"],"author":{"name":"RiegelZdenek"},"license":"MIT","_id":"@beautiful-types/strong-events@1.0.0","maintainers":[{"name":"zdenek_riegel","email":"riegel.zdenek@gmail.com"}],"homepage":"https://github.com/RiegelZdenek/strong-events#readme","bugs":{"url":"https://github.com/RiegelZdenek/strong-events/issues"},"dist":{"shasum":"1c6f88b5b226ee83bc458a513f2148424d35d836","tarball":"https://registry.npmjs.org/@beautiful-types/strong-events/-/strong-events-1.0.0.tgz","fileCount":7,"integrity":"sha512-7RnVHr2tJa7ja06OUStVewXAE9umeUoszUhGob++Vz8J/8OoNcAN4ERga8gtJTAuMAxlDADg2Ux2KTkPLzpZeg==","signatures":[{"sig":"MEUCIF3D8DwddCyLKRzFGk+BcPKTsFIoqvZ4HvdtsQFZc094AiEA5oosWzX6QN6uDfFRVIaEasRW7Hijz8ZB7qxOlv9w4WI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":25858},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=14.0.0"},"gitHead":"0eb391a81eaadca562e59f5ac4a0ad3b1a992dbf","scripts":{"dev":"tsc --watch","test":"jest","build":"tsc","test:watch":"jest --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"zdenek_riegel","email":"riegel.zdenek@gmail.com"},"repository":{"url":"git+https://github.com/RiegelZdenek/strong-events.git","type":"git"},"_npmVersion":"10.9.3","description":"A strongly-typed event emitter for TypeScript with class-based event definitions","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/strong-events_1.0.0_1759780426813_0.8980465907166273","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@beautiful-types/strong-events","version":"2.0.0","keywords":["typescript","events","event-emitter","type-safe","strongly-typed","class-based","event-system"],"author":{"name":"RiegelZdenek"},"license":"MIT","_id":"@beautiful-types/strong-events@2.0.0","maintainers":[{"name":"zdenek_riegel","email":"riegel.zdenek@gmail.com"}],"homepage":"https://github.com/RiegelZdenek/strong-events#readme","bugs":{"url":"https://github.com/RiegelZdenek/strong-events/issues"},"dist":{"shasum":"088ec71b11f77fe285947d35a235df1de0503826","tarball":"https://registry.npmjs.org/@beautiful-types/strong-events/-/strong-events-2.0.0.tgz","fileCount":7,"integrity":"sha512-0/P3XthOftGZ8h23HOpRXaXn/g281wcpCP06oR9QXeZbY3+pmZQATRtrfEAqYJp3RmivzrmqPW9A4wPH9aM8rg==","signatures":[{"sig":"MEUCIGU5ZP1EUnHJrdm1E1yiha7ioagEosHiWpsK+r5AmBtcAiEAxe6+OGHrhBRbh4F6lviZSySYMKv7KPI+8wH2bIniyJc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":28058},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=14.0.0"},"gitHead":"27c4c433c8ba86257fc51ab115022c0384136c64","scripts":{"dev":"tsc --watch","test":"jest","build":"tsc","test:watch":"jest --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"zdenek_riegel","email":"riegel.zdenek@gmail.com"},"repository":{"url":"git+https://github.com/RiegelZdenek/strong-events.git","type":"git"},"_npmVersion":"10.9.3","description":"A strongly-typed event emitter for TypeScript with class-based event definitions","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/strong-events_2.0.0_1760639997909_0.8109662828367064","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@beautiful-types/strong-events","version":"2.1.0","keywords":["typescript","events","event-emitter","type-safe","strongly-typed","class-based","event-system"],"author":{"name":"RiegelZdenek"},"license":"MIT","_id":"@beautiful-types/strong-events@2.1.0","maintainers":[{"name":"zdenek_riegel","email":"riegel.zdenek@gmail.com"}],"homepage":"https://github.com/RiegelZdenek/strong-events#readme","bugs":{"url":"https://github.com/RiegelZdenek/strong-events/issues"},"dist":{"shasum":"2d20f979ef2cf2005b129ab4ff9bd1cc3c140bae","tarball":"https://registry.npmjs.org/@beautiful-types/strong-events/-/strong-events-2.1.0.tgz","fileCount":13,"integrity":"sha512-Xbv1A7fbwJ1VmC9c+aaReZuus8ur/e7wSw0jP7vRV3UZJyxc/kbxEPjd30c+BpsohROgyiYNhi8jvnQBSfqnZw==","signatures":[{"sig":"MEUCIQC5tzAK/yTKUyPT+Yd5YTccmCduHMkW5JeUWvYf0Z3ekgIgBOY3Gv7RslXBSb6Hyo13+7rNmwamXHkQpByKvEkBEmg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":30130},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=14.0.0"},"gitHead":"86bdbc7cd6ed27f7d9e83797bdc37ffb3b94ec01","scripts":{"dev":"tsc --watch","test":"jest","build":"tsc","test:watch":"jest --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"zdenek_riegel","email":"riegel.zdenek@gmail.com"},"repository":{"url":"git+https://github.com/RiegelZdenek/strong-events.git","type":"git"},"_npmVersion":"10.9.3","description":"A strongly-typed event emitter for TypeScript with class-based event definitions","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/strong-events_2.1.0_1760740959312_0.25323113348527837","host":"s3://npm-registry-packages-npm-production"}},"2.1.1":{"name":"@beautiful-types/strong-events","version":"2.1.1","keywords":["typescript","events","event-emitter","type-safe","strongly-typed","class-based","event-system"],"author":{"name":"RiegelZdenek"},"license":"MIT","_id":"@beautiful-types/strong-events@2.1.1","maintainers":[{"name":"zdenek_riegel","email":"riegel.zdenek@gmail.com"}],"homepage":"https://github.com/RiegelZdenek/strong-events#readme","bugs":{"url":"https://github.com/RiegelZdenek/strong-events/issues"},"dist":{"shasum":"8ef9a59615e5b2197a3e3acdcff2ab05b573cb2c","tarball":"https://registry.npmjs.org/@beautiful-types/strong-events/-/strong-events-2.1.1.tgz","fileCount":13,"integrity":"sha512-Rt66S8qs8wHODzhGY1miuXS0dAEH3R1gwZKzDsm0fQ7w72bB4uFL2ajVCxWTG+f+BBIQjNSc6ocalxwVXrrx2A==","signatures":[{"sig":"MEQCIGKX/ZsFJYriqAvCkJJLRwneRNKuAyybGuzjfpOmhSV4AiAtgjR1Sm9kc+yOH+wvH/8XU4Su7mccS4Rf3cwhNa9baw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":30332},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=14.0.0"},"gitHead":"c34354d78e856f904cc48ada737f9ed6371daa92","scripts":{"dev":"tsc --watch","test":"jest","build":"tsc","test:watch":"jest --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"zdenek_riegel","email":"riegel.zdenek@gmail.com"},"repository":{"url":"git+https://github.com/RiegelZdenek/strong-events.git","type":"git"},"_npmVersion":"10.9.3","description":"A strongly-typed event emitter for TypeScript with class-based event definitions","directories":{},"_nodeVersion":"22.19.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/strong-events_2.1.1_1760886069261_0.6974785402037194","host":"s3://npm-registry-packages-npm-production"}},"2.1.2":{"name":"@beautiful-types/strong-events","version":"2.1.2","description":"A strongly-typed event emitter for TypeScript with class-based event definitions","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","test":"jest","test:watch":"jest --watch","prepublishOnly":"npm run build","dev":"tsc --watch"},"keywords":["typescript","events","event-emitter","type-safe","strongly-typed","class-based","event-system"],"author":{"name":"RiegelZdenek"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/RiegelZdenek/strong-events.git"},"bugs":{"url":"https://github.com/RiegelZdenek/strong-events/issues"},"homepage":"https://github.com/RiegelZdenek/strong-events#readme","devDependencies":{"@types/jest":"^29.5.0","@types/node":"^20.0.0","jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0"},"engines":{"node":">=14.0.0"},"_id":"@beautiful-types/strong-events@2.1.2","gitHead":"bb96e114db8d17effc9bbc87742bb73edb7c45df","_nodeVersion":"22.19.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-JPe0LgubJH96zFL9324dlxA2rUqRbUNhfmEITk5O9f5xcdSXjOG6siZNNOct6bV+GO/29qBapSsAG8fpFkYi6g==","shasum":"0be6e43fd9f02434603dd198312f54e118ca162a","tarball":"https://registry.npmjs.org/@beautiful-types/strong-events/-/strong-events-2.1.2.tgz","fileCount":13,"unpackedSize":30688,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDhv4uwRJIDCx/7c+1n9//GMr+XNHqaEnRBDrQBV8dwyAIhAIT8ACPsedqn84LcuWpLtlDUC10xX0+mvrjgbkUH3uUo"}]},"_npmUser":{"name":"zdenek_riegel","email":"riegel.zdenek@gmail.com"},"directories":{},"maintainers":[{"name":"zdenek_riegel","email":"riegel.zdenek@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/strong-events_2.1.2_1761504339429_0.8065184936606622"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-06T19:53:46.740Z","modified":"2025-10-26T18:45:39.830Z","1.0.0":"2025-10-06T19:53:47.003Z","2.0.0":"2025-10-16T18:39:58.136Z","2.1.0":"2025-10-17T22:42:39.517Z","2.1.1":"2025-10-19T15:01:09.473Z","2.1.2":"2025-10-26T18:45:39.622Z"},"bugs":{"url":"https://github.com/RiegelZdenek/strong-events/issues"},"author":{"name":"RiegelZdenek"},"license":"MIT","homepage":"https://github.com/RiegelZdenek/strong-events#readme","keywords":["typescript","events","event-emitter","type-safe","strongly-typed","class-based","event-system"],"repository":{"type":"git","url":"git+https://github.com/RiegelZdenek/strong-events.git"},"description":"A strongly-typed event emitter for TypeScript with class-based event definitions","maintainers":[{"name":"zdenek_riegel","email":"riegel.zdenek@gmail.com"}],"readme":"# Strong Events\r\n\r\nA strongly-typed event emitter for TypeScript that uses class-based event definitions to provide type safety.\r\n\r\n[![npm version](https://badge.fury.io/js/@beautiful-types%2Fstrong-events.svg)](https://badge.fury.io/js/@beautiful-types%2Fstrong-events)\r\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)\r\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\r\n\r\n## Features\r\n\r\n- **🔒 Type Safety**: Event payloads are typed at compile time.\r\n- **🌳 Event Inheritance**: Create event hierarchies with automatic parent listener invocation.\r\n- **�🌐 Wildcard Listening**: Listen to all events or entire event families.\r\n- **⚡ Async Support**: Built-in support for parallel async event handling.\r\n- **📦 Zero Dependencies**: Lightweight and dependency-free.\r\n\r\n## 🚀 Quick Start\r\n\r\n### Installation\r\n\r\n```bash\r\nnpm install @beautiful-types/strong-events\r\n```\r\n\r\n### Basic Usage\r\n\r\n```typescript\r\nimport { EventEmitter, BaseEvent } from '@beautiful-types/strong-events';\r\n\r\n// Define your event data types\r\ninterface IUser {\r\n  name: string;\r\n  age: number;\r\n  email: string;\r\n}\r\n\r\n// Create strongly-typed events\r\nclass UserCreatedEvent extends BaseEvent<IUser> {}\r\nclass UserDeletedEvent extends BaseEvent<{ userId: string }> {}\r\n\r\n// Create the event emitter\r\nconst emitter = new EventEmitter();\r\n\r\n// Register type-safe listeners\r\nemitter.on(UserCreatedEvent, (user) => {\r\n  console.log(`New user: ${user.name}`); // user is fully typed as IUser\r\n});\r\n\r\n// Optional second parameter provides emit information\r\nemitter.on(UserDeletedEvent, ({ userId }, emitInfo) => {\r\n  console.log(`User ${userId} deleted`);\r\n  // emitInfo contains metadata about the current emission\r\n});\r\n\r\n// Emit events with type checking\r\nemitter.emit(UserCreatedEvent, {\r\n  name: 'Alice',\r\n  age: 30,\r\n  email: 'alice@example.com'\r\n});\r\n\r\nemitter.emit(UserDeletedEvent, { userId: '123' });\r\n```\r\n\r\n## 🔍 Comparison with String-Based Emitters\r\n\r\n### Traditional Event Emitters\r\n\r\nString-based event names are prone to typos and require manual type assertions.\r\n\r\n```typescript\r\n// Prone to typos and requires casting\r\nemitter.on('user:created', (data: any) => {\r\n  console.log(data.name); // No type safety, could be undefined\r\n});\r\n\r\n// A typo here ('user:create' instead of 'user:created') would fail silently.\r\nemitter.emit('user:create', userData);\r\n```\r\n\r\n### Strong Events\r\n\r\nClass-based events prevent typos and provide full type safety for payloads.\r\n\r\n```typescript\r\n// The event name is a class, so typos are impossible.\r\nemitter.on(UserCreatedEvent, (user) => {\r\n  console.log(user.name); // `user` is fully typed, so autocompletion works.\r\n});\r\n\r\n// The compiler ensures the payload matches the event's type definition.\r\nemitter.emit(UserCreatedEvent, userData);\r\n```\r\n\r\n## 📚 API Reference\r\n\r\n### EventEmitter\r\n\r\nThe main class for managing events.\r\n\r\n#### Methods\r\n\r\n- **`on<T>(event, listener)`**: Register an event listener. Listener receives `(data, emitInfo?)`.\r\n- **`off<T>(event, listener)`**: Remove a specific listener.\r\n- **`once<T>(event, listener)`**: Register a one-time listener.\r\n- **`emit<T>(event, data)`**: Synchronously emit an event. Returns `true` if no errors occurred.\r\n- **`emitAsync<T>(event, data)`**: Asynchronously emit an event in parallel. Returns `true` if all listeners succeeded.\r\n- **`removeAllListenersFor<T>(event)`**: Remove all listeners for a specific event type.\r\n- **`removeAllListeners()`**: Remove all listeners for all events.\r\n\r\n### EmitInfo\r\n\r\nThe optional second parameter passed to listeners containing information about the current emission.\r\n\r\n#### Properties\r\n\r\n- **`event`**: The event constructor that was emitted.\r\n- **`shouldContinuePropagation`**: Whether propagation should continue to parent event classes.\r\n\r\n#### Methods\r\n\r\n- **`stopEventPropagation()`**: Stops propagation to parent event classes (only works with `emit()`, not `emitAsync()`).\r\n\r\n### BaseEvent<TArgs>\r\n\r\nThe base class for creating event types.\r\n\r\n```typescript\r\nclass MyEvent extends BaseEvent<{ message: string }> {}\r\n```\r\n\r\n## ⚡ Async Support\r\n\r\nListeners can be synchronous or asynchronous. When using `emitAsync`, all listeners are executed in parallel.\r\n\r\n```typescript\r\nimport { EventEmitter, BaseEvent } from '@beautiful-types/strong-events';\r\n\r\nclass FileProcessedEvent extends BaseEvent<{ filename: string }> {}\r\n\r\nconst emitter = new EventEmitter();\r\n\r\n// Mix sync and async listeners\r\nemitter.on(FileProcessedEvent, (file) => {\r\n  console.log(`Processing: ${file.filename}`); // Sync\r\n});\r\n\r\nemitter.on(FileProcessedEvent, async (file) => {\r\n  await uploadToCloud(file.filename); // Async\r\n  console.log(`Uploaded: ${file.filename}`);\r\n});\r\n\r\n// All listeners execute in parallel.\r\nawait emitter.emitAsync(FileProcessedEvent, { filename: 'document.pdf' });\r\n```\r\n\r\n## 🌳 Event Inheritance\r\n\r\nEvents can inherit from a base event, allowing for structured event hierarchies.\r\n\r\n```typescript\r\ninterface OrderData {\r\n  orderId: string;\r\n  amount: number;\r\n}\r\n\r\n// A base event for all order-related events\r\nclass BaseOrderEvent extends BaseEvent<OrderData> {}\r\n\r\n// Specific order events that inherit from the base\r\nclass OrderCreatedEvent extends BaseOrderEvent {}\r\nclass OrderCancelledEvent extends BaseOrderEvent {}\r\n\r\nconst emitter = new EventEmitter();\r\n\r\n// This listener will catch ALL events that inherit from BaseOrderEvent\r\nemitter.on(BaseOrderEvent, (order) => {\r\n  console.log(`Order event: ${order.orderId}`);\r\n});\r\n\r\n// This listener only catches OrderCreatedEvent\r\nemitter.on(OrderCreatedEvent, (order) => {\r\n  console.log(`Order created: ${order.orderId}`);\r\n});\r\n\r\n// Emitting OrderCreatedEvent will trigger BOTH listeners above.\r\nemitter.emit(OrderCreatedEvent, { orderId: '123', amount: 99.99 });\r\n// Output:\r\n// \"Order created: 123\"\r\n// \"Order event: 123\"\r\n```\r\n\r\n### Stopping Event Propagation\r\n\r\nYou can prevent events from propagating to parent event classes using `emitInfo.stopEventPropagation()`.\r\n\r\n```typescript\r\n// This listener will stop propagation to BaseOrderEvent\r\nemitter.on(OrderCreatedEvent, (order, emitInfo) => {\r\n  console.log(`Order created: ${order.orderId}`);\r\n  emitInfo?.stopEventPropagation(); // Parent listeners won't be called\r\n});\r\n\r\nemitter.on(BaseOrderEvent, (order) => {\r\n  console.log(`This won't be called`);\r\n});\r\n\r\nemitter.emit(OrderCreatedEvent, { orderId: '123', amount: 99.99 });\r\n// Output: \"Order created: 123\"\r\n// The BaseOrderEvent listener is NOT called\r\n```\r\n\r\n**Note:** Propagation control only works with synchronous `emit()`. When using `emitAsync()`, all listeners are collected before execution begins, so `stopEventPropagation()` has no effect.\r\n\r\n```typescript\r\n// In async mode, propagation cannot be stopped\r\nawait emitter.emitAsync(OrderCreatedEvent, { orderId: '123', amount: 99.99 });\r\n// Both listeners will execute in parallel regardless of stopEventPropagation()\r\n```\r\n\r\n### Wildcard Listening with BaseEvent\r\n\r\nYou can listen to all events emitted by an emitter by subscribing to `BaseEvent`.\r\n\r\n```typescript\r\n// A catch-all listener for logging or debugging\r\nemitter.on(BaseEvent, (data, emitInfo) => {\r\n  console.log(`Event fired: ${emitInfo?.event.name}`);\r\n});\r\n\r\nemitter.emit(UserCreatedEvent, { name: 'Alice', age: 30, email: 'a@a.com' });\r\nemitter.emit(OrderCreatedEvent, { orderId: '456', amount: 49.99 });\r\n// Output:\r\n// \"Event fired: UserCreatedEvent\"\r\n// \"Event fired: OrderCreatedEvent\"\r\n```\r\n\r\n## 🛡️ Error Handling\r\n\r\nAn error thrown in one listener will not prevent other listeners from running. The `emit` method returns `false` if any listener throws an error.\r\n\r\n```typescript\r\nemitter.on(MyEvent, (data) => {\r\n  throw new Error('This listener failed.');\r\n});\r\n\r\nemitter.on(MyEvent, (data) => {\r\n  console.log('This listener still runs.');\r\n});\r\n\r\nconst success = emitter.emit(MyEvent, { test: true });\r\nconsole.log(success); // false - an error occurred\r\n\r\n// For async, returns false if any listener fails\r\nconst asyncSuccess = await emitter.emitAsync(MyEvent, { test: true });\r\nconsole.log(asyncSuccess); // false - an error occurred\r\n```\r\n\r\n## ⚙️ Performance\r\n\r\n- Uses Maps for O(1) listener lookup.\r\n- Automatically cleans up empty listener sets to manage memory.\r\n\r\n## TypeScript Configuration\r\n\r\nFor best results, your `tsconfig.json` should have `strict` mode enabled.\r\n\r\n```json\r\n{\r\n  \"compilerOptions\": {\r\n    \"strict\": true,\r\n    \"target\": \"ES2020\",\r\n    \"lib\": [\"ES2020\", \"DOM\"]\r\n  }\r\n}\r\n```\r\n\r\n## Examples\r\n\r\nThe `/examples` directory contains more usage patterns:\r\n\r\n- **`basic-usage.ts`**\r\n- **`async-events.ts`**\r\n- **`advanced-patterns.ts`**\r\n\r\n## Contributing\r\n\r\nContributions are welcome. Please feel free to submit a Pull Request.\r\n\r\n## License\r\n\r\nThis project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.\r\n\r\n---\r\n\r\n**Made with ❤️ and TypeScript**","readmeFilename":"README.md"}