eventify 2.0.1 → 3.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/BENCHMARKS.md +196 -0
- package/CHANGELOG.md +27 -0
- package/LICENSE +21 -0
- package/README.md +319 -160
- package/dist/index.d.ts +117 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +624 -0
- package/dist/index.js.map +10 -0
- package/package.json +54 -64
- package/.jshintrc +0 -35
- package/.npmignore +0 -8
- package/.travis.yml +0 -9
- package/Gruntfile.js +0 -53
- package/Makefile +0 -49
- package/dist/eventify.min.js +0 -1
- package/index.js +0 -1
- package/lib/ender.js +0 -8
- package/lib/eventify.js +0 -377
- package/test/browser-dist.html +0 -22
- package/test/browser.html +0 -23
- package/test/eventify.test.js +0 -730
package/README.md
CHANGED
|
@@ -1,226 +1,385 @@
|
|
|
1
1
|
# Eventify
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Tiny event emitter with strict TypeScript types, wildcard namespaces, and optional schema validation.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- ESM only, tree-shakeable
|
|
6
|
+
- Node 20+, Bun, modern browsers
|
|
7
|
+
- Backbone-style semantics (`all`, listener snapshots, predictable order)
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
## Install
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
```bash
|
|
12
|
+
npm install eventify
|
|
13
|
+
```
|
|
10
14
|
|
|
11
|
-
##
|
|
15
|
+
## Quickstart
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
```ts
|
|
18
|
+
import { createEmitter } from "eventify";
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
const emitter = createEmitter();
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
emitter.on("alert", (message) => {
|
|
23
|
+
console.log(message);
|
|
24
|
+
});
|
|
18
25
|
|
|
26
|
+
emitter.trigger("alert", "hello");
|
|
27
|
+
```
|
|
19
28
|
|
|
20
|
-
|
|
29
|
+
## Usage
|
|
21
30
|
|
|
22
|
-
|
|
31
|
+
### Mixins
|
|
23
32
|
|
|
33
|
+
```ts
|
|
34
|
+
import { decorateWithEvents } from "eventify";
|
|
24
35
|
|
|
25
|
-
|
|
36
|
+
const target = decorateWithEvents({ name: "service" });
|
|
37
|
+
```
|
|
26
38
|
|
|
27
|
-
|
|
39
|
+
### Typed Events
|
|
28
40
|
|
|
29
|
-
|
|
41
|
+
```ts
|
|
42
|
+
type Events = {
|
|
43
|
+
ready: void;
|
|
44
|
+
"change:title": string;
|
|
45
|
+
data: [string, number];
|
|
46
|
+
};
|
|
30
47
|
|
|
48
|
+
const emitter = createEmitter<Events>();
|
|
31
49
|
|
|
32
|
-
|
|
50
|
+
emitter.on("data", (name, count) => {
|
|
51
|
+
console.log(name, count);
|
|
52
|
+
});
|
|
33
53
|
|
|
34
|
-
|
|
54
|
+
emitter.trigger("data", "hello", 42);
|
|
55
|
+
```
|
|
35
56
|
|
|
36
|
-
|
|
57
|
+
### Event Maps + Space-Delimited Names
|
|
37
58
|
|
|
38
|
-
|
|
59
|
+
```ts
|
|
60
|
+
emitter.on({
|
|
61
|
+
"change:title": () => console.log("title"),
|
|
62
|
+
"change:author": () => console.log("author"),
|
|
63
|
+
});
|
|
39
64
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
});
|
|
65
|
+
emitter.on("open close", () => console.log("toggled"));
|
|
66
|
+
```
|
|
43
67
|
|
|
44
|
-
|
|
68
|
+
### Namespaces + Wildcards
|
|
45
69
|
|
|
46
|
-
|
|
70
|
+
Event names are split by `namespaceDelimiter` (default `/`). The `wildcard` token (default `*`) matches segments.
|
|
47
71
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
72
|
+
- `*` in the middle matches one segment
|
|
73
|
+
- trailing `*` matches remaining segments
|
|
74
|
+
- `*` alone matches any event (use `"all"` if you need the event name)
|
|
75
|
+
- leading/trailing delimiters create empty segments that must match exactly
|
|
51
76
|
|
|
52
|
-
|
|
77
|
+
```ts
|
|
78
|
+
const emitter = createEmitter({
|
|
79
|
+
namespaceDelimiter: "/",
|
|
80
|
+
wildcard: "*",
|
|
81
|
+
});
|
|
53
82
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
83
|
+
emitter.on("/product/foo/org/123/user/56/*", () => {
|
|
84
|
+
console.log("any account for that user");
|
|
85
|
+
});
|
|
57
86
|
|
|
58
|
-
|
|
87
|
+
emitter.on("/product/foo/org/123/*", () => {
|
|
88
|
+
console.log("any user in org 123");
|
|
89
|
+
});
|
|
59
90
|
|
|
60
|
-
|
|
91
|
+
emitter.on("/product/foo/*", () => {
|
|
92
|
+
console.log("any org in product foo");
|
|
93
|
+
});
|
|
61
94
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
})
|
|
95
|
+
emitter.trigger("/product/foo/org/123/user/56/account/abcd");
|
|
96
|
+
```
|
|
65
97
|
|
|
98
|
+
Middle-segment wildcards:
|
|
66
99
|
|
|
67
|
-
|
|
100
|
+
```ts
|
|
101
|
+
emitter.on("/product/foo/org/*/tracked-object/*/assesment", () => {
|
|
102
|
+
console.log("any tracked-object assesment within an org");
|
|
103
|
+
});
|
|
104
|
+
```
|
|
68
105
|
|
|
69
|
-
|
|
106
|
+
Colon namespaces:
|
|
70
107
|
|
|
71
|
-
|
|
108
|
+
```ts
|
|
109
|
+
const emitter = createEmitter({
|
|
110
|
+
namespaceDelimiter: ":",
|
|
111
|
+
wildcard: "*",
|
|
112
|
+
});
|
|
72
113
|
|
|
73
|
-
|
|
114
|
+
emitter.on("namespace:foo:*", () => {
|
|
115
|
+
console.log("any sub-event in namespace:foo");
|
|
116
|
+
});
|
|
117
|
+
```
|
|
74
118
|
|
|
119
|
+
### Schemas (Zod v4 Compatible)
|
|
75
120
|
|
|
76
|
-
|
|
121
|
+
Any schema with `parse` or `safeParse` works. Zod is supported via DI.
|
|
77
122
|
|
|
78
|
-
|
|
123
|
+
```ts
|
|
124
|
+
import { z } from "zod";
|
|
125
|
+
import { createEmitter, setDefaultSchemaValidator } from "eventify";
|
|
79
126
|
|
|
80
|
-
|
|
127
|
+
const schemas = {
|
|
128
|
+
data: z.tuple([z.string(), z.number()]),
|
|
129
|
+
ready: z.undefined(),
|
|
130
|
+
};
|
|
81
131
|
|
|
82
|
-
|
|
132
|
+
const emitter = createEmitter({
|
|
133
|
+
schemas,
|
|
134
|
+
validate: setDefaultSchemaValidator,
|
|
135
|
+
});
|
|
83
136
|
|
|
84
|
-
|
|
137
|
+
emitter.on("data", (name, count) => {
|
|
138
|
+
console.log(name, count);
|
|
139
|
+
});
|
|
85
140
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
});
|
|
141
|
+
emitter.trigger("data", "hello", 1);
|
|
142
|
+
```
|
|
89
143
|
|
|
144
|
+
Validation runs on `trigger`/`emit`/`produce`. If validation fails, the call throws and no listeners run.
|
|
90
145
|
|
|
91
|
-
|
|
146
|
+
### Error Handling
|
|
92
147
|
|
|
93
|
-
|
|
94
|
-
"change:title": titleView.update,
|
|
95
|
-
"change:author": authorPane.update,
|
|
96
|
-
"destroy": bookView.remove
|
|
97
|
-
});
|
|
148
|
+
Listener failures never crash by default. Errors are routed to `onError`.
|
|
98
149
|
|
|
150
|
+
```ts
|
|
151
|
+
const emitter = createEmitter({
|
|
152
|
+
onError: (error, meta) => {
|
|
153
|
+
console.error(meta.event, error);
|
|
154
|
+
},
|
|
155
|
+
});
|
|
99
156
|
|
|
100
|
-
|
|
157
|
+
emitter.on("boom", () => {
|
|
158
|
+
throw new Error("nope");
|
|
159
|
+
});
|
|
101
160
|
|
|
102
|
-
|
|
161
|
+
emitter.trigger("boom");
|
|
162
|
+
```
|
|
103
163
|
|
|
104
|
-
|
|
105
|
-
object.off("change", onChange);
|
|
164
|
+
### EventTarget Interop
|
|
106
165
|
|
|
107
|
-
|
|
108
|
-
object.off("change");
|
|
166
|
+
`createEmitter` and `decorateWithEvents` expose `addEventListener`, `removeEventListener`, and `dispatchEvent`.
|
|
109
167
|
|
|
110
|
-
|
|
111
|
-
|
|
168
|
+
`trigger`/`emit`/`produce` dispatch a `CustomEvent` with the payload in `event.detail`.
|
|
169
|
+
`dispatchEvent` only uses the EventTarget path (and matching `on` listeners). It does not run schemas, patterns, or `"all"`.
|
|
170
|
+
`detail` is the single payload for 1-arg events, an array for multi-arg events, and `undefined` for no-arg events.
|
|
112
171
|
|
|
113
|
-
|
|
114
|
-
object.off(null, null, context);
|
|
172
|
+
### Async Iteration
|
|
115
173
|
|
|
116
|
-
|
|
117
|
-
|
|
174
|
+
```ts
|
|
175
|
+
const emitter = createEmitter();
|
|
176
|
+
const iterator = emitter.iterate("data");
|
|
118
177
|
|
|
178
|
+
emitter.trigger("data", "a", 1);
|
|
119
179
|
|
|
120
|
-
|
|
180
|
+
const { value } = await iterator.next();
|
|
181
|
+
// value -> ["a", 1]
|
|
182
|
+
```
|
|
121
183
|
|
|
122
|
-
|
|
184
|
+
Iterate all events:
|
|
123
185
|
|
|
124
|
-
|
|
186
|
+
```ts
|
|
187
|
+
const all = emitter.iterate("all");
|
|
188
|
+
emitter.trigger("ready");
|
|
189
|
+
const { value } = await all.next();
|
|
190
|
+
// value -> ["ready"]
|
|
191
|
+
```
|
|
125
192
|
|
|
126
|
-
|
|
193
|
+
Abort with an `AbortSignal`:
|
|
127
194
|
|
|
195
|
+
```ts
|
|
196
|
+
const controller = new AbortController();
|
|
197
|
+
const iterator = emitter.iterate("data", { signal: controller.signal });
|
|
198
|
+
controller.abort();
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
`for await` with abort:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
const controller = new AbortController();
|
|
128
205
|
|
|
129
|
-
|
|
206
|
+
(async () => {
|
|
207
|
+
for await (const value of emitter.iterate("data", {
|
|
208
|
+
signal: controller.signal,
|
|
209
|
+
})) {
|
|
210
|
+
console.log(value);
|
|
211
|
+
controller.abort();
|
|
212
|
+
}
|
|
213
|
+
})();
|
|
214
|
+
```
|
|
130
215
|
|
|
131
|
-
|
|
216
|
+
### Failure Modes + Constraints
|
|
132
217
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
###
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
Another option is to bind the Eventify library to the window object using a different name. You can do so by declaring the localEventifyLibraryName before loading the Eventify library code. For example:
|
|
157
|
-
|
|
158
|
-
<script>var localEventifyLibraryName = 'EventManager';</script>
|
|
159
|
-
<script src="/dist/eventify.min.js" type="text/javascript"></script>
|
|
160
|
-
<script>
|
|
161
|
-
var dispatcher = EventManager.enable();
|
|
162
|
-
</script>
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
## Testing
|
|
166
|
-
|
|
167
|
-
In order to run the tests you will need to have nodejs installed.
|
|
168
|
-
|
|
169
|
-
Install dev dependencies with:
|
|
170
|
-
|
|
171
|
-
$ npm install
|
|
172
|
-
|
|
173
|
-
And then run the tests with:
|
|
174
|
-
|
|
175
|
-
$ make test
|
|
176
|
-
|
|
177
|
-
### On the browser
|
|
178
|
-
|
|
179
|
-
$ make test-browser
|
|
180
|
-
|
|
181
|
-
### Code coverage
|
|
182
|
-
|
|
183
|
-
You will need to install https://github.com/visionmedia/node-jscoverage
|
|
184
|
-
and then run
|
|
185
|
-
|
|
186
|
-
$ make test-coverage
|
|
187
|
-
|
|
188
|
-
## Development watcher and test runner
|
|
189
|
-
|
|
190
|
-
### Continuous linting
|
|
191
|
-
|
|
192
|
-
$ make dev
|
|
193
|
-
|
|
194
|
-
### Continuous testing
|
|
195
|
-
|
|
196
|
-
$ make test-watch
|
|
197
|
-
|
|
198
|
-
### Continuous linting + testing
|
|
199
|
-
|
|
200
|
-
$ make dev-test
|
|
218
|
+
- Validation failure: `trigger`/`emit`/`produce` throws and no listeners run (including wildcard and `all`).
|
|
219
|
+
- Listener errors: thrown errors or rejected promises are routed to `onError` and do not stop other listeners.
|
|
220
|
+
- Invalid callbacks: invoking a non-function throws a `TypeError` that is routed to `onError`.
|
|
221
|
+
- `onError` failures: errors thrown by the handler are swallowed to avoid crashing producers.
|
|
222
|
+
- `iterate` backpressure: if producers emit faster than you consume, the iterator queue grows. Use `AbortSignal`, `return()`, or stop iteration.
|
|
223
|
+
- `listenTo`/`listenToOnce`: the target must be an Eventify emitter (or another object with compatible `on`/`once`/`off`).
|
|
224
|
+
|
|
225
|
+
Constraint tools:
|
|
226
|
+
|
|
227
|
+
- Payload: `schemas` + `validate` enforce data shape at emit time.
|
|
228
|
+
- Cardinality: `once` / `listenToOnce`.
|
|
229
|
+
- Lifetime: `off` / `stopListening` / `iterate` + `AbortSignal`.
|
|
230
|
+
- Namespace scope: `namespaceDelimiter` + `wildcard`.
|
|
231
|
+
- Errors: `onError` centralizes listener failures.
|
|
232
|
+
|
|
233
|
+
### Semantics
|
|
234
|
+
|
|
235
|
+
- Dispatch order: event listeners, then matching patterns, then `"all"`.
|
|
236
|
+
- Listener lists are snapshotted at emit time; mutations during dispatch do not affect the current cycle.
|
|
237
|
+
- The `context` defaults to the emitter.
|
|
238
|
+
- Duplicate registrations are allowed.
|
|
239
|
+
- `"all"` is a compatibility feature (Backbone/Eventify style); it is not a standard `EventTarget` concept.
|
|
201
240
|
|
|
241
|
+
## API
|
|
242
|
+
|
|
243
|
+
### Preferred Named Exports
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
createEmitter([options]);
|
|
247
|
+
decorateWithEvents([target], [options]);
|
|
248
|
+
setDefaultSchemaValidator(schema, payload, meta);
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
`createEmitter` returns a standalone emitter. `decorateWithEvents` mixes Eventify methods into an existing object.
|
|
252
|
+
`setDefaultSchemaValidator` is the default validator function (no global mutation).
|
|
253
|
+
|
|
254
|
+
### Default Export (Compat)
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
Eventify.create([options]);
|
|
258
|
+
Eventify.enable([target], [options]);
|
|
259
|
+
Eventify.defaultSchemaValidator;
|
|
260
|
+
Eventify.version;
|
|
261
|
+
Eventify.proto;
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
The `Eventify` default export remains for compatibility.
|
|
265
|
+
|
|
266
|
+
### Options
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
type EventifyOptions = {
|
|
270
|
+
schemas?: Record<string, SchemaLike>;
|
|
271
|
+
validate?: SchemaValidator;
|
|
272
|
+
onError?: (
|
|
273
|
+
error: unknown,
|
|
274
|
+
meta: {
|
|
275
|
+
event: string;
|
|
276
|
+
args: unknown[];
|
|
277
|
+
listener?: (...args: unknown[]) => unknown;
|
|
278
|
+
emitter: object;
|
|
279
|
+
},
|
|
280
|
+
) => void;
|
|
281
|
+
namespaceDelimiter?: string; // default "/"
|
|
282
|
+
wildcard?: string; // default "*"
|
|
283
|
+
};
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Events
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
on(event, callback, [context])
|
|
290
|
+
on({ event: callback, ... }, [context])
|
|
291
|
+
on("a b c", callback, [context])
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
once(event, callback, [context])
|
|
296
|
+
once({ event: callback, ... }, [context])
|
|
297
|
+
once("a b c", callback, [context])
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
off()
|
|
302
|
+
off(event, [callback], [context])
|
|
303
|
+
off({ event: callback, ... }, [context])
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
trigger(event, ...args);
|
|
308
|
+
emit(event, ...args);
|
|
309
|
+
produce(event, ...args);
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
`emit` and `produce` are aliases of `trigger`.
|
|
313
|
+
|
|
314
|
+
### EventTarget Interop
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
addEventListener(type, listener, [options]);
|
|
318
|
+
removeEventListener(type, listener, [options]);
|
|
319
|
+
dispatchEvent(event);
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Cross-Emitter Listening
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
listenTo(other, event, callback)
|
|
326
|
+
listenTo(other, { event: callback, ... })
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
listenToOnce(other, event, callback)
|
|
331
|
+
listenToOnce(other, { event: callback, ... })
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
stopListening([other], [event], [callback]);
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Async Iteration
|
|
339
|
+
|
|
340
|
+
```ts
|
|
341
|
+
iterate(event, [options]);
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
For `"all"`, each value is `[eventName, ...args]`. For other events, a single argument is yielded as a value; multiple arguments are yielded as an array.
|
|
345
|
+
|
|
346
|
+
### Type Exports
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
EventMap;
|
|
350
|
+
EventName;
|
|
351
|
+
EventHandler;
|
|
352
|
+
EventHandlerMap;
|
|
353
|
+
SchemaLike;
|
|
354
|
+
SchemaMap;
|
|
355
|
+
SchemaValidator;
|
|
356
|
+
EventsFromSchemas;
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Benchmarks + Changelog
|
|
360
|
+
|
|
361
|
+
- `BENCHMARKS.md`
|
|
362
|
+
- `CHANGELOG.md`
|
|
363
|
+
|
|
364
|
+
## Development + Release
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
bun install
|
|
368
|
+
bun run format
|
|
369
|
+
bun test --coverage
|
|
370
|
+
bun run build:all
|
|
371
|
+
bunx playwright install --with-deps chromium
|
|
372
|
+
bun run test:browser
|
|
373
|
+
bun run test:all
|
|
374
|
+
bun run ci:local
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
bun run publish
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
`ci:local` requires `act` installed locally.
|
|
202
382
|
|
|
203
383
|
## License
|
|
204
384
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
Copyright (c) 2012 Bermi Ferrer <bermi@bermilabs.com>
|
|
208
|
-
|
|
209
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
|
210
|
-
a copy of this software and associated documentation files (the
|
|
211
|
-
'Software'), to deal in the Software without restriction, including
|
|
212
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
|
213
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
|
214
|
-
permit persons to whom the Software is furnished to do so, subject to
|
|
215
|
-
the following conditions:
|
|
216
|
-
|
|
217
|
-
The above copyright notice and this permission notice shall be
|
|
218
|
-
included in all copies or substantial portions of the Software.
|
|
219
|
-
|
|
220
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
221
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
222
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
223
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
224
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
225
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
226
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
385
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
export type EventMap = Record<string, unknown>;
|
|
2
|
+
export type PayloadArgs<T> = [T] extends [void] ? [] : [T] extends [undefined] ? [] : T extends readonly unknown[] ? T : [T];
|
|
3
|
+
export type PayloadValue<T> = T extends readonly unknown[] ? T : T;
|
|
4
|
+
export type EventName<Events extends EventMap> = Extract<keyof Events, string>;
|
|
5
|
+
export type EventHandler<T> = (...args: PayloadArgs<T>) => unknown;
|
|
6
|
+
export type AllHandler<Events extends EventMap> = (event: EventName<Events>, ...args: unknown[]) => unknown;
|
|
7
|
+
export type EventHandlerMap<Events extends EventMap> = {
|
|
8
|
+
[K in keyof Events]?: EventHandler<Events[K]>;
|
|
9
|
+
};
|
|
10
|
+
export type SchemaLike<T = unknown> = {
|
|
11
|
+
parse: (input: unknown) => T;
|
|
12
|
+
} | {
|
|
13
|
+
safeParse: (input: unknown) => {
|
|
14
|
+
success: true;
|
|
15
|
+
data: T;
|
|
16
|
+
} | {
|
|
17
|
+
success: false;
|
|
18
|
+
error: unknown;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export type SchemaMap = Record<string, SchemaLike>;
|
|
22
|
+
export type InferSchema<S> = S extends {
|
|
23
|
+
parse: (input: unknown) => infer T;
|
|
24
|
+
} ? T : S extends {
|
|
25
|
+
safeParse: (input: unknown) => {
|
|
26
|
+
success: true;
|
|
27
|
+
data: infer T;
|
|
28
|
+
};
|
|
29
|
+
} ? T : unknown;
|
|
30
|
+
export type EventsFromSchemas<TSchemas> = TSchemas extends SchemaMap ? {
|
|
31
|
+
[K in keyof TSchemas]: InferSchema<TSchemas[K]>;
|
|
32
|
+
} : EventMap;
|
|
33
|
+
export type ValidationMeta = {
|
|
34
|
+
event: string;
|
|
35
|
+
};
|
|
36
|
+
export type SchemaValidator<TSchema extends SchemaLike = SchemaLike> = (schema: TSchema, payload: unknown, meta: ValidationMeta) => unknown;
|
|
37
|
+
export type ErrorMeta<Events extends EventMap> = {
|
|
38
|
+
event: EventName<Events> | string;
|
|
39
|
+
args: unknown[];
|
|
40
|
+
listener?: (...args: unknown[]) => unknown;
|
|
41
|
+
emitter: object;
|
|
42
|
+
};
|
|
43
|
+
export type ErrorHandler<Events extends EventMap> = (error: unknown, meta: ErrorMeta<Events>) => void;
|
|
44
|
+
export type EventifyOptions<TSchemas extends SchemaMap | undefined = undefined, TEvents extends EventMap = EventMap> = {
|
|
45
|
+
schemas?: TSchemas;
|
|
46
|
+
validate?: SchemaValidator;
|
|
47
|
+
onError?: ErrorHandler<TEvents>;
|
|
48
|
+
namespaceDelimiter?: string;
|
|
49
|
+
wildcard?: string;
|
|
50
|
+
};
|
|
51
|
+
export type IterateOptions = {
|
|
52
|
+
signal?: AbortSignal;
|
|
53
|
+
};
|
|
54
|
+
export interface EventifyEmitter<Events extends EventMap = EventMap> {
|
|
55
|
+
addEventListener(type: string, listener: EventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions): void;
|
|
56
|
+
removeEventListener(type: string, listener: EventListenerOrEventListenerObject | null, options?: boolean | EventListenerOptions): void;
|
|
57
|
+
dispatchEvent(event: Event): boolean;
|
|
58
|
+
on<K extends EventName<Events>>(name: K, callback: EventHandler<Events[K]>, context?: unknown): this;
|
|
59
|
+
on(name: "all", callback: AllHandler<Events>, context?: unknown): this;
|
|
60
|
+
on(name: EventHandlerMap<Events>, context?: unknown): this;
|
|
61
|
+
on(name: string, callback?: (...args: unknown[]) => unknown, context?: unknown): this;
|
|
62
|
+
once<K extends EventName<Events>>(name: K, callback: EventHandler<Events[K]>, context?: unknown): this;
|
|
63
|
+
once(name: "all", callback: AllHandler<Events>, context?: unknown): this;
|
|
64
|
+
once(name: EventHandlerMap<Events>, context?: unknown): this;
|
|
65
|
+
once(name: string, callback?: (...args: unknown[]) => unknown, context?: unknown): this;
|
|
66
|
+
off(): this;
|
|
67
|
+
off<K extends EventName<Events>>(name: K, callback?: EventHandler<Events[K]> | null, context?: unknown): this;
|
|
68
|
+
off(name: EventHandlerMap<Events>, context?: unknown): this;
|
|
69
|
+
off(name?: string | null, callback?: ((...args: unknown[]) => unknown) | null, context?: unknown): this;
|
|
70
|
+
trigger<K extends EventName<Events>>(name: K, ...args: PayloadArgs<Events[K]>): this;
|
|
71
|
+
trigger(name: string, ...args: unknown[]): this;
|
|
72
|
+
emit<K extends EventName<Events>>(name: K, ...args: PayloadArgs<Events[K]>): this;
|
|
73
|
+
emit(name: string, ...args: unknown[]): this;
|
|
74
|
+
produce<K extends EventName<Events>>(name: K, ...args: PayloadArgs<Events[K]>): this;
|
|
75
|
+
produce(name: string, ...args: unknown[]): this;
|
|
76
|
+
listenTo<OtherEvents extends EventMap, K extends EventName<OtherEvents>>(other: EventifyEmitter<OtherEvents>, name: K, callback: EventHandler<OtherEvents[K]>): this;
|
|
77
|
+
listenTo<OtherEvents extends EventMap>(other: EventifyEmitter<OtherEvents>, name: EventHandlerMap<OtherEvents>): this;
|
|
78
|
+
listenTo(other: EventifyEmitter<EventMap>, name: string, callback?: (...args: unknown[]) => unknown): this;
|
|
79
|
+
listenToOnce<OtherEvents extends EventMap, K extends EventName<OtherEvents>>(other: EventifyEmitter<OtherEvents>, name: K, callback: EventHandler<OtherEvents[K]>): this;
|
|
80
|
+
listenToOnce<OtherEvents extends EventMap>(other: EventifyEmitter<OtherEvents>, name: EventHandlerMap<OtherEvents>): this;
|
|
81
|
+
listenToOnce(other: EventifyEmitter<EventMap>, name: string, callback?: (...args: unknown[]) => unknown): this;
|
|
82
|
+
stopListening<OtherEvents extends EventMap>(other?: EventifyEmitter<OtherEvents> | null, name?: EventName<OtherEvents> | EventHandlerMap<OtherEvents> | null, callback?: ((...args: unknown[]) => unknown) | null): this;
|
|
83
|
+
iterate<K extends EventName<Events>>(name: K, options?: IterateOptions): AsyncIterableIterator<PayloadValue<Events[K]>>;
|
|
84
|
+
iterate(name: "all", options?: IterateOptions): AsyncIterableIterator<[EventName<Events>, ...unknown[]]>;
|
|
85
|
+
iterate(name: string, options?: IterateOptions): AsyncIterableIterator<unknown>;
|
|
86
|
+
}
|
|
87
|
+
export interface EventifyStatic<Events extends EventMap = EventMap> extends EventifyEmitter<Events> {
|
|
88
|
+
version: string;
|
|
89
|
+
enable<TTarget extends object, TSchemas extends SchemaMap>(target: TTarget | undefined, options: EventifyOptions<TSchemas, EventsFromSchemas<TSchemas>> & {
|
|
90
|
+
schemas: TSchemas;
|
|
91
|
+
}): TTarget & EventifyEmitter<EventsFromSchemas<TSchemas>>;
|
|
92
|
+
enable<TTarget extends object, TEvents extends EventMap = EventMap, TSchemas extends SchemaMap | undefined = undefined>(target?: TTarget, options?: EventifyOptions<TSchemas, TEvents>): TTarget & EventifyEmitter<TEvents>;
|
|
93
|
+
create<TSchemas extends SchemaMap>(options: EventifyOptions<TSchemas, EventsFromSchemas<TSchemas>> & {
|
|
94
|
+
schemas: TSchemas;
|
|
95
|
+
}): EventifyEmitter<EventsFromSchemas<TSchemas>>;
|
|
96
|
+
create<TEvents extends EventMap = EventMap, TSchemas extends SchemaMap | undefined = undefined>(options?: EventifyOptions<TSchemas, TEvents>): EventifyEmitter<TEvents>;
|
|
97
|
+
mixin: EventifyStatic["enable"];
|
|
98
|
+
proto: EventifyEmitter<EventMap>;
|
|
99
|
+
noConflict: () => EventifyStatic<Events>;
|
|
100
|
+
defaultSchemaValidator: SchemaValidator;
|
|
101
|
+
}
|
|
102
|
+
export declare function defaultSchemaValidator(schema: SchemaLike, payload: unknown, _meta: ValidationMeta): unknown;
|
|
103
|
+
export declare function createEventify<TSchemas extends SchemaMap>(options: EventifyOptions<TSchemas, EventsFromSchemas<TSchemas>> & {
|
|
104
|
+
schemas: TSchemas;
|
|
105
|
+
}): EventifyEmitter<EventsFromSchemas<TSchemas>>;
|
|
106
|
+
export declare function createEventify<TEvents extends EventMap = EventMap, TSchemas extends SchemaMap | undefined = undefined>(options?: EventifyOptions<TSchemas, TEvents>): EventifyEmitter<TEvents>;
|
|
107
|
+
export declare function enable<TTarget extends object, TSchemas extends SchemaMap>(target: TTarget | undefined, options: EventifyOptions<TSchemas, EventsFromSchemas<TSchemas>> & {
|
|
108
|
+
schemas: TSchemas;
|
|
109
|
+
}): TTarget & EventifyEmitter<EventsFromSchemas<TSchemas>>;
|
|
110
|
+
export declare function enable<TTarget extends object, TEvents extends EventMap = EventMap, TSchemas extends SchemaMap | undefined = undefined>(target?: TTarget, options?: EventifyOptions<TSchemas, TEvents>): TTarget & EventifyEmitter<TEvents>;
|
|
111
|
+
declare const Eventify: EventifyStatic;
|
|
112
|
+
declare const createEmitter: typeof createEventify;
|
|
113
|
+
declare const decorateWithEvents: typeof enable;
|
|
114
|
+
declare const setDefaultSchemaValidator: typeof defaultSchemaValidator;
|
|
115
|
+
export { Eventify, createEmitter, decorateWithEvents, setDefaultSchemaValidator, };
|
|
116
|
+
export default Eventify;
|
|
117
|
+
//# sourceMappingURL=index.d.ts.map
|