@stacksjs/events 0.70.170 → 0.70.172

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.
@@ -0,0 +1,37 @@
1
+ import type { Handler } from './index';
2
+ /**
3
+ * Walk the listeners directory and register every default-exported
4
+ * listener that matches the `ListenerModule` shape. Returns the
5
+ * count of successfully registered listeners.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * // In your framework boot path:
10
+ * import { discoverListeners } from '@stacksjs/events'
11
+ *
12
+ * await discoverListeners() // defaults to app/Listeners
13
+ * // or
14
+ * await discoverListeners({ dir: '/custom/path' })
15
+ * ```
16
+ */
17
+ export declare function discoverListeners(options?: DiscoverOptions): Promise<number>;
18
+ /**
19
+ * Shape of a listener module's default export. The `listensTo`
20
+ * field is the event name (matches the strict type of
21
+ * `StacksEvents` keys via `unknown` for cross-pkg flexibility);
22
+ * `handle` is the actual listener function.
23
+ */
24
+ export declare interface ListenerModule<T = unknown> {
25
+ listensTo: string
26
+ handle: Handler<T>
27
+ name?: string
28
+ }
29
+ declare interface DiscoverOptions {
30
+ dir?: string
31
+ extensions?: string[]
32
+ log?: {
33
+ warn?: (msg: string) => void
34
+ error?: (msg: string) => void
35
+ info?: (msg: string) => void
36
+ }
37
+ }
@@ -0,0 +1,153 @@
1
+ import type { ModelEvents } from '@stacksjs/types';
2
+ export type { ListenerModule } from './discover';
3
+ /**
4
+ * Create a fresh Stacks event emitter. Most consumers want the singleton
5
+ * exported below — call this directly only when you need an isolated bus
6
+ * (tests, child workers, plugin sandboxes).
7
+ */
8
+ // eslint-disable-next-line pickier/no-unused-vars
9
+ export declare function createEmitter<Events extends Record<EventType, unknown>>(all?: EventHandlerMap<Events>): Emitter<Events>;
10
+ /**
11
+ * Build a scoped wrapper around an emitter (stacksjs/stacks#1878 E-5).
12
+ * Every dispatch and listen call is prefixed with `${prefix}:` so
13
+ * different tenants / plugins / subsystems can share the same
14
+ * underlying bus without colliding on event names.
15
+ *
16
+ * Listeners registered through the scoped wrapper only receive events
17
+ * dispatched through the SAME wrapper — they don't see unprefixed
18
+ * events on the underlying bus. Apps that need to subscribe across
19
+ * scopes use the underlying emitter directly with a glob pattern.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { events, scope } from '@stacksjs/events'
24
+ *
25
+ * const tenantA = scope(events, 'tenant:42')
26
+ * tenantA.on('user:created', user => sendWelcome(user))
27
+ * tenantA.emit('user:created', { id: 1 })
28
+ * // ↑ fires the listener; on the underlying bus the event is
29
+ * // emitted as 'tenant:42:user:created'.
30
+ *
31
+ * // Listener on the raw bus DOES see the prefixed form:
32
+ * events.on('tenant:42:user:created', auditTrail)
33
+ * // Listener on the raw bus DOES NOT see the bare 'user:created' —
34
+ * // the prefix is mandatory.
35
+ * ```
36
+ */
37
+ export declare function scope<Events extends Record<EventType, unknown>>(underlying: Emitter<Events>, prefix: string): {
38
+ on: (type: string, handler: Handler<unknown>, options?: { priority?: number }) => void
39
+ once: (type: string, handler: Handler<unknown>) => void
40
+ off: (type: string, handler?: Handler<unknown>) => void
41
+ emit: (type: string, event: unknown) => void
42
+ emitAsync: (type: string, event: unknown) => Promise<unknown[]>
43
+ emitAndCollect: (type: string, event: unknown) => Promise<Array<{ ok: true, value: unknown } | { ok: false, error: Error }>>
44
+ listenerCount: (type: string) => number
45
+ };
46
+ // Singleton-friendly scope alias (#1878 E-5). Use to create a
47
+ // per-tenant / per-plugin wrapper that auto-prefixes event names.
48
+ export declare function scopedEvents(prefix: string): void;
49
+ /**
50
+ * Backward-compatible alias for the legacy `mitt()` export. Behaves
51
+ * identically to {@link createEmitter}.
52
+ */
53
+ export declare const mitt: unknown;
54
+ declare const events: Emitter<StacksEvents>;
55
+ declare const emitter: Emitter<StacksEvents>;
56
+ declare const useEvents: Emitter<StacksEvents>;
57
+ declare const dispatch: Dispatch;
58
+ declare const dispatchAsync: DispatchAsync;
59
+ declare const dispatchAndCollect: DispatchAndCollect;
60
+ declare const useEvent: Dispatch;
61
+ declare const all: EventHandlerMap<StacksEvents>;
62
+ declare const listen: Listen;
63
+ declare const useListen: Listen;
64
+ declare const once: Listen;
65
+ declare const off: Off;
66
+ export declare interface Emitter<Events extends Record<EventType, unknown>> {
67
+ all: EventHandlerMap<Events>
68
+ on: (<Key extends keyof Events>(_type: Key, _handler: Handler<Events[Key]>, _options?: { priority?: number }) => void) &
69
+ ((_type: '*', _handler: WildcardHandler<Events>, _options?: { priority?: number }) => void) &
70
+ ((_type: string, _handler: WildcardHandler<Events>, _options?: { priority?: number }) => void)
71
+ once: (<Key extends keyof Events>(_type: Key, _handler: Handler<Events[Key]>) => void) &
72
+ ((_type: '*', _handler: WildcardHandler<Events>) => void)
73
+ off: (<Key extends keyof Events>(_type: Key, _handler?: Handler<Events[Key]>) => void) &
74
+ ((_type: '*', _handler?: WildcardHandler<Events>) => void) &
75
+ ((_type: string, _handler?: WildcardHandler<Events>) => void)
76
+ emit: (<Key extends keyof Events>(_type: Key, _event: Events[Key]) => void) &
77
+ (<Key extends keyof Events>(_type: undefined extends Events[Key] ? Key : never) => void)
78
+ emitAsync: <Key extends keyof Events>(_type: Key, _event: Events[Key]) => Promise<unknown[]>
79
+ emitAndCollect: <Key extends keyof Events>(_type: Key, _event: Events[Key]) => Promise<Array<{ ok: true, value: unknown } | { ok: false, error: Error }>>
80
+ removeAllListeners: (_type?: keyof Events | '*') => void
81
+ listenerCount: (_type: keyof Events | '*') => number
82
+ }
83
+ /**
84
+ * Concrete payload shape for the auth-related events. Keeping these
85
+ * narrow (instead of `Record<string, any>`) means listeners don't need to
86
+ * cast or guess what fields are present — the handler signature reflects
87
+ * what RegisterAction / LoginAction actually dispatch.
88
+ */
89
+ export declare interface UserRegisteredEvent {
90
+ id?: number | string
91
+ email: string
92
+ name?: string
93
+ to?: string
94
+ }
95
+ export declare interface UserLoggedInEvent {
96
+ id: number | string
97
+ email: string
98
+ }
99
+ export declare interface UserLoggedOutEvent {
100
+ id: number | string
101
+ }
102
+ export declare interface UserPasswordEvent {
103
+ id: number | string
104
+ email: string
105
+ }
106
+ /**
107
+ * Application-wide event types. Listeners and dispatchers below are
108
+ * pre-typed to this map; user-defined event names land here via
109
+ * `ModelEvents` (model-emitted events) + the explicit auth events listed.
110
+ */
111
+ export declare interface StacksEvents extends ModelEvents, Record<EventType, unknown> {
112
+ 'user:registered': UserRegisteredEvent
113
+ 'user:logged-in': UserLoggedInEvent
114
+ 'user:logged-out': UserLoggedOutEvent
115
+ 'user:password-reset': UserPasswordEvent
116
+ 'user:password-changed': UserPasswordEvent
117
+ }
118
+ export type EventType = string | symbol;
119
+ export type Handler<T = unknown> = (_event: T) => void | Promise<void>;
120
+ export type WildcardHandler<T = Record<string, unknown>> = (_type: keyof T, _event: T[keyof T]) => void | Promise<void>;
121
+ export type EventHandlerList<T = unknown> = Array<Handler<T>>;
122
+ export type WildCardEventHandlerList<T = Record<string, unknown>> = Array<WildcardHandler<T>>;
123
+ export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<
124
+ keyof Events | '*',
125
+ EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>
126
+ >;
127
+ declare type Dispatch = <Key extends keyof StacksEvents>(_type: Key, _event: StacksEvents[Key]) => void;
128
+ // eslint-disable-next-line pickier/no-unused-vars
129
+ declare type Listen = <Key extends keyof StacksEvents>(_type: Key, _handler: Handler<StacksEvents[Key]>, _options?: { priority?: number }) => void;
130
+ // eslint-disable-next-line pickier/no-unused-vars
131
+ declare type Off = <Key extends keyof StacksEvents>(_type: Key, handler?: Handler<StacksEvents[Key]>) => void;
132
+ declare type DispatchAsync = <Key extends keyof StacksEvents>(_type: Key, _event: StacksEvents[Key]) => Promise<unknown[]>;
133
+ declare type DispatchAndCollect = <Key extends keyof StacksEvents>(_type: Key, _event: StacksEvents[Key]) => Promise<Array<{ ok: true, value: unknown } | { ok: false, error: Error }>>;
134
+ export {
135
+ all,
136
+ dispatch,
137
+ dispatchAndCollect,
138
+ dispatchAsync,
139
+ emitter,
140
+ events,
141
+ listen,
142
+ off,
143
+ once,
144
+ useEvent,
145
+ useEvents,
146
+ useListen,
147
+ };
148
+ // Boot-time listener auto-discovery (stacksjs/stacks#1878 E-3,
149
+ // closing F-3 from #1874). Scans `app/Listeners/**/*.ts` for
150
+ // default-exported `{ listensTo, handle }` modules and registers them.
151
+ export { discoverListeners } from './discover';
152
+ // Default export keeps `import mitt from '@stacksjs/events'` shape working.
153
+ export default createEmitter;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/events",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.70.170",
5
+ "version": "0.70.172",
6
6
  "description": "Functional event emitting.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [