@ublitzjs/channel 1.0.0

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.
package/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # @ublitzjs/channel - REALLY fastest niche event emitter alternative
2
+
3
+ A blazing-fast, lightweight Pub/Sub event channel designed as a high-performance, type-safe alternative to Node's standard `EventEmitter`.
4
+
5
+ ![μBlitz.js](https://github.com/ublitzjs/core/blob/main/logo.png)
6
+ <br/>
7
+
8
+ Built for performance-critical applications, it minimizes creation overhead and leverages an optimized swap-and-pop strategy to achieve **$O(1)$ unsubscription times** for unique listeners.
9
+
10
+ ## Features
11
+
12
+ - **Ultra Low Overhead:** Faster instantiation and publication execution than standard event emitters.
13
+ - **$O(1)$ Removals:** True constant-time unsubscriptions via `sub_unique` and `unsub_unique`.
14
+ - **Self-Cleaning Listeners:** Easily create single-use (`once`) events mid-execution without breaking the dispatch loop.
15
+ - **No Dependencies:** Works in NodeJS, Bun and a Web browser
16
+ - **TypeScript-first**
17
+ - **Prebuilt for ESM and CJS**
18
+ - **Thoroughly tested**
19
+
20
+ > ⚠️ **Important Note on Ordering:** To maintain extreme speed during deletions, the execution order of the remaining listeners is **not preserved** when a subscriber is removed.
21
+
22
+ ---
23
+
24
+ ## Benchmarks
25
+ - [NodeJS](./nodejs_benchmark.md)
26
+ - [Bun](./bunjs_benchmark.md)
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ bun add @ublitzjs/channel
32
+ ```
33
+
34
+ ## Quick Start
35
+ ### Using a single Channel
36
+
37
+ If you use EventEmitter for only one event, use **Channel** directly
38
+ ```typescript
39
+
40
+ import { Channel } from '@ublitzjs/channel';
41
+
42
+ // Define your payload type
43
+ type LogMessage = `[Log] ${string}`;
44
+
45
+ // Create a channel with a payload type
46
+ const logChannel = new Channel<LogMessage>();
47
+
48
+ // Subscribe to updates (like emitter.on)
49
+ const onLog = (msg: LogMessage) => console.log(`Received: ${msg}`);
50
+ logChannel.sub(onLog);
51
+
52
+ // Publish data (like emitter.emit)
53
+ logChannel.pub("[Log] User logged in successfully");
54
+
55
+ // Unsubscribe (like emitter.off)
56
+ logChannel.unsub(onLog);
57
+ ```
58
+
59
+ ## Using a ChannelMap (EventEmitter Style)
60
+
61
+ For multiple lazily created centralised events use **ChannelMap**
62
+ ```typescript
63
+
64
+ import { ChannelMap } from '@ublitzjs/channel';
65
+
66
+ // 1. Define your Event Registry Map
67
+ interface AppEvents {
68
+ 'user:login': { id: number; username: string };
69
+ 'user:logout': { id: number };
70
+ }
71
+
72
+ // 2. Instantiate the Emitter Map
73
+ const emitter = new ChannelMap<AppEvents>();
74
+
75
+ // 3. Get the specific channel and subscribe
76
+ const loginChannel = emitter.on('user:login');
77
+
78
+ loginChannel.sub(({ username }) => {
79
+ console.log(`Welcome back, ${username}!`);
80
+ });
81
+
82
+ // 4. Emit/Publish an event
83
+ loginChannel.pub({ id: 42, username: 'Neo' });
84
+ ```
85
+
86
+ ## Core Guide & Performance Optimization
87
+ 1. Standard Subscription (sub / unsub)
88
+
89
+ Best used for listeners shared across multiple distinct channels or when you intend to subscribe the exact same function reference multiple times to a single channel.
90
+
91
+ Unsubscription Cost: O(N) linear scan from the end of the array.
92
+
93
+ ```typescript
94
+ channel.sub(myListener);
95
+ channel.unsub(myListener);
96
+ ```
97
+
98
+ 2. High-Performance Unique Subscription (sub_unique / unsub_unique)
99
+
100
+ Highly Recommended for hot code paths. By ensuring a listener is unique to this channel, the channel injects an internal tracking ID to achieve instant unsubscription.
101
+
102
+ Unsubscription Cost: O(1) constant time.
103
+
104
+ ```typescript
105
+ // The listener reference must be unique to this channel instance
106
+ const onDataReceived = (data) => processData(data);
107
+
108
+ channel.sub_unique(onDataReceived);
109
+
110
+ // Instantly removed in O(1) time complexity
111
+ channel.unsub_unique(onDataReceived);
112
+ ```
113
+
114
+ 🔴 Warning: Do not manually modify or rely on the id property appended to your callback function in your external application logic.
115
+
116
+ 3. Single-Use / Self-Cleaning Listeners (unsubCurrent)
117
+
118
+ Perfect for implementing once() behavior. If listener is It is advised to call it at the top of a listener
119
+ ```TypeScript
120
+
121
+ channel.sub((data) => {
122
+ // Safely unsubscribes the callback while the channel is mid-publication
123
+ channel.unsubCurrent();
124
+ console.log("This will only run for the very first event dispatch:", data);
125
+ });
126
+
127
+ channel.sub(async (data)=>{
128
+ channel.unsubCurrent();
129
+ await doSomething(data);
130
+
131
+ /* Do not call unsubCurrent() here */
132
+ })
133
+ ```
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * An optimized Pub/Sub event channel designed as a high-performance, scalable alternative to the standard `EventEmitter`.
5
+ * Features $O(1)$ removals for unique listeners and faster creation overhead.
6
+ * @template MessageType The type of data payload published by this channel.
7
+ * @note The order of listeners is **not preserved** when removing subscribers.
8
+ * @see Inspired by tseep.
9
+ * @example
10
+ * type LogMessage = `[Log] ${string}`;
11
+ * const logChannel = new Channel<LogMessage>();
12
+ * const onLog = (msg: LogMessage) => console.log(msg);
13
+ * logChannel.sub_unique(onLog);
14
+ * logChannel.pub("[Log] User logged in");
15
+ * logChannel.unsub_unique(onLog);
16
+ */
17
+ Object.defineProperty(exports, "__esModule", {
18
+ value: true
19
+ });
20
+ exports.ChannelMap = exports.Channel = void 0;
21
+ class Channel {
22
+ cbs = [];
23
+ i = 0;
24
+ /**
25
+ * Indicates whether the channel currently has no active listeners.
26
+ */
27
+ get isEmpty() {
28
+ return !this.cbs.length;
29
+ }
30
+ /**
31
+ * Subscribes a listener to the channel.
32
+ * Use this for general listeners, that you reuse in many Channel instances OR when you need to register a listener several times OR or removal order doesn't matter.
33
+ * @example
34
+ * channel.sub((data) => console.log(data));
35
+ */
36
+ sub(fn) {
37
+ this.cbs.push(fn);
38
+ }
39
+ /**
40
+ * Subscribes a unique listener to the channel and attaches an internal ID metadata property.
41
+ * Use this alongside `unsub_unique` to achieve constant time $O(1)$ unsubscription performance.
42
+ * @example
43
+ * const onEvent = (data) => console.log(data);
44
+ * channel.sub_unique(onEvent);
45
+ */
46
+ sub_unique(fn) {
47
+ var cbs = this.cbs;
48
+ fn.id = cbs.length;
49
+ cbs.push(fn);
50
+ }
51
+ /**
52
+ * Unsubscribes a listener by performing a linear scan from the end of the array.
53
+ * @warning This method alters the execution order of the remaining listeners.
54
+ * @example
55
+ * channel.unsub(onEvent);
56
+ */
57
+ unsub(fn) {
58
+ for (var i = this.cbs.length - 1; i >= 0; i--) {
59
+ if (this.cbs[i] != fn) continue;
60
+ if (i == this.cbs.length - 1) {
61
+ this.cbs.pop();
62
+ } else {
63
+ let newCb = this.cbs[i] = this.cbs.pop();
64
+ newCb.id = i;
65
+ }
66
+ break;
67
+ }
68
+ }
69
+ /**
70
+ * Unsubscribes a listener previously registered via `sub_unique`.
71
+ * Leverages the internal `id` property to swap and pop elements in $O(1)$ time.
72
+ * @warning This method alters the execution order of the remaining listeners.
73
+ * @example
74
+ * channel.unsub_unique(onEvent);
75
+ */
76
+ unsub_unique(fn) {
77
+ var id = fn.id;
78
+ if (id == this.cbs.length - 1) {
79
+ this.cbs.pop();
80
+ } else {
81
+ let newCb = this.cbs[id] = this.cbs.pop();
82
+ newCb.id = id;
83
+ }
84
+ }
85
+ /**
86
+ * Unsubscribes the listener that is **currently executing** during a publication cycle.
87
+ * Useful for writing single-use ("once") listeners or self-cleaning hooks.
88
+ * @warning This method alters the execution order of the remaining listeners.
89
+ * @example
90
+ * channel.sub((msg) => {
91
+ * console.log("Runs only once:", msg);
92
+ * channel.unsubCurrent();
93
+ * });
94
+ */
95
+ unsubCurrent() {
96
+ var cbs = this.cbs;
97
+ if (this.i == cbs.length - 1) {
98
+ cbs.pop();
99
+ return;
100
+ }
101
+ ;
102
+ var newCb = cbs[this.i] = cbs.pop();
103
+ newCb.id = this.i--;
104
+ }
105
+ /**
106
+ * Publishes data synchronously to all registered listeners.
107
+ * Listeners can be safely removed mid-execution via `unsubCurrent()`.
108
+ * @example
109
+ * channel.pub({ eventType: "click", x: 10, y: 20 });
110
+ */
111
+ pub(data) {
112
+ var cbs = this.cbs;
113
+ while (this.i < cbs.length) {
114
+ cbs[this.i](data);
115
+ this.i++;
116
+ }
117
+ this.i = 0;
118
+ }
119
+ /**
120
+ * Drops all registered listeners from the channel instantly.
121
+ */
122
+ clear() {
123
+ this.cbs = [];
124
+ }
125
+ }
126
+ /**
127
+ * A strongly-typed map wrapper that dynamically manages distinct named `Channel` instances.
128
+ * Acts as a minimal simulation of EventEmitter
129
+ * For event names use should use strings performance-wise
130
+ * @template EventMap Type definition containing event names mapped to their respective payloads.
131
+ * @example
132
+ * interface Events {
133
+ * login: { username: string };
134
+ * }
135
+ * const emitter = new ChannelMap<Events>();
136
+ * var channel = emitter.on("login");
137
+ * channel.sub(({ username }) => console.log(username));
138
+ * channel.pub({ username: "Neo" });
139
+ */
140
+ exports.Channel = Channel;
141
+ class ChannelMap {
142
+ /* Map get initialised lazily*/
143
+ events = {};
144
+ /**
145
+ * Retrieves or instantiates the specific `Channel` instance tied to an event name.
146
+ * @param ev The event name/key.
147
+ * @returns The `Channel` handling the event payload type.
148
+ */
149
+ on(ev) {
150
+ return this.events[ev] ??= new Channel();
151
+ }
152
+ /**
153
+ * @param ev The optional event name/key. If present - clears the channel for event. Otherwise - remove all channels
154
+ */
155
+ removeAllListeners(ev) {
156
+ ev ? this.events[ev]?.clear() : this.events = {};
157
+ }
158
+ }
159
+ exports.ChannelMap = ChannelMap;
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ /**
3
+ * An optimized Pub/Sub event channel designed as a high-performance, scalable alternative to the standard `EventEmitter`.
4
+ * Features $O(1)$ removals for unique listeners and faster creation overhead.
5
+ * @template MessageType The type of data payload published by this channel.
6
+ * @note The order of listeners is **not preserved** when removing subscribers.
7
+ * @see Inspired by tseep.
8
+ * @example
9
+ * type LogMessage = `[Log] ${string}`;
10
+ * const logChannel = new Channel<LogMessage>();
11
+ * const onLog = (msg: LogMessage) => console.log(msg);
12
+ * logChannel.sub_unique(onLog);
13
+ * logChannel.pub("[Log] User logged in");
14
+ * logChannel.unsub_unique(onLog);
15
+ */
16
+ export class Channel {
17
+ cbs = [];
18
+ i = 0;
19
+ /**
20
+ * Indicates whether the channel currently has no active listeners.
21
+ */
22
+ get isEmpty() { return !this.cbs.length; }
23
+ /**
24
+ * Subscribes a listener to the channel.
25
+ * Use this for general listeners, that you reuse in many Channel instances OR when you need to register a listener several times OR or removal order doesn't matter.
26
+ * @example
27
+ * channel.sub((data) => console.log(data));
28
+ */
29
+ sub(fn) {
30
+ this.cbs.push(fn);
31
+ }
32
+ /**
33
+ * Subscribes a unique listener to the channel and attaches an internal ID metadata property.
34
+ * Use this alongside `unsub_unique` to achieve constant time $O(1)$ unsubscription performance.
35
+ * @example
36
+ * const onEvent = (data) => console.log(data);
37
+ * channel.sub_unique(onEvent);
38
+ */
39
+ sub_unique(fn) {
40
+ var cbs = this.cbs;
41
+ fn.id = cbs.length;
42
+ cbs.push(fn);
43
+ }
44
+ /**
45
+ * Unsubscribes a listener by performing a linear scan from the end of the array.
46
+ * @warning This method alters the execution order of the remaining listeners.
47
+ * @example
48
+ * channel.unsub(onEvent);
49
+ */
50
+ unsub(fn) {
51
+ for (var i = this.cbs.length - 1; i >= 0; i--) {
52
+ if (this.cbs[i] != fn)
53
+ continue;
54
+ if (i == this.cbs.length - 1) {
55
+ this.cbs.pop();
56
+ }
57
+ else {
58
+ let newCb = (this.cbs[i] = this.cbs.pop());
59
+ newCb.id = i;
60
+ }
61
+ break;
62
+ }
63
+ }
64
+ /**
65
+ * Unsubscribes a listener previously registered via `sub_unique`.
66
+ * Leverages the internal `id` property to swap and pop elements in $O(1)$ time.
67
+ * @warning This method alters the execution order of the remaining listeners.
68
+ * @example
69
+ * channel.unsub_unique(onEvent);
70
+ */
71
+ unsub_unique(fn) {
72
+ var id = fn.id;
73
+ if (id == this.cbs.length - 1) {
74
+ this.cbs.pop();
75
+ }
76
+ else {
77
+ let newCb = (this.cbs[id] = this.cbs.pop());
78
+ newCb.id = id;
79
+ }
80
+ }
81
+ /**
82
+ * Unsubscribes the listener that is **currently executing** during a publication cycle.
83
+ * Useful for writing single-use ("once") listeners or self-cleaning hooks.
84
+ * @warning This method alters the execution order of the remaining listeners.
85
+ * @example
86
+ * channel.sub((msg) => {
87
+ * console.log("Runs only once:", msg);
88
+ * channel.unsubCurrent();
89
+ * });
90
+ */
91
+ unsubCurrent() {
92
+ var cbs = this.cbs;
93
+ if (this.i == cbs.length - 1) {
94
+ cbs.pop();
95
+ return;
96
+ }
97
+ ;
98
+ var newCb = (cbs[this.i] = cbs.pop());
99
+ newCb.id = this.i--;
100
+ }
101
+ /**
102
+ * Publishes data synchronously to all registered listeners.
103
+ * Listeners can be safely removed mid-execution via `unsubCurrent()`.
104
+ * @example
105
+ * channel.pub({ eventType: "click", x: 10, y: 20 });
106
+ */
107
+ pub(data) {
108
+ var cbs = this.cbs;
109
+ while (this.i < cbs.length) {
110
+ cbs[this.i](data);
111
+ this.i++;
112
+ }
113
+ this.i = 0;
114
+ }
115
+ /**
116
+ * Drops all registered listeners from the channel instantly.
117
+ */
118
+ clear() { this.cbs = []; }
119
+ }
120
+ /**
121
+ * A strongly-typed map wrapper that dynamically manages distinct named `Channel` instances.
122
+ * Acts as a minimal simulation of EventEmitter
123
+ * For event names use should use strings performance-wise
124
+ * @template EventMap Type definition containing event names mapped to their respective payloads.
125
+ * @example
126
+ * interface Events {
127
+ * login: { username: string };
128
+ * }
129
+ * const emitter = new ChannelMap<Events>();
130
+ * var channel = emitter.on("login");
131
+ * channel.sub(({ username }) => console.log(username));
132
+ * channel.pub({ username: "Neo" });
133
+ */
134
+ export class ChannelMap {
135
+ /* Map get initialised lazily*/
136
+ events = {};
137
+ /**
138
+ * Retrieves or instantiates the specific `Channel` instance tied to an event name.
139
+ * @param ev The event name/key.
140
+ * @returns The `Channel` handling the event payload type.
141
+ */
142
+ on(ev) {
143
+ return this.events[ev] ??= new Channel();
144
+ }
145
+ /**
146
+ * @param ev The optional event name/key. If present - clears the channel for event. Otherwise - remove all channels
147
+ */
148
+ removeAllListeners(ev) {
149
+ ev ? this.events[ev]?.clear() : this.events = {};
150
+ }
151
+ }
@@ -0,0 +1 @@
1
+ {"type": "module"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * A callback function used as a listener in a `Channel`.
3
+ * * @template T The type of data payload this callback receives.
4
+ * * @note This type is mutated internally with an `id` property to achieve $O(1)$ lookup times during unsubscription.
5
+ * **Do not manually modify or rely on the `id` property in external code.**
6
+ */
7
+ export type ChannelCB<T> = ((data: T) => void) & {
8
+ id?: number;
9
+ };
10
+ /**
11
+ * An optimized Pub/Sub event channel designed as a high-performance, scalable alternative to the standard `EventEmitter`.
12
+ * Features $O(1)$ removals for unique listeners and faster creation overhead.
13
+ * @template MessageType The type of data payload published by this channel.
14
+ * @note The order of listeners is **not preserved** when removing subscribers.
15
+ * @see Inspired by tseep.
16
+ * @example
17
+ * type LogMessage = `[Log] ${string}`;
18
+ * const logChannel = new Channel<LogMessage>();
19
+ * const onLog = (msg: LogMessage) => console.log(msg);
20
+ * logChannel.sub_unique(onLog);
21
+ * logChannel.pub("[Log] User logged in");
22
+ * logChannel.unsub_unique(onLog);
23
+ */
24
+ export declare class Channel<MessageType> {
25
+ protected cbs: ChannelCB<MessageType>[];
26
+ protected i: number;
27
+ /**
28
+ * Indicates whether the channel currently has no active listeners.
29
+ */
30
+ get isEmpty(): boolean;
31
+ /**
32
+ * Subscribes a listener to the channel.
33
+ * Use this for general listeners, that you reuse in many Channel instances OR when you need to register a listener several times OR or removal order doesn't matter.
34
+ * @example
35
+ * channel.sub((data) => console.log(data));
36
+ */
37
+ sub(fn: ChannelCB<MessageType>): void;
38
+ /**
39
+ * Subscribes a unique listener to the channel and attaches an internal ID metadata property.
40
+ * Use this alongside `unsub_unique` to achieve constant time $O(1)$ unsubscription performance.
41
+ * @example
42
+ * const onEvent = (data) => console.log(data);
43
+ * channel.sub_unique(onEvent);
44
+ */
45
+ sub_unique(fn: ChannelCB<MessageType>): void;
46
+ /**
47
+ * Unsubscribes a listener by performing a linear scan from the end of the array.
48
+ * @warning This method alters the execution order of the remaining listeners.
49
+ * @example
50
+ * channel.unsub(onEvent);
51
+ */
52
+ unsub(fn: ChannelCB<MessageType>): void;
53
+ /**
54
+ * Unsubscribes a listener previously registered via `sub_unique`.
55
+ * Leverages the internal `id` property to swap and pop elements in $O(1)$ time.
56
+ * @warning This method alters the execution order of the remaining listeners.
57
+ * @example
58
+ * channel.unsub_unique(onEvent);
59
+ */
60
+ unsub_unique(fn: ChannelCB<MessageType>): void;
61
+ /**
62
+ * Unsubscribes the listener that is **currently executing** during a publication cycle.
63
+ * Useful for writing single-use ("once") listeners or self-cleaning hooks.
64
+ * @warning This method alters the execution order of the remaining listeners.
65
+ * @example
66
+ * channel.sub((msg) => {
67
+ * console.log("Runs only once:", msg);
68
+ * channel.unsubCurrent();
69
+ * });
70
+ */
71
+ unsubCurrent(): void;
72
+ /**
73
+ * Publishes data synchronously to all registered listeners.
74
+ * Listeners can be safely removed mid-execution via `unsubCurrent()`.
75
+ * @example
76
+ * channel.pub({ eventType: "click", x: 10, y: 20 });
77
+ */
78
+ pub(data: MessageType): void;
79
+ /**
80
+ * Drops all registered listeners from the channel instantly.
81
+ */
82
+ clear(): void;
83
+ }
84
+ /**
85
+ * A strongly-typed map wrapper that dynamically manages distinct named `Channel` instances.
86
+ * Acts as a minimal simulation of EventEmitter
87
+ * For event names use should use strings performance-wise
88
+ * @template EventMap Type definition containing event names mapped to their respective payloads.
89
+ * @example
90
+ * interface Events {
91
+ * login: { username: string };
92
+ * }
93
+ * const emitter = new ChannelMap<Events>();
94
+ * var channel = emitter.on("login");
95
+ * channel.sub(({ username }) => console.log(username));
96
+ * channel.pub({ username: "Neo" });
97
+ */
98
+ export declare class ChannelMap<EventMap extends Record<string | number | symbol, any>> {
99
+ protected events: EventMap;
100
+ /**
101
+ * Retrieves or instantiates the specific `Channel` instance tied to an event name.
102
+ * @param ev The event name/key.
103
+ * @returns The `Channel` handling the event payload type.
104
+ */
105
+ on<Event extends keyof EventMap>(ev: Event): Channel<EventMap[Event]>;
106
+ /**
107
+ * @param ev The optional event name/key. If present - clears the channel for event. Otherwise - remove all channels
108
+ */
109
+ removeAllListeners(ev?: keyof EventMap): void;
110
+ }
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@ublitzjs/channel",
3
+ "version": "1.0.0",
4
+ "types": "./dist/types/index.d.ts",
5
+ "files": ["dist", "LICENSE"],
6
+ "typesVersions": {
7
+ "*": {
8
+ ".": ["./dist/types/index.d.ts"]
9
+ }
10
+ },
11
+ "license": "MIT",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/types/index.d.ts",
15
+ "require": "./dist/cjs/index.js",
16
+ "import": "./dist/esm/index.js"
17
+ }
18
+ },
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "devDependencies": {
23
+ "@babel/cli": "^7.28.6",
24
+ "@babel/core": "^7.29.0",
25
+ "@babel/plugin-transform-modules-commonjs": "^7.28.6",
26
+ "@types/node": "^25.9.1",
27
+ "cozyevent": "^1.3.3",
28
+ "esbuild": "^0.25.12",
29
+ "tinybench": "^6.0.0",
30
+ "tsd": "^0.33.0",
31
+ "tseep": "^1.3.1"
32
+ },
33
+ "scripts": {
34
+ "trick-tsd": "bun link && bun link @ublitzjs/channel",
35
+ "build:esm": "tsc -p tsconfig.esm.json && echo '{\"type\": \"module\"}' > dist/esm/package.json",
36
+ "build:cjs": "babel dist/esm --out-dir dist/cjs",
37
+ "build:types": "tsc -p tsconfig.types.json",
38
+ "build": "npm run build:types && npm run build:esm && npm run build:cjs",
39
+ "test": "tsd && vitest run tests/index.test.ts --coverage",
40
+ "bench:node": "node tests/bench.mjs",
41
+ "bench:bun": "bun tests/bench.mjs"
42
+ },
43
+ "tsd": {
44
+ "directory": "tests"
45
+ },
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/ublitzjs/channel.git"
49
+ },
50
+ "bugs": {
51
+ "url": "https://github.com/ublitzjs/channel/issues",
52
+ "email": "diril656@gmail.com"
53
+ },
54
+ "homepage": "https://github.com/ublitzjs/channel#readme",
55
+ "keywords": [
56
+ "ublitzjs",
57
+ "typescript",
58
+ "development",
59
+ "pub/sub",
60
+ "fastest event emitter",
61
+ "O(1)",
62
+ "asynchronous code",
63
+ "µBlitz.js"
64
+ ],
65
+ "dependencies": {
66
+ "@vitest/coverage-v8": "^4.1.7",
67
+ "vitest": "^4.1.7"
68
+ }
69
+ }