@tyravel/events 0.1.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.
Files changed (57) hide show
  1. package/dist/call-queued-listener.d.ts +10 -0
  2. package/dist/call-queued-listener.d.ts.map +1 -0
  3. package/dist/call-queued-listener.js +17 -0
  4. package/dist/call-queued-listener.js.map +1 -0
  5. package/dist/call-queued-listener.test.d.ts +2 -0
  6. package/dist/call-queued-listener.test.d.ts.map +1 -0
  7. package/dist/call-queued-listener.test.js +36 -0
  8. package/dist/call-queued-listener.test.js.map +1 -0
  9. package/dist/dispatcher-options.d.ts +21 -0
  10. package/dist/dispatcher-options.d.ts.map +1 -0
  11. package/dist/dispatcher-options.js +2 -0
  12. package/dist/dispatcher-options.js.map +1 -0
  13. package/dist/event-dispatcher.d.ts +26 -0
  14. package/dist/event-dispatcher.d.ts.map +1 -0
  15. package/dist/event-dispatcher.js +107 -0
  16. package/dist/event-dispatcher.js.map +1 -0
  17. package/dist/event-dispatcher.test.d.ts +2 -0
  18. package/dist/event-dispatcher.test.d.ts.map +1 -0
  19. package/dist/event-dispatcher.test.js +64 -0
  20. package/dist/event-dispatcher.test.js.map +1 -0
  21. package/dist/event-registry.d.ts +13 -0
  22. package/dist/event-registry.d.ts.map +1 -0
  23. package/dist/event-registry.js +28 -0
  24. package/dist/event-registry.js.map +1 -0
  25. package/dist/event-subscribers.test.d.ts +2 -0
  26. package/dist/event-subscribers.test.d.ts.map +1 -0
  27. package/dist/event-subscribers.test.js +38 -0
  28. package/dist/event-subscribers.test.js.map +1 -0
  29. package/dist/index.d.ts +17 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +13 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/listener-registry.d.ts +12 -0
  34. package/dist/listener-registry.d.ts.map +1 -0
  35. package/dist/listener-registry.js +28 -0
  36. package/dist/listener-registry.js.map +1 -0
  37. package/dist/queued-listener-context.d.ts +12 -0
  38. package/dist/queued-listener-context.d.ts.map +1 -0
  39. package/dist/queued-listener-context.js +14 -0
  40. package/dist/queued-listener-context.js.map +1 -0
  41. package/dist/queued-listeners.test.d.ts +2 -0
  42. package/dist/queued-listeners.test.d.ts.map +1 -0
  43. package/dist/queued-listeners.test.js +57 -0
  44. package/dist/queued-listeners.test.js.map +1 -0
  45. package/dist/should-queue.d.ts +35 -0
  46. package/dist/should-queue.d.ts.map +1 -0
  47. package/dist/should-queue.js +30 -0
  48. package/dist/should-queue.js.map +1 -0
  49. package/dist/subscribers.d.ts +8 -0
  50. package/dist/subscribers.d.ts.map +1 -0
  51. package/dist/subscribers.js +20 -0
  52. package/dist/subscribers.js.map +1 -0
  53. package/dist/types.d.ts +32 -0
  54. package/dist/types.d.ts.map +1 -0
  55. package/dist/types.js +12 -0
  56. package/dist/types.js.map +1 -0
  57. package/package.json +40 -0
