@stacksjs/events 0.72.97 → 0.72.99

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.
@@ -1,3 +1,28 @@
1
+ import type { EventName, StacksEvents } from './index';
2
+ /**
3
+ * Define a listener module, with the event names checked and the payload
4
+ * inferred from them.
5
+ *
6
+ * The same helper `defineEvents` is for `app/Events.ts`, for the other half of
7
+ * the convention: a plain object literal cannot infer `T` from `listensTo`, so
8
+ * without this the handler's payload widens to the union of everything the bus
9
+ * carries and the event names go unchecked.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * // app/Listeners/SendWelcomeEmail.ts
14
+ * import { defineListener } from '@stacksjs/events'
15
+ *
16
+ * export default defineListener({
17
+ * listensTo: 'user:registered',
18
+ * handle: async (user) => {
19
+ * // `user` is the registration payload, not `unknown`
20
+ * await mail.send({ to: user.email })
21
+ * },
22
+ * })
23
+ * ```
24
+ */
25
+ export declare function defineListener<const T extends EventSubscription>(listener: ListenerModule<T>): ListenerModule<T>;
1
26
  /**
2
27
  * Walk the listeners directory and register every default-exported
3
28
  * listener that matches the `ListenerModule` shape. Returns the
@@ -33,15 +58,22 @@ export declare function resetListenerRegistry(): void;
33
58
  * alternative is an application that will not boot over a typo in a notifier.
34
59
  */
35
60
  export declare function registerAppListeners(options?: RegisterOptions): Promise<number>;
61
+ /** For tests, and for a dev server that regenerated the registries. */
62
+ export declare function resetNameRegistries(): void;
36
63
  /**
37
- * Shape of a listener module's default export. The `listensTo`
38
- * field is the event name (matches the strict type of
39
- * `StacksEvents` keys via `unknown` for cross-pkg flexibility);
40
- * `handle` is the actual listener function.
64
+ * Shape of a listener module's default export.
65
+ *
66
+ * `listensTo` was `string | string[]`, with a comment explaining that the loose
67
+ * type bought "cross-pkg flexibility". What it actually bought was a listener
68
+ * file that compiles while subscribing to an event that does not exist: the
69
+ * scan registers it, the emitter never matches it, and the file looks like it
70
+ * is doing its job forever. The names are checked now, and the payload follows
71
+ * from the name rather than being `unknown` for the handler to assert its way
72
+ * out of.
41
73
  */