@@ -0,0 +1,10 @@
1
+ import { Job } from '@tyravel/queue';
2
+ export interface CallQueuedListenerData extends Record<string, unknown> {
3
+ listener: string;
4
+ event: string;
5
+ eventData: Record<string, unknown>;
6
+ }
7
+ export declare class CallQueuedListener extends Job<CallQueuedListenerData> {
8
+ handle(): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=call-queued-listener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call-queued-listener.d.ts","sourceRoot":"","sources":["../src/call-queued-listener.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAGrC,MAAM,WAAW,sBAAuB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,qBAAa,kBAAmB,SAAQ,GAAG,CAAC,sBAAsB,CAAC;IAClD,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAkBvC"}
@@ -0,0 +1,17 @@
1
+ import { Job } from '@tyravel/queue';
2
+ import { getQueuedListenerContext } from './queued-listener-context.js';
3
+ export class CallQueuedListener extends Job {
4
+ async handle() {
5
+ const context = getQueuedListenerContext();
6
+ const event = context.events.create(this.data.event, this.data.eventData);
7
+ const ListenerClass = context.listeners.resolve(this.data.listener);
8
+ if (context.container) {
9
+ const instance = context.container.make(ListenerClass);
10
+ await instance.handle(event);
11
+ return;
12
+ }
13
+ const instance = context.listeners.create(this.data.listener);
14
+ await instance.handle(event);
15
+ }
16
+ }
17
+ //# sourceMappingURL=call-queued-listener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call-queued-listener.js","sourceRoot":"","sources":["../src/call-queued-listener.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAQxE,MAAM,OAAO,kBAAmB,SAAQ,GAA2B;IACxD,KAAK,CAAC,MAAM;QACnB,MAAM,OAAO,GAAG,wBAAwB,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1E,MAAM,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEpE,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,CACrC,aAEC,CACF,CAAC;YACF,MAAM,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9D,MAAM,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=call-queued-listener.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call-queued-listener.test.d.ts","sourceRoot":"","sources":["../src/call-queued-listener.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,36 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { Container } from '@tyravel/container';
3
+ import { JobRegistry, QueueWorker } from '@tyravel/queue';
4
+ import { CallQueuedListener, Event, EventRegistry, ListenerRegistry, QueuedListener, setQueuedListenerContext, } from './index.js';
5
+ class InvoicePaid extends Event {
6
+ }
7
+ class RecordPayment extends QueuedListener {
8
+ static calls = [];
9
+ async handle(event) {
10
+ RecordPayment.calls.push(event.data.invoiceId);
11
+ }
12
+ }
13
+ describe('CallQueuedListener job', () => {
14
+ it('rehydrates the event and invokes the listener when processed', async () => {
15
+ RecordPayment.calls = [];
16
+ const events = new EventRegistry();
17
+ events.register(InvoicePaid);
18
+ const listeners = new ListenerRegistry();
19
+ listeners.register(RecordPayment);
20
+ const container = new Container();
21
+ setQueuedListenerContext({ container, events, listeners });
22
+ const registry = new JobRegistry();
23
+ registry.register(CallQueuedListener);
24
+ const worker = new QueueWorker(registry, container);
25
+ await worker.process({
26
+ job: 'CallQueuedListener',
27
+ data: {
28
+ listener: 'RecordPayment',
29
+ event: 'InvoicePaid',
30
+ eventData: { invoiceId: 9001 },
31
+ },
32
+ });
33
+ expect(RecordPayment.calls).toEqual([9001]);
34
+ });
35
+ });
36
+ //# sourceMappingURL=call-queued-listener.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call-queued-listener.test.js","sourceRoot":"","sources":["../src/call-queued-listener.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EACL,kBAAkB,EAClB,KAAK,EACL,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,wBAAwB,GACzB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAY,SAAQ,KAA4B;CAAG;AAEzD,MAAM,aAAc,SAAQ,cAA2B;IACrD,MAAM,CAAC,KAAK,GAAa,EAAE,CAAC;IAEnB,KAAK,CAAC,MAAM,CAAC,KAAkB;QACtC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACjD,CAAC;;AAGH,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,aAAa,CAAC,KAAK,GAAG,EAAE,CAAC;QAEzB,MAAM,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QACnC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC7B,MAAM,SAAS,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACzC,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAElC,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;QAClC,wBAAwB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAE3D,MAAM,QAAQ,GAAG,IAAI,WAAW,EAAE,CAAC;QACnC,QAAQ,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACpD,MAAM,MAAM,CAAC,OAAO,CAAC;YACnB,GAAG,EAAE,oBAAoB;YACzB,IAAI,EAAE;gBACJ,QAAQ,EAAE,eAAe;gBACzB,KAAK,EAAE,aAAa;gBACpB,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aAC/B;SACF,CAAC,CAAC;QAEH,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { Job } from '@tyravel/queue';
2
+ import type { EventRegistry } from './event-registry.js';
3
+ import type { ListenerRegistry } from './listener-registry.js';
4
+ import type { QueuedListenerMetadata } from './should-queue.js';
5
+ export interface QueuedListenerBridge {
6
+ dispatch(job: Job, options: {
7
+ connection: string;
8
+ queue: string;
9
+ delaySeconds: number;
10
+ }): Promise<void>;
11
+ }
12
+ export interface EventDispatcherOptions {
13
+ container?: import('@tyravel/container').Container;
14
+ eventRegistry?: EventRegistry;
15
+ listenerRegistry?: ListenerRegistry;
16
+ queue?: QueuedListenerBridge;
17
+ queueDefaults?: QueuedListenerMetadata & {
18
+ connection?: string;
19
+ };
20
+ }
21
+ //# sourceMappingURL=dispatcher-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher-options.d.ts","sourceRoot":"","sources":["../src/dispatcher-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEhE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CACN,GAAG,EAAE,GAAG,EACR,OAAO,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GACnE,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,OAAO,oBAAoB,EAAE,SAAS,CAAC;IACnD,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,aAAa,CAAC,EAAE,sBAAsB,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAClE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=dispatcher-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher-options.js","sourceRoot":"","sources":["../src/dispatcher-options.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ import type { EventDispatcherOptions } from './dispatcher-options.js';
2
+ import type { Event } from './types.js';
3
+ import { type EventConstructor, type ListenerHandler } from './types.js';
4
+ export declare class EventDispatcher {
5
+ private readonly listeners;
6
+ private readonly container?;
7
+ private readonly eventRegistry?;
8
+ private readonly listenerRegistry?;
9
+ private readonly queue?;
10
+ private queueDefaults;
11
+ constructor(options?: EventDispatcherOptions);
12
+ listen<TEvent extends Event>(event: EventConstructor<TEvent>, handler: ListenerHandler<TEvent>): this;
13
+ listenMany(event: EventConstructor, handlers: ListenerHandler[]): this;
14
+ hasListeners(event: EventConstructor | Event): boolean;
15
+ dispatch<TEvent extends Event>(event: TEvent): Promise<void>;
16
+ dispatchUntil<TEvent extends Event>(event: TEvent, predicate: (event: TEvent) => boolean): Promise<boolean>;
17
+ forget(event: EventConstructor): this;
18
+ flush(): this;
19
+ setQueueDefaults(defaults: EventDispatcherOptions['queueDefaults']): this;
20
+ private invokeHandler;
21
+ private queueListener;
22
+ private resolveListener;
23
+ private isListenerCallback;
24
+ private isListenerClass;
25
+ }
26
+ //# sourceMappingURL=event-dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-dispatcher.d.ts","sourceRoot":"","sources":["../src/event-dispatcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EACL,KAAK,gBAAgB,EAIrB,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAMpB,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;IAClE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAY;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAmB;IACrD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAkC;IACzD,OAAO,CAAC,aAAa,CAA0C;gBAEnD,OAAO,GAAE,sBAA2B;IAQhD,MAAM,CAAC,MAAM,SAAS,KAAK,EACzB,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAC/B,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,GAC/B,IAAI;IAaP,UAAU,CACR,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,eAAe,EAAE,GAC1B,IAAI;IAOP,YAAY,CAAC,KAAK,EAAE,gBAAgB,GAAG,KAAK,GAAG,OAAO;IAKhD,QAAQ,CAAC,MAAM,SAAS,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5D,aAAa,CAAC,MAAM,SAAS,KAAK,EACtC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GACpC,OAAO,CAAC,OAAO,CAAC;IAcnB,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAKrC,KAAK,IAAI,IAAI;IAKb,gBAAgB,CAAC,QAAQ,EAAE,sBAAsB,CAAC,eAAe,CAAC,GAAG,IAAI;YAQ3D,aAAa;YAkBb,aAAa;IAmB3B,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,eAAe;CAQxB"}
@@ -0,0 +1,107 @@
1
+ import { buildCallQueuedListenerJob, listenerShouldQueue, } from './should-queue.js';
2
+ export class EventDispatcher {
3
+ listeners = new Map();
4
+ container;
5
+ eventRegistry;
6
+ listenerRegistry;
7
+ queue;
8
+ queueDefaults;
9
+ constructor(options = {}) {
10
+ this.container = options.container;
11
+ this.eventRegistry = options.eventRegistry;
12
+ this.listenerRegistry = options.listenerRegistry;
13
+ this.queue = options.queue;
14
+ this.queueDefaults = options.queueDefaults;
15
+ }
16
+ listen(event, handler) {
17
+ this.eventRegistry?.register(event);
18
+ if (this.isListenerClass(handler)) {
19
+ this.listenerRegistry?.register(handler);
20
+ }
21
+ const key = event.name;
22
+ const existing = this.listeners.get(key) ?? [];
23
+ existing.push(handler);
24
+ this.listeners.set(key, existing);
25
+ return this;
26
+ }
27
+ listenMany(event, handlers) {
28
+ for (const handler of handlers) {
29
+ this.listen(event, handler);
30
+ }
31
+ return this;
32
+ }
33
+ hasListeners(event) {
34
+ const key = typeof event === 'function' ? event.name : event.constructor.name;
35
+ return (this.listeners.get(key)?.length ?? 0) > 0;
36
+ }
37
+ async dispatch(event) {
38
+ const key = event.constructor.name;
39
+ const handlers = this.listeners.get(key) ?? [];
40
+ for (const handler of handlers) {
41
+ await this.invokeHandler(handler, event);
42
+ }
43
+ }
44
+ async dispatchUntil(event, predicate) {
45
+ const key = event.constructor.name;
46
+ const handlers = this.listeners.get(key) ?? [];
47
+ for (const handler of handlers) {
48
+ await this.invokeHandler(handler, event);
49
+ if (predicate(event)) {
50
+ return true;
51
+ }
52
+ }
53
+ return false;
54
+ }
55
+ forget(event) {
56
+ this.listeners.delete(event.name);
57
+ return this;
58
+ }
59
+ flush() {
60
+ this.listeners.clear();
61
+ return this;
62
+ }
63
+ setQueueDefaults(defaults) {
64
+ this.queueDefaults = {
65
+ ...this.queueDefaults,
66
+ ...defaults,
67
+ };
68
+ return this;
69
+ }
70
+ async invokeHandler(handler, event) {
71
+ if (this.isListenerClass(handler) && listenerShouldQueue(handler)) {
72
+ await this.queueListener(handler, event);
73
+ return;
74
+ }
75
+ if (this.isListenerCallback(handler)) {
76
+ await handler(event);
77
+ return;
78
+ }
79
+ const instance = this.resolveListener(handler);
80
+ await instance.handle(event);
81
+ }
82
+ async queueListener(constructor, event) {
83
+ if (!this.queue) {
84
+ throw new Error(`Listener ${constructor.name} is queued but no queue bridge is configured. Register QueueServiceProvider before EventServiceProvider.`);
85
+ }
86
+ const { job, metadata } = buildCallQueuedListenerJob(constructor, event, this.queueDefaults);
87
+ await this.queue.dispatch(job, metadata);
88
+ }
89
+ resolveListener(constructor) {
90
+ if (this.container && this.isListenerClass(constructor)) {
91
+ return this.container.make(constructor);
92
+ }
93
+ if (this.isListenerClass(constructor)) {
94
+ return new constructor();
95
+ }
96
+ throw new Error('Invalid event listener handler.');
97
+ }
98
+ isListenerCallback(handler) {
99
+ return (typeof handler === 'function' &&
100
+ (!('prototype' in handler) || typeof handler.prototype?.handle !== 'function'));
101
+ }
102
+ isListenerClass(handler) {
103
+ return (typeof handler === 'function' &&
104
+ typeof handler.prototype?.handle === 'function');
105
+ }
106
+ }
107
+ //# sourceMappingURL=event-dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-dispatcher.js","sourceRoot":"","sources":["../src/event-dispatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=event-dispatcher.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-dispatcher.test.d.ts","sourceRoot":"","sources":["../src/event-dispatcher.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,64 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { Container } from '@tyravel/container';
3
+ import { EventDispatcher } from './event-dispatcher.js';
4
+ import { Event, Listener } from './types.js';
5
+ class UserRegistered extends Event {
6
+ }
7
+ class LogUserRegistered extends Listener {
8
+ static calls = [];
9
+ async handle(event) {
10
+ LogUserRegistered.calls.push(event);
11
+ }
12
+ }
13
+ describe('EventDispatcher', () => {
14
+ it('dispatches to class-based listeners', async () => {
15
+ LogUserRegistered.calls = [];
16
+ const dispatcher = new EventDispatcher();
17
+ dispatcher.listen(UserRegistered, LogUserRegistered);
18
+ const event = new UserRegistered({ userId: 42 });
19
+ await dispatcher.dispatch(event);
20
+ expect(LogUserRegistered.calls).toHaveLength(1);
21
+ expect(LogUserRegistered.calls[0]?.data.userId).toBe(42);
22
+ });
23
+ it('dispatches to inline listener callbacks', async () => {
24
+ const handler = vi.fn();
25
+ const dispatcher = new EventDispatcher();
26
+ dispatcher.listen(UserRegistered, handler);
27
+ await dispatcher.dispatch(new UserRegistered({ userId: 7 }));
28
+ expect(handler).toHaveBeenCalledOnce();
29
+ expect(handler.mock.calls[0]?.[0]?.data.userId).toBe(7);
30
+ });
31
+ it('resolves listeners from the container when available', async () => {
32
+ class CounterListener extends Listener {
33
+ label;
34
+ constructor(label) {
35
+ super();
36
+ this.label = label;
37
+ }
38
+ async handle() {
39
+ //
40
+ }
41
+ }
42
+ const container = new Container();
43
+ container.singleton(CounterListener, () => new CounterListener('from-container'));
44
+ const dispatcher = new EventDispatcher({ container });
45
+ dispatcher.listen(UserRegistered, CounterListener);
46
+ const instance = container.make(CounterListener);
47
+ const handleSpy = vi.spyOn(instance, 'handle');
48
+ await dispatcher.dispatch(new UserRegistered({ userId: 1 }));
49
+ expect(handleSpy).toHaveBeenCalledOnce();
50
+ });
51
+ it('stops early when dispatchUntil predicate matches', async () => {
52
+ const first = vi.fn();
53
+ const second = vi.fn();
54
+ const dispatcher = new EventDispatcher();
55
+ dispatcher.listen(UserRegistered, first);
56
+ dispatcher.listen(UserRegistered, second);
57
+ const event = new UserRegistered({ userId: 99 });
58
+ const stopped = await dispatcher.dispatchUntil(event, (e) => e.data.userId === 99);
59
+ expect(stopped).toBe(true);
60
+ expect(first).toHaveBeenCalledOnce();
61
+ expect(second).not.toHaveBeenCalled();
62
+ });
63
+ });
64
+ //# sourceMappingURL=event-dispatcher.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-dispatcher.test.js","sourceRoot":"","sources":["../src/event-dispatcher.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Event } from './types.js';
2
+ import type { EventConstructor } from './types.js';
3
+ export declare class EventNotFoundException extends Error {
4
+ constructor(name: string);
5
+ }
6
+ export declare class EventRegistry {
7
+ private readonly events;
8
+ register(constructor: EventConstructor): this;
9
+ has(name: string): boolean;
10
+ resolve(name: string): EventConstructor;
11
+ create(name: string, data: Record<string, unknown>): Event;
12
+ }
13
+ //# sourceMappingURL=event-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-registry.d.ts","sourceRoot":"","sources":["../src/event-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,IAAI,EAAE,MAAM;CAIzB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuC;IAE9D,QAAQ,CAAC,WAAW,EAAE,gBAAgB,GAAG,IAAI;IAK7C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB;IAQvC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK;CAI3D"}
@@ -0,0 +1,28 @@
1
+ export class EventNotFoundException extends Error {
2
+ constructor(name) {
3
+ super(`Event class not registered: ${name}`);
4
+ this.name = 'EventNotFoundException';
5
+ }
6
+ }
7
+ export class EventRegistry {
8
+ events = new Map();
9
+ register(constructor) {
10
+ this.events.set(constructor.name, constructor);
11
+ return this;
12
+ }
13
+ has(name) {
14
+ return this.events.has(name);
15
+ }
16
+ resolve(name) {
17
+ const constructor = this.events.get(name);
18
+ if (!constructor) {
19
+ throw new EventNotFoundException(name);
20
+ }
21
+ return constructor;
22
+ }
23
+ create(name, data) {
24
+ const constructor = this.resolve(name);
25
+ return new constructor(data);
26
+ }
27
+ }
28
+ //# sourceMappingURL=event-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-registry.js","sourceRoot":"","sources":["../src/event-registry.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC/C,YAAY,IAAY;QACtB,KAAK,CAAC,+BAA+B,IAAI,EAAE,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AAED,MAAM,OAAO,aAAa;IACP,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;IAE9D,QAAQ,CAAC,WAA6B;QACpC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,CAAC,IAAY;QAClB,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,MAAM,CAAC,IAAY,EAAE,IAA6B;QAChD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=event-subscribers.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-subscribers.test.d.ts","sourceRoot":"","sources":["../src/event-subscribers.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,38 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { Container } from '@tyravel/container';
3
+ import { EventDispatcher } from './event-dispatcher.js';
4
+ import { Event, Listener } from './types.js';
5
+ import { EventSubscriber } from './types.js';
6
+ import { registerEventSubscribers } from './subscribers.js';
7
+ class UserSignedUp extends Event {
8
+ }
9
+ class LogSignup extends Listener {
10
+ static calls = [];
11
+ async handle(event) {
12
+ LogSignup.calls.push(event.data.userId);
13
+ }
14
+ }
15
+ class AuthEventSubscriber extends EventSubscriber {
16
+ subscribe(dispatcher) {
17
+ dispatcher.listen(UserSignedUp, LogSignup);
18
+ }
19
+ }
20
+ describe('event subscribers', () => {
21
+ it('registers listeners via subscribe()', async () => {
22
+ LogSignup.calls = [];
23
+ const dispatcher = new EventDispatcher();
24
+ registerEventSubscribers(dispatcher, [AuthEventSubscriber]);
25
+ await dispatcher.dispatch(new UserSignedUp({ userId: 42 }));
26
+ expect(LogSignup.calls).toEqual([42]);
27
+ });
28
+ it('resolves subscriber from the container when provided', async () => {
29
+ LogSignup.calls = [];
30
+ const container = new Container();
31
+ container.singleton(AuthEventSubscriber, () => new AuthEventSubscriber());
32
+ const dispatcher = new EventDispatcher({ container });
33
+ registerEventSubscribers(dispatcher, [AuthEventSubscriber], container);
34
+ await dispatcher.dispatch(new UserSignedUp({ userId: 7 }));
35
+ expect(LogSignup.calls).toEqual([7]);
36
+ });
37
+ });
38
+ //# sourceMappingURL=event-subscribers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-subscribers.test.js","sourceRoot":"","sources":["../src/event-subscribers.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,MAAM,YAAa,SAAQ,KAAyB;CAAG;AAEvD,MAAM,SAAU,SAAQ,QAAsB;IAC5C,MAAM,CAAC,KAAK,GAAa,EAAE,CAAC;IAEnB,KAAK,CAAC,MAAM,CAAC,KAAmB;QACvC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC;;AAGH,MAAM,mBAAoB,SAAQ,eAAe;IAC/C,SAAS,CAAC,UAA2B;QACnC,UAAU,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IAC7C,CAAC;CACF;AAED,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,SAAS,CAAC,KAAK,GAAG,EAAE,CAAC;QACrB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,wBAAwB,CAAC,UAAU,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC;QAE5D,MAAM,UAAU,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAC5D,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,SAAS,CAAC,KAAK,GAAG,EAAE,CAAC;QACrB,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;QAClC,SAAS,CAAC,SAAS,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,EAAE,CAAC,CAAC;QAE1E,MAAM,UAAU,GAAG,IAAI,eAAe,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;QACtD,wBAAwB,CAAC,UAAU,EAAE,CAAC,mBAAmB,CAAC,EAAE,SAAS,CAAC,CAAC;QAEvE,MAAM,UAAU,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3D,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { EventDispatcher } from './event-dispatcher.js';
2
+ export declare function createEventDispatcher(options?: import('./dispatcher-options.js').EventDispatcherOptions): EventDispatcher;
3
+ export { CallQueuedListener } from './call-queued-listener.js';
4
+ export type { CallQueuedListenerData } from './call-queued-listener.js';
5
+ export { EventDispatcher } from './event-dispatcher.js';
6
+ export { EventRegistry } from './event-registry.js';
7
+ export { ListenerRegistry } from './listener-registry.js';
8
+ export { clearQueuedListenerContext, getQueuedListenerContext, setQueuedListenerContext, } from './queued-listener-context.js';
9
+ export type { QueuedListenerContext } from './queued-listener-context.js';
10
+ export { registerEventListeners, registerEventSubscribers, registerEventsConfig, } from './subscribers.js';
11
+ export { QueuedListener, buildCallQueuedListenerJob, listenerShouldQueue, resolveQueuedListenerMetadata, } from './should-queue.js';
12
+ export type { QueuedListenerBridge, } from './dispatcher-options.js';
13
+ export type { EventDispatcherOptions } from './dispatcher-options.js';
14
+ export { Event, EventSubscriber, Listener } from './types.js';
15
+ export type { EventConstructor, EventListenerRegistration, EventSubscriberConstructor, EventsConfig, ListenerCallback, ListenerConstructor, ListenerContract, ListenerHandler, ShouldQueue, } from './types.js';
16
+ export type { QueuedListenerConstructor, QueuedListenerMetadata, } from './should-queue.js';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAOxD,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,OAAO,yBAAyB,EAAE,sBAA2B,GACrE,eAAe,CAEjB;AAED,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,cAAc,EACd,0BAA0B,EAC1B,mBAAmB,EACnB,6BAA6B,GAC9B,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC9D,YAAY,EACV,gBAAgB,EAChB,yBAAyB,EACzB,0BAA0B,EAC1B,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ import { EventDispatcher } from './event-dispatcher.js';
2
+ export function createEventDispatcher(options = {}) {
3
+ return new EventDispatcher(options);
4
+ }
5
+ export { CallQueuedListener } from './call-queued-listener.js';
6
+ export { EventDispatcher } from './event-dispatcher.js';
7
+ export { EventRegistry } from './event-registry.js';
8
+ export { ListenerRegistry } from './listener-registry.js';
9
+ export { clearQueuedListenerContext, getQueuedListenerContext, setQueuedListenerContext, } from './queued-listener-context.js';
10
+ export { registerEventListeners, registerEventSubscribers, registerEventsConfig, } from './subscribers.js';
11
+ export { QueuedListener, buildCallQueuedListenerJob, listenerShouldQueue, resolveQueuedListenerMetadata, } from './should-queue.js';
12
+ export { Event, EventSubscriber, Listener } from './types.js';
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAOxD,MAAM,UAAU,qBAAqB,CACnC,UAAoE,EAAE;IAEtE,OAAO,IAAI,eAAe,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC;AAED,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,cAAc,EACd,0BAA0B,EAC1B,mBAAmB,EACnB,6BAA6B,GAC9B,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ListenerConstructor, ListenerContract } from './types.js';
2
+ export declare class ListenerNotFoundException extends Error {
3
+ constructor(name: string);
4
+ }
5
+ export declare class ListenerRegistry {
6
+ private readonly listeners;
7
+ register(constructor: ListenerConstructor): this;
8
+ has(name: string): boolean;
9
+ resolve(name: string): ListenerConstructor;
10
+ create(name: string): ListenerContract;
11
+ }
12
+ //# sourceMappingURL=listener-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listener-registry.d.ts","sourceRoot":"","sources":["../src/listener-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAExE,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,IAAI,EAAE,MAAM;CAIzB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0C;IAEpE,QAAQ,CAAC,WAAW,EAAE,mBAAmB,GAAG,IAAI;IAKhD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB;IAQ1C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB;CAIvC"}
@@ -0,0 +1,28 @@
1
+ export class ListenerNotFoundException extends Error {
2
+ constructor(name) {
3
+ super(`Listener class not registered: ${name}`);
4
+ this.name = 'ListenerNotFoundException';
5
+ }
6
+ }
7
+ export class ListenerRegistry {
8
+ listeners = new Map();
9
+ register(constructor) {
10
+ this.listeners.set(constructor.name, constructor);
11
+ return this;
12
+ }
13
+ has(name) {
14
+ return this.listeners.has(name);
15
+ }
16
+ resolve(name) {
17
+ const constructor = this.listeners.get(name);
18
+ if (!constructor) {
19
+ throw new ListenerNotFoundException(name);
20
+ }
21
+ return constructor;
22
+ }
23
+ create(name) {
24
+ const constructor = this.resolve(name);
25
+ return new constructor();
26
+ }
27
+ }
28
+ //# sourceMappingURL=listener-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listener-registry.js","sourceRoot":"","sources":["../src/listener-registry.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAClD,YAAY,IAAY;QACtB,KAAK,CAAC,kCAAkC,IAAI,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,OAAO,gBAAgB;IACV,SAAS,GAAG,IAAI,GAAG,EAA+B,CAAC;IAEpE,QAAQ,CAAC,WAAgC;QACvC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,CAAC,IAAY;QAClB,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,yBAAyB,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,MAAM,CAAC,IAAY;QACjB,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,IAAI,WAAW,EAAE,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ import type { Container } from '@tyravel/container';
2
+ import type { EventRegistry } from './event-registry.js';
3
+ import type { ListenerRegistry } from './listener-registry.js';
4
+ export interface QueuedListenerContext {
5
+ container?: Container;
6
+ events: EventRegistry;
7
+ listeners: ListenerRegistry;
8
+ }
9
+ export declare function setQueuedListenerContext(context: QueuedListenerContext): void;
10
+ export declare function getQueuedListenerContext(): QueuedListenerContext;
11
+ export declare function clearQueuedListenerContext(): void;
12
+ //# sourceMappingURL=queued-listener-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queued-listener-context.d.ts","sourceRoot":"","sources":["../src/queued-listener-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,gBAAgB,CAAC;CAC7B;AAID,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAE7E;AAED,wBAAgB,wBAAwB,IAAI,qBAAqB,CAOhE;AAED,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}
@@ -0,0 +1,14 @@
1
+ let activeContext;
2
+ export function setQueuedListenerContext(context) {
3
+ activeContext = context;
4
+ }
5
+ export function getQueuedListenerContext() {
6
+ if (!activeContext) {
7
+ throw new Error('Queued listener context is not configured. Register EventServiceProvider before processing CallQueuedListener jobs.');
8
+ }
9
+ return activeContext;
10
+ }
11
+ export function clearQueuedListenerContext() {
12
+ activeContext = undefined;
13
+ }
14
+ //# sourceMappingURL=queued-listener-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queued-listener-context.js","sourceRoot":"","sources":["../src/queued-listener-context.ts"],"names":[],"mappings":"AAUA,IAAI,aAAgD,CAAC;AAErD,MAAM,UAAU,wBAAwB,CAAC,OAA8B;IACrE,aAAa,GAAG,OAAO,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,qHAAqH,CACtH,CAAC;IACJ,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,aAAa,GAAG,SAAS,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=queued-listeners.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queued-listeners.test.d.ts","sourceRoot":"","sources":["../src/queued-listeners.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { EventDispatcher } from './event-dispatcher.js';
3
+ import { EventRegistry } from './event-registry.js';
4
+ import { ListenerRegistry } from './listener-registry.js';
5
+ import { Event, Listener } from './types.js';
6
+ import { QueuedListener } from './should-queue.js';
7
+ class OrderPlaced extends Event {
8
+ }
9
+ class SyncAudit extends Listener {
10
+ static handled = [];
11
+ async handle(event) {
12
+ SyncAudit.handled.push(event.data.orderId);
13
+ }
14
+ }
15
+ class QueuedNotify extends QueuedListener {
16
+ static handled = [];
17
+ async handle(event) {
18
+ QueuedNotify.handled.push(event.data.orderId);
19
+ }
20
+ }
21
+ describe('queued listeners', () => {
22
+ it('pushes CallQueuedListener jobs instead of running synchronously', async () => {
23
+ SyncAudit.handled = [];
24
+ QueuedNotify.handled = [];
25
+ const queuedJobs = [];
26
+ const events = new EventRegistry();
27
+ const listeners = new ListenerRegistry();
28
+ const dispatcher = new EventDispatcher({
29
+ eventRegistry: events,
30
+ listenerRegistry: listeners,
31
+ queue: {
32
+ dispatch: async (job) => {
33
+ queuedJobs.push(job);
34
+ },
35
+ },
36
+ queueDefaults: { connection: 'sync', queue: 'events' },
37
+ });
38
+ dispatcher.listen(OrderPlaced, SyncAudit);
39
+ dispatcher.listen(OrderPlaced, QueuedNotify);
40
+ await dispatcher.dispatch(new OrderPlaced({ orderId: 'ord_1' }));
41
+ expect(SyncAudit.handled).toEqual(['ord_1']);
42
+ expect(QueuedNotify.handled).toEqual([]);
43
+ expect(queuedJobs).toHaveLength(1);
44
+ expect(queuedJobs[0]?.jobName()).toBe('CallQueuedListener');
45
+ expect(queuedJobs[0]?.data).toMatchObject({
46
+ listener: 'QueuedNotify',
47
+ event: 'OrderPlaced',
48
+ eventData: { orderId: 'ord_1' },
49
+ });
50
+ });
51
+ it('throws when a queued listener is used without a queue bridge', async () => {
52
+ const dispatcher = new EventDispatcher();
53
+ dispatcher.listen(OrderPlaced, QueuedNotify);
54
+ await expect(dispatcher.dispatch(new OrderPlaced({ orderId: 'x' }))).rejects.toThrow(/queue bridge/i);
55
+ });
56
+ });
57
+ //# sourceMappingURL=queued-listeners.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queued-listeners.test.js","sourceRoot":"","sources":["../src/queued-listeners.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { Job } from '@tyravel/queue';
2
+ import type { Event } from './types.js';
3
+ import { Listener } from './types.js';
4
+ import type { ListenerConstructor } from './types.js';
5
+ import type { ShouldQueue } from './types.js';
6
+ export interface QueuedListenerMetadata {
7
+ connection?: string;
8
+ queue?: string;
9
+ delaySeconds?: number;
10
+ }
11
+ export type QueuedListenerConstructor = ListenerConstructor & {
12
+ shouldQueue: true;
13
+ } & QueuedListenerMetadata;
14
+ export declare abstract class QueuedListener<TEvent extends Event = Event> extends Listener<TEvent> implements ShouldQueue {
15
+ readonly shouldQueue: true;
16
+ static shouldQueue: true;
17
+ static connection?: string;
18
+ static queue?: string;
19
+ static delaySeconds?: number;
20
+ }
21
+ export declare function listenerShouldQueue(constructor: ListenerConstructor): constructor is QueuedListenerConstructor;
22
+ export declare function resolveQueuedListenerMetadata(constructor: QueuedListenerConstructor, defaults?: QueuedListenerMetadata & {
23
+ connection?: string;
24
+ }): {
25
+ connection: string;
26
+ queue: string;
27
+ delaySeconds: number;
28
+ };
29
+ export declare function buildCallQueuedListenerJob(constructor: QueuedListenerConstructor, event: Event, defaults?: QueuedListenerMetadata & {
30
+ connection?: string;
31
+ }): {
32
+ job: Job;
33
+ metadata: ReturnType<typeof resolveQueuedListenerMetadata>;
34
+ };
35
+ //# sourceMappingURL=should-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"should-queue.d.ts","sourceRoot":"","sources":["../src/should-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,yBAAyB,GAAG,mBAAmB,GAAG;IAC5D,WAAW,EAAE,IAAI,CAAC;CACnB,GAAG,sBAAsB,CAAC;AAE3B,8BAAsB,cAAc,CAAC,MAAM,SAAS,KAAK,GAAG,KAAK,CAC/D,SAAQ,QAAQ,CAAC,MAAM,CACvB,YAAW,WAAW;IAEtB,QAAQ,CAAC,WAAW,EAAG,IAAI,CAAU;IAErC,MAAM,CAAC,WAAW,EAAG,IAAI,CAAU;IACnC,MAAM,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,mBAAmB,GAC/B,WAAW,IAAI,yBAAyB,CAG1C;AAED,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,yBAAyB,EACtC,QAAQ,GAAE,sBAAsB,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9D;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAM7D;AAED,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,yBAAyB,EACtC,KAAK,EAAE,KAAK,EACZ,QAAQ,GAAE,sBAAsB,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9D;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,6BAA6B,CAAC,CAAA;CAAE,CAS1E"}
@@ -0,0 +1,30 @@
1
+ import { CallQueuedListener } from './call-queued-listener.js';
2
+ import { Listener } from './types.js';
3
+ export class QueuedListener extends Listener {
4
+ shouldQueue = true;
5
+ static shouldQueue = true;
6
+ static connection;
7
+ static queue;
8
+ static delaySeconds;
9
+ }
10
+ export function listenerShouldQueue(constructor) {
11
+ const typed = constructor;
12
+ return typed.shouldQueue === true;
13
+ }
14
+ export function resolveQueuedListenerMetadata(constructor, defaults = {}) {
15
+ return {
16
+ connection: constructor.connection ?? defaults.connection ?? 'sync',
17
+ queue: constructor.queue ?? defaults.queue ?? 'default',
18
+ delaySeconds: constructor.delaySeconds ?? defaults.delaySeconds ?? 0,
19
+ };
20
+ }
21
+ export function buildCallQueuedListenerJob(constructor, event, defaults = {}) {
22
+ const metadata = resolveQueuedListenerMetadata(constructor, defaults);
23
+ const job = new CallQueuedListener({
24
+ listener: constructor.name,
25
+ event: event.constructor.name,
26
+ eventData: event.data,
27
+ });
28
+ return { job, metadata };
29
+ }
30
+ //# sourceMappingURL=should-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"should-queue.js","sourceRoot":"","sources":["../src/should-queue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AActC,MAAM,OAAgB,cACpB,SAAQ,QAAgB;IAGf,WAAW,GAAG,IAAa,CAAC;IAErC,MAAM,CAAC,WAAW,GAAG,IAAa,CAAC;IACnC,MAAM,CAAC,UAAU,CAAU;IAC3B,MAAM,CAAC,KAAK,CAAU;IACtB,MAAM,CAAC,YAAY,CAAU;;AAG/B,MAAM,UAAU,mBAAmB,CACjC,WAAgC;IAEhC,MAAM,KAAK,GAAG,WAA8D,CAAC;IAC7E,OAAO,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,WAAsC,EACtC,WAA6D,EAAE;IAE/D,OAAO;QACL,UAAU,EAAE,WAAW,CAAC,UAAU,IAAI,QAAQ,CAAC,UAAU,IAAI,MAAM;QACnE,KAAK,EAAE,WAAW,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,IAAI,SAAS;QACvD,YAAY,EAAE,WAAW,CAAC,YAAY,IAAI,QAAQ,CAAC,YAAY,IAAI,CAAC;KACrE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,WAAsC,EACtC,KAAY,EACZ,WAA6D,EAAE;IAE/D,MAAM,QAAQ,GAAG,6BAA6B,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACtE,MAAM,GAAG,GAAG,IAAI,kBAAkB,CAAC;QACjC,QAAQ,EAAE,WAAW,CAAC,IAAI;QAC1B,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,IAAI;QAC7B,SAAS,EAAE,KAAK,CAAC,IAA+B;KACjD,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Container } from '@tyravel/container';
2
+ import type { EventDispatcher } from './event-dispatcher.js';
3
+ import type { EventSubscriberConstructor } from './types.js';
4
+ import type { EventsConfig } from './types.js';
5
+ export declare function registerEventListeners(dispatcher: EventDispatcher, registrations: EventsConfig['listen']): void;
6
+ export declare function registerEventSubscribers(dispatcher: EventDispatcher, subscribers: EventSubscriberConstructor[], container?: Container): void;
7
+ export declare function registerEventsConfig(dispatcher: EventDispatcher, config: EventsConfig, container?: Container): void;
8
+ //# sourceMappingURL=subscribers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscribers.d.ts","sourceRoot":"","sources":["../src/subscribers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,eAAe,EAC3B,aAAa,EAAE,YAAY,CAAC,QAAQ,CAAC,GACpC,IAAI,CAIN;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,eAAe,EAC3B,WAAW,EAAE,0BAA0B,EAAE,EACzC,SAAS,CAAC,EAAE,SAAS,GACpB,IAAI,CASN;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,eAAe,EAC3B,MAAM,EAAE,YAAY,EACpB,SAAS,CAAC,EAAE,SAAS,GACpB,IAAI,CAKN"}
@@ -0,0 +1,20 @@
1
+ export function registerEventListeners(dispatcher, registrations) {
2
+ for (const [event, handlers] of registrations) {
3
+ dispatcher.listenMany(event, handlers);
4
+ }
5
+ }
6
+ export function registerEventSubscribers(dispatcher, subscribers, container) {
7
+ for (const SubscriberClass of subscribers) {
8
+ const instance = container
9
+ ? container.make(SubscriberClass)
10
+ : new SubscriberClass();
11
+ instance.subscribe(dispatcher);
12
+ }
13
+ }
14
+ export function registerEventsConfig(dispatcher, config, container) {
15
+ registerEventListeners(dispatcher, config.listen);
16
+ if (config.subscribers?.length) {
17
+ registerEventSubscribers(dispatcher, config.subscribers, container);
18
+ }
19
+ }
20
+ //# sourceMappingURL=subscribers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscribers.js","sourceRoot":"","sources":["../src/subscribers.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,sBAAsB,CACpC,UAA2B,EAC3B,aAAqC;IAErC,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9C,UAAU,CAAC,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,UAA2B,EAC3B,WAAyC,EACzC,SAAqB;IAErB,KAAK,MAAM,eAAe,IAAI,WAAW,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,SAAS;YACxB,CAAC,CAAC,SAAS,CAAC,IAAI,CACZ,eAA4E,CAC7E;YACH,CAAC,CAAC,IAAI,eAAe,EAAE,CAAC;QAC1B,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,UAA2B,EAC3B,MAAoB,EACpB,SAAqB;IAErB,sBAAsB,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAClD,IAAI,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;QAC/B,wBAAwB,CAAC,UAAU,EAAE,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IACtE,CAAC;AACH,CAAC"}
@@ -0,0 +1,32 @@
1
+ export declare abstract class Event<TData = any> {
2
+ readonly data: TData;
3
+ constructor(data: TData);
4
+ }
5
+ export type EventConstructor<TEvent extends Event = Event> = new (...args: any[]) => TEvent;
6
+ export type ListenerCallback<TEvent extends Event = Event> = (event: TEvent) => void | Promise<void>;
7
+ export interface ListenerContract<TEvent extends Event = Event> {
8
+ handle(event: TEvent): void | Promise<void>;
9
+ }
10
+ export declare abstract class Listener<TEvent extends Event = Event> implements ListenerContract<TEvent> {
11
+ abstract handle(event: TEvent): void | Promise<void>;
12
+ }
13
+ export type ListenerConstructor<TEvent extends Event = Event> = new (...args: any[]) => ListenerContract<TEvent>;
14
+ export type ListenerHandler<TEvent extends Event = Event> = ListenerConstructor<TEvent> | ListenerCallback<TEvent>;
15
+ export interface ShouldQueue {
16
+ readonly shouldQueue: true;
17
+ }
18
+ export type EventListenerRegistration = [
19
+ EventConstructor,
20
+ ListenerHandler[]
21
+ ];
22
+ export declare abstract class EventSubscriber {
23
+ abstract subscribe(dispatcher: import('./event-dispatcher.js').EventDispatcher): void;
24
+ }
25
+ export type EventSubscriberConstructor = new (...args: any[]) => EventSubscriber;
26
+ export interface EventsConfig {
27
+ listen: EventListenerRegistration[];
28
+ subscribers?: EventSubscriberConstructor[];
29
+ queueConnection?: string;
30
+ queue?: string;
31
+ }
32
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,8BAAsB,KAAK,CAAC,KAAK,GAAG,GAAG;aACT,IAAI,EAAE,KAAK;gBAAX,IAAI,EAAE,KAAK;CACxC;AAGD,MAAM,MAAM,gBAAgB,CAAC,MAAM,SAAS,KAAK,GAAG,KAAK,IAAI,KAC3D,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,MAAM,CAAC;AAEZ,MAAM,MAAM,gBAAgB,CAAC,MAAM,SAAS,KAAK,GAAG,KAAK,IAAI,CAC3D,KAAK,EAAE,MAAM,KACV,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,MAAM,WAAW,gBAAgB,CAAC,MAAM,SAAS,KAAK,GAAG,KAAK;IAC5D,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAED,8BAAsB,QAAQ,CAAC,MAAM,SAAS,KAAK,GAAG,KAAK,CACzD,YAAW,gBAAgB,CAAC,MAAM,CAAC;IAEnC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CACrD;AAGD,MAAM,MAAM,mBAAmB,CAAC,MAAM,SAAS,KAAK,GAAG,KAAK,IAAI,KAC9D,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAE9B,MAAM,MAAM,eAAe,CAAC,MAAM,SAAS,KAAK,GAAG,KAAK,IACpD,mBAAmB,CAAC,MAAM,CAAC,GAC3B,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAE7B,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC;CAC5B;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,gBAAgB;IAChB,eAAe,EAAE;CAClB,CAAC;AAEF,8BAAsB,eAAe;IACnC,QAAQ,CAAC,SAAS,CAAC,UAAU,EAAE,OAAO,uBAAuB,EAAE,eAAe,GAAG,IAAI;CACtF;AAGD,MAAM,MAAM,0BAA0B,GAAG,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,eAAe,CAAC;AAEjF,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,yBAAyB,EAAE,CAAC;IACpC,WAAW,CAAC,EAAE,0BAA0B,EAAE,CAAC;IAC3C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
package/dist/types.js ADDED
@@ -0,0 +1,12 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ export class Event {
3
+ data;
4
+ constructor(data) {
5
+ this.data = data;
6
+ }
7
+ }
8
+ export class Listener {
9
+ }
10
+ export class EventSubscriber {
11
+ }
12
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,MAAM,OAAgB,KAAK;IACG;IAA5B,YAA4B,IAAW;QAAX,SAAI,GAAJ,IAAI,CAAO;IAAG,CAAC;CAC5C;AAeD,MAAM,OAAgB,QAAQ;CAI7B;AAoBD,MAAM,OAAgB,eAAe;CAEpC"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@tyravel/events",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "scripts": {
14
+ "build": "tsc -p tsconfig.json",
15
+ "typecheck": "tsc -p tsconfig.json --noEmit"
16
+ },
17
+ "dependencies": {
18
+ "@tyravel/container": "0.1.0",
19
+ "@tyravel/queue": "0.1.0"
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "engines": {
25
+ "node": ">=22"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^22.15.30"
29
+ },
30
+ "description": "Domain events and listeners for Tyravel",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/thesimonharms/tyravel.git",
35
+ "directory": "packages/events"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ }
40
+ }