42
- export declare interface ListenerModule<T = unknown> {
43
- listensTo: string | string[]
44
- handle: (_payload: T, _eventName?: string) => void | Promise<void>
74
+ export declare interface ListenerModule<T extends EventSubscription = EventSubscription> {
75
+ listensTo: T | readonly T[]
76
+ handle: (_payload: SubscriptionPayload<T>, _eventName?: EventName) => void | Promise<void>
45
77
  name?: string
46
78
  }
47
79
  declare interface DiscoverOptions {
@@ -56,5 +88,24 @@ declare interface DiscoverOptions {
56
88
  declare interface RegisterOptions extends DiscoverOptions {
57
89
  base?: string
58
90
  }
91
+ /**
92
+ * What a listener may subscribe to: an event that exists, or a glob the
93
+ * emitter matches against every event name (`'user:*'`, `'*'`).
94
+ *
95
+ * The glob branch is why this is not simply `EventName`. `registerFromMap` and
96
+ * the scan both hand their names to `emitter.on`, which matches patterns as
97
+ * well as exact names, so a union without them would reject a subscription
98
+ * that works.
99
+ */
100
+ export type EventSubscription = EventName | '*' | `${string}:*`;
101
+ /**
102
+ * The payload a subscription carries.
103
+ *
104
+ * Exact for an exact event name. A glob can fire for any event, so it gets the
105
+ * union of what the bus can carry rather than a guess at which one.
106
+ */
107
+ export type SubscriptionPayload<T extends EventSubscription> = T extends EventName
108
+ ? StacksEvents[T]
109
+ : StacksEvents[EventName];
59
110
  /** An action's `validations:`, as much of it as this module needs. */
60
111
  declare type PayloadValidations = Record<string, { rule?: { validate?: (_value: unknown) => { valid: boolean } } }>;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type { ListenerModule } from './discover';
1
+ export type { EventSubscription, ListenerModule, SubscriptionPayload } from './discover';
2
2
  /**
3
3
  * Create a fresh Stacks event emitter. Most consumers want the singleton
4
4
  * exported below — call this directly only when you need an isolated bus
@@ -42,6 +42,43 @@ export declare function scope<Events extends EventMap>(underlying: Emitter<Event
42
42
  emitAndCollect: (type: string, event: unknown) => Promise<Array<{ ok: true, value: unknown } | { ok: false, error: Error }>>
43
43
  listenerCount: (type: string) => number
44
44
  };
45
+ /**
46
+ * Define the application's event-to-listener map, with the literal names kept.
47
+ *
48
+ * Identical in effect to `satisfies Events`, and preferred for the same reason
49
+ * every other `define*` helper in the framework is: the constraint is applied
50
+ * where the object is written, so the error points at the misspelled event name
51
+ * rather than at whatever consumed the map later.
52
+ *
53
+ * `const` on the type parameter is what makes it *narrower* than `satisfies`:
54
+ * the returned type keeps `readonly ['SendWelcomeEmail']` rather than widening
55
+ * to `ListenerName[]`, so `keyof typeof events` and `events['user:registered']`
56
+ * are exactly what the file declares.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * // app/Events.ts
61
+ * import { defineEvents } from '@stacksjs/events'
62
+ *
63
+ * export default defineEvents({
64
+ * 'user:registered': ['SendWelcomeEmail'],
65
+ * 'user:created': ['NotifyUser'],
66
+ * })
67
+ * ```
68
+ *
69
+ * The `Record<Exclude<keyof T, EventName>, never>` half of the constraint is
70
+ * what rejects an event name that does not exist, and it is not redundant with
71
+ * `Events`. Excess-property checking is a freshness rule on the object literal,
72
+ * and it stops applying as soon as inference has something to work with: a map
73
+ * of one bad key is caught by it, and the same bad key sitting next to one good
74
+ * one is not, because `T` infers happily and a type with extra properties is
75
+ * assignable to a mapped type whose keys are all optional. Requiring every key
76
+ * outside `EventName` to hold something no listener list can be makes the check
77
+ * structural, so it holds however many entries the map has - and the shape it
78
+ * demands is an object with one impossible property, so the compiler's message
79
+ * is the sentence naming the fix rather than `not assignable to never`.
80
+ */
81
+ export declare function defineEvents<const T extends Events & Record< Exclude<keyof T, EventName>, { 'this event name is not declared on AppEvents or AuthEvents': never } >,>(events: T): T;
45
82
  // Singleton-friendly scope alias (#1878 E-5). Use to create a
46
83
  // per-tenant / per-plugin wrapper that auto-prefixes event names.
47
84
  export declare function scopedEvents(prefix: string): void;
@@ -140,6 +177,31 @@ export declare interface AuthEvents {
140
177
  'user:password-reset': UserPasswordEvent
141
178
  'user:password-changed': UserPasswordEvent
142
179
  }
180
+ /**
181
+ * Augmentation target: every listener name `app/Events.ts` may reference.
182
+ *
183
+ * The keys are listener names as they are written in the map - `'NotifyUser'`,
184
+ * `'Auth/LoginAction'` - which is a name relative to `app/Listeners/` or
185
+ * `app/Actions/` (or the framework defaults behind them), without the
186
+ * extension. Filled by `storage/framework/types/registries.d.ts`, which reads
187
+ * the same name maps `resolveListener` resolves through - so the type and the
188
+ * resolution cannot disagree about what exists, because there is one list.
189
+ *
190
+ * An interface rather than a union alias because a union cannot be reopened,
191
+ * and this one has to be: the framework declares it empty and the application's
192
+ * generated declarations fill it in.
193
+ *
194
+ * @example
195
+ * ```ts
196
+ * declare module '@stacksjs/events' {
197
+ * interface EventListeners {
198
+ * 'SendWelcomeEmail': true
199
+ * }
200
+ * }
201
+ * ```
202
+ */
203
+ // eslint-disable-next-line ts/no-empty-object-type -- augmentation target; empty by design
204
+ export declare interface EventListeners {}
143
205
  /**
144
206
  * Stacks event engine — a native, type-safe, async-aware pub/sub.
145
207
  *
@@ -207,6 +269,37 @@ export type EventHandlerMap<Events extends EventMap> = Map<
207
269
  * `AppEvents` and the typo becomes a compile error.
208
270
  */
209
271
  export type StacksEvents = AppEvents & AuthEvents;
272
+ /**
273
+ * Every event name this application can dispatch or listen for.
274
+ *
275
+ * `& string` because `keyof` on an object type also yields `number | symbol`
276
+ * for an index signature, and an event name in `app/Events.ts` is a string key.
277
+ */
278
+ export type EventName = keyof StacksEvents & string;
279
+ /**
280
+ * A listener name, as narrow as the application has made it.
281
+ *
282
+ * Falls back to `string` while `EventListeners` is empty. That is not a
283
+ * loophole left open: `generate:types` has not run yet in a project that has
284
+ * just been created, and rejecting every listener name until it does would make
285
+ * a fresh app fail to compile over a file it has never been told to generate.
286
+ * Once the registry exists, a misspelled listener is a compile error.
287
+ */
288
+ export type ListenerName = keyof EventListeners extends never
289
+ ? string
290
+ : keyof EventListeners & string;
291
+ /**
292
+ * The `app/Events.ts` map: an event name to the listeners that handle it.
293
+ *
294
+ * Both halves are checked. The key must be an event that exists - a name only
295
+ * `AppEvents` or `AuthEvents` declares - and the value must name listeners that
296
+ * are on disk. Neither used to be: the type was `{ [key: string]: string[] }`,
297
+ * which accepts `{ 'user:registerd': ['SendWelcomEmail'] }` in full, and both
298
+ * halves of that fail at runtime by doing nothing at all.
299
+ */
300
+ export type Events = {
301
+ readonly [K in EventName]?: readonly ListenerName[]
302
+ }
210
303
  declare type Dispatch = <Key extends keyof StacksEvents>(_type: Key, _event: StacksEvents[Key]) => void;
211
304
  // eslint-disable-next-line pickier/no-unused-vars
212
305
  declare type Listen = <Key extends keyof StacksEvents>(_type: Key, _handler: Handler<StacksEvents[Key]>, _options?: { priority?: number }) => void;
@@ -231,6 +324,6 @@ export {
231
324
  // Boot-time listener auto-discovery (stacksjs/stacks#1878 E-3,
232
325
  // closing F-3 from #1874). Scans `app/Listeners/**/*.ts` for
233
326
  // default-exported `{ listensTo, handle }` modules and registers them.
234
- export { discoverListeners, registerAppListeners, resetListenerRegistry } from './discover';
327
+ export { defineListener, discoverListeners, registerAppListeners, resetListenerRegistry, resetNameRegistries } from './discover';
235
328
  // Default export keeps `import mitt from '@stacksjs/events'` shape working.
236
329
  export default createEmitter;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{existsSync as P,readdirSync as V,statSync as B}from"fs";import{extname as Y,join as A}from"path";import W from"process";async function C(n={}){let e=n.dir??A(W.cwd(),"app","Listeners"),r=n.extensions??[".ts",".js"],t={warn:n.log?.warn??((c)=>console.warn(c)),error:n.log?.error??((c)=>console.error(c)),info:n.log?.info??((c)=>console.info(c))};if(!P(e))return 0;let o=O(e,r);if(o.length===0)return 0;let i=0;for(let c of o)try{let y=await import(c),p=y?.default??y;if(typeof p==="function")continue;if(!G(p)){t.warn(`[events/discover] ${c}: default export doesn't match ListenerModule shape ({ listensTo, handle }), skipping`);continue}for(let E of q(p.listensTo)){if(!D(E,c))continue;T(E,(_)=>p.handle(_,E)),i++}}catch(y){t.error(`[events/discover] failed to import ${c}: ${y instanceof Error?y.message:String(y)}`)}if(i>0)t.info(`[events/discover] registered ${i} listener${i===1?"":"s"} from ${e}`);return i}function O(n,e){let r=[],t=V(n);for(let o of t){let i=A(n,o),c=B(i);if(c.isDirectory())r.push(...O(i,e));else if(c.isFile()&&e.includes(Y(o)))r.push(i)}return r}function G(n){let e=n?.listensTo;return!!n&&typeof n==="object"&&(typeof e==="string"||Array.isArray(e))&&typeof n.handle==="function"}function q(n){return(Array.isArray(n)?n:[n]).map((r)=>String(r).trim()).filter(Boolean)}var L=new Set;function D(n,e){let r=`${n}\x00${e}`;if(L.has(r))return!1;return L.add(r),!0}function z(){L.clear()}async function J(n={}){let e=n.base??W.cwd(),r={warn:n.log?.warn??((o)=>console.warn(o)),error:n.log?.error??((o)=>console.error(o)),info:n.log?.info??((o)=>console.info(o))},t=0;if(t+=await Q(e,r),t+=await C({...n,dir:n.dir??A(e,"app","Listeners"),log:{...r,info:()=>{}}}),t>0)r.info(`[events] registered ${t} listener${t===1?"":"s"}`);return t}async function Q(n,e){let r=["ts","js"].map((i)=>A(n,"app",`Events.${i}`)).find((i)=>P(i));if(!r)return 0;let t;try{let i=await import(r);t=i?.default??i}catch(i){return e.error(`[events] failed to read ${r}: ${i instanceof Error?i.message:String(i)}`),0}if(!t||typeof t!=="object")return 0;let o=0;for(let[i,c]of Object.entries(t))for(let y of Array.isArray(c)?c:[c]){if(typeof y!=="string"||!y.trim())continue;let p=await Z(n,y.trim());if(!p){e.warn(`[events] ${i}: no listener or action called ${y}`);continue}if(!D(i,p.id))continue;let{handle:E,validations:_}=p;T(i,(S)=>(X(i,y,S,_,e),E(S,i))),o++}return o}function X(n,e,r,t,o){if(!t||typeof r!=="object"||r===null)return;let i=r,c=[];for(let[y,p]of Object.entries(t)){let E=p?.rule?.validate;if(typeof E!=="function")continue;try{if(!E(i[y]).valid)c.push(y)}catch{c.push(y)}}if(c.length)o.warn(`[events] ${n}: payload does not match what ${e} declares (${c.join(", ")})`)}async function Z(n,e){let r=[];for(let t of["Listeners","Actions"])for(let o of["ts","js"])r.push(A(n,"app",t,`${e}.${o}`));for(let t of r){if(!P(t))continue;try{let o=await import(t),i=o?.default??o,c=i?.handle;if(typeof c!=="function")continue;return{id:t,handle:c.bind(i),validations:i?.validations}}catch{continue}}return null}var j=Symbol.for("stacks.events.handler.error"),I=Symbol.for("stacks.events.handler.priority");function ee(n){if(n&&typeof n==="object"||typeof n==="function"){let e=n[I];return typeof e==="number"&&Number.isFinite(e)?e:0}return 0}function H(n){return n.map((e,r)=>({h:e,i:r,p:ee(e)})).sort((e,r)=>r.p-e.p||e.i-r.i).map((e)=>e.h)}function h(n,e,r){console.error(`[Events] ${n} for '${String(e)}':`,r)}function b(n){return!!n&&typeof n.catch==="function"}function R(n){let e=n??new Map,r=new Map,t=(s,f)=>{let d=r.get(s);if(!d)d=new RegExp(`^${s.replace(/\*/g,".*")}$`),r.set(s,d);return d.test(f)};function o(s,f,d){if(d?.priority!==void 0&&Number.isFinite(d.priority))f[I]=d.priority;let u=e.get(s);if(u)u.push(f);else e.set(s,[f])}function i(s,f){let d=(...u)=>(c(s,d),f(...u));d[j]=f,o(s,d)}function c(s,f){let d=e.get(s);if(!d)return;if(!f){e.set(s,[]);return}for(let u=d.length-1;u>=0;u--){let m=d[u];if(m===f||m?.[j]===f)d.splice(u,1)}}function y(s){if(s===void 0)e.clear();else e.delete(s)}function p(s){return e.get(s)?.length??0}function E(s,f){let d=e.get(s)?.slice(),u=e.get("*")?.slice(),m=d?H(d):void 0,k=u?H(u):void 0;if(m)for(let g of m)try{let a=g(f);if(b(a))a.catch((l)=>h("Async handler error",s,l))}catch(a){h("Handler error",s,a)}let v=String(s);if(e.forEach((g,a)=>{let l=String(a);if(l===v||l==="*"||!l.includes("*"))return;if(t(l,v))for(let x of H(g.slice()))try{let K=x(s,f);if(b(K))K.catch((N)=>h(`Async pattern handler '${l}' error`,s,N))}catch(K){h(`Pattern handler '${l}' error`,s,K)}}),k)for(let g of k)try{let a=g(s,f);if(b(a))a.catch((l)=>h("Async wildcard handler error",s,l))}catch(a){h("Wildcard handler error",s,a)}}async function _(s,f){let d=[],u=async(v,g)=>{if(!v)return;for(let a of H(v.slice()))try{let l=g?a(s,f):a(f);d.push(b(l)?await l:l)}catch(l){h("Awaited handler error",s,l),d.push(void 0)}};await u(e.get(s),!1);let m=String(s),k=[];e.forEach((v,g)=>{let a=String(g);if(a===m||a==="*"||!a.includes("*"))return;if(t(a,m))k.push(a)});for(let v of k)await u(e.get(v),!0);return await u(e.get("*"),!0),d}async function S(s,f){let d=[],u=async(v,g)=>{if(!v)return;for(let a of H(v.slice()))try{let l=g?a(s,f):a(f),x=b(l)?await l:l;d.push({ok:!0,value:x})}catch(l){let x=l instanceof Error?l:Error(String(l));d.push({ok:!1,error:x})}};await u(e.get(s),!1);let m=String(s),k=[];e.forEach((v,g)=>{let a=String(g);if(a===m||a==="*"||!a.includes("*"))return;if(t(a,m))k.push(a)});for(let v of k)await u(e.get(v),!0);return await u(e.get("*"),!0),d}return{all:e,on:o,once:i,off:c,emit:E,emitAsync:_,emitAndCollect:S,removeAllListeners:y,listenerCount:p}}var ce=R,ke=R;function ne(n,e){let r=(t)=>`${e}:${t}`;return{on(t,o,i){n.on(r(t),o,i)},once(t,o){n.once(r(t),o)},off(t,o){n.off(r(t),o)},emit(t,o){n.emit(r(t),o)},emitAsync(t,o){return n.emitAsync(r(t),o)},emitAndCollect(t,o){return n.emitAndCollect(r(t),o)},listenerCount(t){return n.listenerCount(r(t))}}}var U=Symbol.for("stacks.events.emitter"),F=globalThis,M=F[U]??(F[U]=R()),w=M,de=M,te=w.emit,le=w.emitAsync,fe=w.emitAndCollect,ue=te,ye=w.all,T=w.on,ve=w.on,pe=w.once,ge=w.off;function me(n){return ne(M,n)}export{ye as all,R as createEmitter,ke as default,C as discoverListeners,te as dispatch,fe as dispatchAndCollect,le as dispatchAsync,w as emitter,M as events,T as listen,ce as mitt,ge as off,pe as once,J as registerAppListeners,z as resetListenerRegistry,ne as scope,me as scopedEvents,ue as useEvent,de as useEvents,ve as useListen};
2
+ import{existsSync as T,readdirSync as Y,statSync as G}from"fs";import{extname as J,join as k,resolve as q}from"path";import W from"process";function z(e){return e}async function C(e={}){let n=e.dir??k(W.cwd(),"app","Listeners"),t=e.extensions??[".ts",".js"],r={warn:e.log?.warn??((a)=>console.warn(a)),error:e.log?.error??((a)=>console.error(a)),info:e.log?.info??((a)=>console.info(a))};if(!T(n))return 0;let s=j(n,t);if(s.length===0)return 0;let o=0;for(let a of s)try{let u=await import(a),v=u?.default??u;if(typeof v==="function")continue;if(!Q(v)){r.warn(`[events/discover] ${a}: default export doesn't match ListenerModule shape ({ listensTo, handle }), skipping`);continue}for(let m of X(v.listensTo)){if(!D(m,a))continue;R(m,(x)=>v.handle(x,m)),o++}}catch(u){r.error(`[events/discover] failed to import ${a}: ${u instanceof Error?u.message:String(u)}`)}if(o>0)r.info(`[events/discover] registered ${o} listener${o===1?"":"s"} from ${n}`);return o}function j(e,n){let t=[],r=Y(e);for(let s of r){let o=k(e,s),a=G(o);if(a.isDirectory())t.push(...j(o,n));else if(a.isFile()&&n.includes(J(s)))t.push(o)}return t}function Q(e){let n=e?.listensTo;return!!e&&typeof e==="object"&&(typeof n==="string"||Array.isArray(n))&&typeof e.handle==="function"}function X(e){return(Array.isArray(e)?e:[e]).map((t)=>String(t).trim()).filter(Boolean)}var K=new Set;function D(e,n){let t=`${e}\x00${n}`;if(K.has(t))return!1;return K.add(t),!0}function Z(){K.clear()}async function ee(e={}){let n=e.base??W.cwd(),t={warn:e.log?.warn??((s)=>console.warn(s)),error:e.log?.error??((s)=>console.error(s)),info:e.log?.info??((s)=>console.info(s))},r=0;if(r+=await ne(n,t),r+=await C({...e,dir:e.dir??k(n,"app","Listeners"),log:{...t,info:()=>{}}}),r>0)t.info(`[events] registered ${r} listener${r===1?"":"s"}`);return r}async function ne(e,n){let t=["ts","js"].map((o)=>k(e,"app",`Events.${o}`)).find((o)=>T(o));if(!t)return 0;let r;try{let o=await import(t);r=o?.default??o}catch(o){return n.error(`[events] failed to read ${t}: ${o instanceof Error?o.message:String(o)}`),0}if(!r||typeof r!=="object")return 0;let s=0;for(let[o,a]of Object.entries(r))for(let u of Array.isArray(a)?a:[a]){if(typeof u!=="string"||!u.trim())continue;let v=await ie(e,u.trim());if(!v){n.warn(`[events] ${o}: no listener or action called ${u}`);continue}if(!D(o,v.id))continue;let{handle:m,validations:x}=v;R(o,(H)=>(te(o,u,H,x,n),m(H,o))),s++}return s}function te(e,n,t,r,s){if(!r||typeof t!=="object"||t===null)return;let o=t,a=[];for(let[u,v]of Object.entries(r)){let m=v?.rule?.validate;if(typeof m!=="function")continue;try{if(!m(o[u]).valid)a.push(u)}catch{a.push(u)}}if(a.length)s.warn(`[events] ${e}: payload does not match what ${n} declares (${a.join(", ")})`)}var P=new Map;async function O(e,n,t){let r=`${e}:${n}`,s=P.get(r);if(s)return s;let o=(async()=>{try{let a=k(e,"storage","framework","auto-imports"),v=(await import(k(a,`${n}.ts`)))[t];if(!v)return null;return Object.fromEntries(Object.entries(v).map(([m,x])=>[m,q(a,x)]))}catch{return null}})();return P.set(r,o),o}async function re(e,n){let t=await O(e,"listeners","listeners"),r=await O(e,"actions","actions");if(!t&&!r)return null;return t?.[n]??r?.[`Actions/${n}`]??null}function se(){P.clear()}function oe(e){let n=[k(e,"app"),k(e,"storage","framework","defaults","app")];try{let t=Bun.resolveSync("@stacksjs/defaults/package.json",e);n.push(k(t.slice(0,t.lastIndexOf("/")),"app"))}catch{}return n.filter((t)=>T(t))}async function ie(e,n){let t=[],r=await re(e,n);if(r)t.push(r);for(let s of oe(e))for(let o of["Listeners","Actions"])for(let a of["ts","js"])t.push(k(s,o,`${n}.${a}`));for(let s of t){if(!T(s))continue;try{let o=await import(s),a=o?.default??o,u=a?.handle;if(typeof u!=="function")continue;return{id:s,handle:u.bind(a),validations:a?.validations}}catch{continue}}return null}var U=Symbol.for("stacks.events.handler.error"),V=Symbol.for("stacks.events.handler.priority");function ae(e){if(e&&typeof e==="object"||typeof e==="function"){let n=e[V];return typeof n==="number"&&Number.isFinite(n)?n:0}return 0}function A(e){return e.map((n,t)=>({h:n,i:t,p:ae(n)})).sort((n,t)=>t.p-n.p||n.i-t.i).map((n)=>n.h)}function S(e,n,t){console.error(`[Events] ${e} for '${String(n)}':`,t)}function b(e){return!!e&&typeof e.catch==="function"}function M(e){let n=e??new Map,t=new Map,r=(i,f)=>{let d=t.get(i);if(!d)d=new RegExp(`^${i.replace(/\*/g,".*")}$`),t.set(i,d);return d.test(f)};function s(i,f,d){if(d?.priority!==void 0&&Number.isFinite(d.priority))f[V]=d.priority;let y=n.get(i);if(y)y.push(f);else n.set(i,[f])}function o(i,f){let d=(...y)=>(a(i,d),f(...y));d[U]=f,s(i,d)}function a(i,f){let d=n.get(i);if(!d)return;if(!f){n.set(i,[]);return}for(let y=d.length-1;y>=0;y--){let E=d[y];if(E===f||E?.[U]===f)d.splice(y,1)}}function u(i){if(i===void 0)n.clear();else n.delete(i)}function v(i){return n.get(i)?.length??0}function m(i,f){let d=n.get(i)?.slice(),y=n.get("*")?.slice(),E=d?A(d):void 0,w=y?A(y):void 0;if(E)for(let g of E)try{let c=g(f);if(b(c))c.catch((l)=>S("Async handler error",i,l))}catch(c){S("Handler error",i,c)}let p=String(i);if(n.forEach((g,c)=>{let l=String(c);if(l===p||l==="*"||!l.includes("*"))return;if(r(l,p))for(let _ of A(g.slice()))try{let L=_(i,f);if(b(L))L.catch((B)=>S(`Async pattern handler '${l}' error`,i,B))}catch(L){S(`Pattern handler '${l}' error`,i,L)}}),w)for(let g of w)try{let c=g(i,f);if(b(c))c.catch((l)=>S("Async wildcard handler error",i,l))}catch(c){S("Wildcard handler error",i,c)}}async function x(i,f){let d=[],y=async(p,g)=>{if(!p)return;for(let c of A(p.slice()))try{let l=g?c(i,f):c(f);d.push(b(l)?await l:l)}catch(l){S("Awaited handler error",i,l),d.push(void 0)}};await y(n.get(i),!1);let E=String(i),w=[];n.forEach((p,g)=>{let c=String(g);if(c===E||c==="*"||!c.includes("*"))return;if(r(c,E))w.push(c)});for(let p of w)await y(n.get(p),!0);return await y(n.get("*"),!0),d}async function H(i,f){let d=[],y=async(p,g)=>{if(!p)return;for(let c of A(p.slice()))try{let l=g?c(i,f):c(f),_=b(l)?await l:l;d.push({ok:!0,value:_})}catch(l){let _=l instanceof Error?l:Error(String(l));d.push({ok:!1,error:_})}};await y(n.get(i),!1);let E=String(i),w=[];n.forEach((p,g)=>{let c=String(g);if(c===E||c==="*"||!c.includes("*"))return;if(r(c,E))w.push(c)});for(let p of w)await y(n.get(p),!0);return await y(n.get("*"),!0),d}return{all:n,on:s,once:o,off:a,emit:m,emitAsync:x,emitAndCollect:H,removeAllListeners:u,listenerCount:v}}var pe=M,He=M;function ce(e,n){let t=(r)=>`${n}:${r}`;return{on(r,s,o){e.on(t(r),s,o)},once(r,s){e.once(t(r),s)},off(r,s){e.off(t(r),s)},emit(r,s){e.emit(t(r),s)},emitAsync(r,s){return e.emitAsync(t(r),s)},emitAndCollect(r,s){return e.emitAndCollect(t(r),s)},listenerCount(r){return e.listenerCount(t(r))}}}function ge(e){return e}var F=Symbol.for("stacks.events.emitter"),I=globalThis,N=I[F]??(I[F]=M()),h=N,me=N,de=h.emit,Ee=h.emitAsync,ke=h.emitAndCollect,we=de,he=h.all,R=h.on,xe=h.on,Se=h.once,_e=h.off;function Ae(e){return ce(N,e)}export{he as all,M as createEmitter,He as default,ge as defineEvents,z as defineListener,C as discoverListeners,de as dispatch,ke as dispatchAndCollect,Ee as dispatchAsync,h as emitter,N as events,R as listen,pe as mitt,_e as off,Se as once,ee as registerAppListeners,Z as resetListenerRegistry,se as resetNameRegistries,ce as scope,Ae as scopedEvents,we as useEvent,me as useEvents,xe as useListen};
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/events",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.72.97",
5
+ "version": "0.72.99",
6
6
  "description": "Functional event emitting.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [