@stacksjs/events 0.70.348 → 0.70.350

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,4 +1,3 @@
1
- import type { Handler } from './index';
2
1
  /**
3
2
  * Walk the listeners directory and register every default-exported
4
3
  * listener that matches the `ListenerModule` shape. Returns the
@@ -15,6 +14,25 @@ import type { Handler } from './index';
15
14
  * ```
16
15
  */
17
16
  export declare function discoverListeners(options?: DiscoverOptions): Promise<number>;
17
+ /** For tests, and for a dev server that genuinely wants to start over. */
18
+ export declare function resetListenerRegistry(): void;
19
+ /**
20
+ * Register every listener the application declares, from both conventions.
21
+ *
22
+ * This is the function a boot path calls. It reads `app/Events.ts` - the map of
23
+ * event name to listener names that the file's own comment documents - and then
24
+ * scans `app/Listeners/` for anything that declares its own `listensTo`.
25
+ *
26
+ * Both halves are needed and neither subsumes the other. The map is how an
27
+ * application says three listeners share one event and in what order; the scan
28
+ * is how a listener that stands alone avoids a second edit in a second file.
29
+ * The registry above stops a listener that does both from running twice.
30
+ *
31
+ * Returns how many (event, listener) pairs were registered. Never throws: a
32
+ * broken listener file must not stop a server from starting, because the
33
+ * alternative is an application that will not boot over a typo in a notifier.
34
+ */
35
+ export declare function registerAppListeners(options?: RegisterOptions): Promise<number>;
18
36
  /**
19
37
  * Shape of a listener module's default export. The `listensTo`
20
38
  * field is the event name (matches the strict type of
@@ -22,8 +40,8 @@ export declare function discoverListeners(options?: DiscoverOptions): Promise<nu
22
40
  * `handle` is the actual listener function.
23
41
  */
24
42
  export declare interface ListenerModule<T = unknown> {
25
- listensTo: string
26
- handle: Handler<T>
43
+ listensTo: string | string[]
44
+ handle: (_payload: T, _eventName?: string) => void | Promise<void>
27
45
  name?: string
28
46
  }
29
47
  declare interface DiscoverOptions {
@@ -35,3 +53,6 @@ declare interface DiscoverOptions {
35
53
  info?: (msg: string) => void
36
54
  }
37
55
  }
56
+ declare interface RegisterOptions extends DiscoverOptions {
57
+ base?: string
58
+ }
package/dist/index.d.ts CHANGED
@@ -148,6 +148,6 @@ export {
148
148
  // Boot-time listener auto-discovery (stacksjs/stacks#1878 E-3,
149
149
  // closing F-3 from #1874). Scans `app/Listeners/**/*.ts` for
150
150
  // default-exported `{ listensTo, handle }` modules and registers them.
151
- export { discoverListeners } from './discover';
151
+ export { discoverListeners, registerAppListeners, resetListenerRegistry } from './discover';
152
152
  // Default export keeps `import mitt from '@stacksjs/events'` shape working.
153
153
  export default createEmitter;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{existsSync as g,readdirSync as v,statSync as u}from"fs";import{extname as m,join as R}from"path";import c from"process";async function h(z={}){let q=z.dir??R(c.cwd(),"app","Listeners"),Z=z.extensions??[".ts",".js"],V={warn:z.log?.warn??((F)=>console.warn(F)),error:z.log?.error??((F)=>console.error(F)),info:z.log?.info??((F)=>console.info(F))};if(!g(q))return 0;let M=P(q,Z);if(M.length===0)return 0;let O=0;for(let F of M)try{let K=await import(F),N=K?.default??K;if(!o(N)){V.warn(`[events/discover] ${F}: default export doesn't match ListenerModule shape ({ listensTo, handle }), skipping`);continue}E(N.listensTo,N.handle),O++}catch(K){V.error(`[events/discover] failed to import ${F}: ${K instanceof Error?K.message:String(K)}`)}if(O>0)V.info(`[events/discover] registered ${O} listener${O===1?"":"s"} from ${q}`);return O}function P(z,q){let Z=[],V=v(z);for(let M of V){let O=R(z,M),F=u(O);if(F.isDirectory())Z.push(...P(O,q));else if(F.isFile()&&q.includes(m(M)))Z.push(O)}return Z}function o(z){return!!z&&typeof z==="object"&&typeof z.listensTo==="string"&&typeof z.handle==="function"}var w=Symbol.for("stacks.events.handler.error"),x=Symbol.for("stacks.events.handler.priority");function d(z){if(z&&typeof z==="object"||typeof z==="function"){let q=z[x];return typeof q==="number"&&Number.isFinite(q)?q:0}return 0}function b(z){return z.map((q,Z)=>({h:q,i:Z,p:d(q)})).sort((q,Z)=>Z.p-q.p||q.i-Z.i).map((q)=>q.h)}function B(z,q,Z){console.error(`[Events] ${z} for '${String(q)}':`,Z)}function C(z){return!!z&&typeof z.catch==="function"}function T(z){let q=z??new Map,Z=new Map,V=(J,$)=>{let U=Z.get(J);if(!U)U=new RegExp(`^${J.replace(/\*/g,".*")}$`),Z.set(J,U);return U.test($)};function M(J,$,U){if(U?.priority!==void 0&&Number.isFinite(U.priority))$[x]=U.priority;let j=q.get(J);if(j)j.push($);else q.set(J,[$])}function O(J,$){let U=(...j)=>{return F(J,U),$(...j)};U[w]=$,M(J,U)}function F(J,$){let U=q.get(J);if(!U)return;if(!$){q.set(J,[]);return}for(let j=U.length-1;j>=0;j--){let I=U[j];if(I===$||I?.[w]===$)U.splice(j,1)}}function K(J){if(J===void 0)q.clear();else q.delete(J)}function N(J){return q.get(J)?.length??0}function f(J,$){let U=q.get(J)?.slice(),j=q.get("*")?.slice(),I=U?b(U):void 0,W=j?b(j):void 0;if(I)for(let D of I)try{let Q=D($);if(C(Q))Q.catch((X)=>B("Async handler error",J,X))}catch(Q){B("Handler error",J,Q)}let G=String(J);if(q.forEach((D,Q)=>{let X=String(Q);if(X===G||X==="*"||!X.includes("*"))return;if(V(X,G))for(let _ of b(D.slice()))try{let H=_(J,$);if(C(H))H.catch((k)=>B(`Async pattern handler '${X}' error`,J,k))}catch(H){B(`Pattern handler '${X}' error`,J,H)}}),W)for(let D of W)try{let Q=D(J,$);if(C(Q))Q.catch((X)=>B("Async wildcard handler error",J,X))}catch(Q){B("Wildcard handler error",J,Q)}}async function A(J,$){let U=[],j=async(G,D)=>{if(!G)return;for(let Q of b(G.slice()))try{let X=D?Q(J,$):Q($);U.push(C(X)?await X:X)}catch(X){B("Awaited handler error",J,X),U.push(void 0)}};await j(q.get(J),!1);let I=String(J),W=[];q.forEach((G,D)=>{let Q=String(D);if(Q===I||Q==="*"||!Q.includes("*"))return;if(V(Q,I))W.push(Q)});for(let G of W)await j(q.get(G),!0);return await j(q.get("*"),!0),U}async function S(J,$){let U=[],j=async(G,D)=>{if(!G)return;for(let Q of b(G.slice()))try{let X=D?Q(J,$):Q($),_=C(X)?await X:X;U.push({ok:!0,value:_})}catch(X){let _=X instanceof Error?X:Error(String(X));U.push({ok:!1,error:_})}};await j(q.get(J),!1);let I=String(J),W=[];q.forEach((G,D)=>{let Q=String(D);if(Q===I||Q==="*"||!Q.includes("*"))return;if(V(Q,I))W.push(Q)});for(let G of W)await j(q.get(G),!0);return await j(q.get("*"),!0),U}return{all:q,on:M,once:O,off:F,emit:f,emitAsync:A,emitAndCollect:S,removeAllListeners:K,listenerCount:N}}var r=T,$q=T;function a(z,q){let Z=(V)=>`${q}:${V}`;return{on(V,M,O){z.on(Z(V),M,O)},once(V,M){z.once(Z(V),M)},off(V,M){z.off(Z(V),M)},emit(V,M){z.emit(Z(V),M)},emitAsync(V,M){return z.emitAsync(Z(V),M)},emitAndCollect(V,M){return z.emitAndCollect(Z(V),M)},listenerCount(V){return z.listenerCount(Z(V))}}}var L=T(),Y=L,t=L,i=Y.emit,e=Y.emitAsync,qq=Y.emitAndCollect,zq=i,Jq=Y.all,E=Y.on,Qq=Y.on,Uq=Y.once,Vq=Y.off;function Xq(z){return a(L,z)}export{Qq as useListen,t as useEvents,zq as useEvent,Xq as scopedEvents,a as scope,Uq as once,Vq as off,r as mitt,E as listen,L as events,Y as emitter,e as dispatchAsync,qq as dispatchAndCollect,i as dispatch,h as discoverListeners,$q as default,T as createEmitter,Jq as all};
2
+ import{existsSync as E,readdirSync as m,statSync as y}from"fs";import{extname as d,join as R}from"path";import S from"process";async function x(z={}){let q=z.dir??R(S.cwd(),"app","Listeners"),Q=z.extensions??[".ts",".js"],J={warn:z.log?.warn??((M)=>console.warn(M)),error:z.log?.error??((M)=>console.error(M)),info:z.log?.info??((M)=>console.info(M))};if(!E(q))return 0;let V=k(q,Q);if(V.length===0)return 0;let X=0;for(let M of V)try{let W=await import(M),B=W?.default??W;if(!o(B)){J.warn(`[events/discover] ${M}: default export doesn't match ListenerModule shape ({ listensTo, handle }), skipping`);continue}for(let N of p(B.listensTo)){if(!u(N,M))continue;T(N,(C)=>B.handle(C,N)),X++}}catch(W){J.error(`[events/discover] failed to import ${M}: ${W instanceof Error?W.message:String(W)}`)}if(X>0)J.info(`[events/discover] registered ${X} listener${X===1?"":"s"} from ${q}`);return X}function k(z,q){let Q=[],J=m(z);for(let V of J){let X=R(z,V),M=y(X);if(M.isDirectory())Q.push(...k(X,q));else if(M.isFile()&&q.includes(d(V)))Q.push(X)}return Q}function o(z){let q=z?.listensTo;return!!z&&typeof z==="object"&&(typeof q==="string"||Array.isArray(q))&&typeof z.handle==="function"}function p(z){return(Array.isArray(z)?z:[z]).map((Q)=>String(Q).trim()).filter(Boolean)}var P=new Set;function u(z,q){let Q=`${z}\x00${q}`;if(P.has(Q))return!1;return P.add(Q),!0}function a(){P.clear()}async function l(z={}){let q=z.base??S.cwd(),Q={warn:z.log?.warn??((V)=>console.warn(V)),error:z.log?.error??((V)=>console.error(V)),info:z.log?.info??((V)=>console.info(V))},J=0;if(J+=await i(q,Q),J+=await x({...z,dir:z.dir??R(q,"app","Listeners"),log:{...Q,info:()=>{}}}),J>0)Q.info(`[events] registered ${J} listener${J===1?"":"s"}`);return J}async function i(z,q){let Q=["ts","js"].map((X)=>R(z,"app",`Events.${X}`)).find((X)=>E(X));if(!Q)return 0;let J;try{let X=await import(Q);J=X?.default??X}catch(X){return q.error(`[events] failed to read ${Q}: ${X instanceof Error?X.message:String(X)}`),0}if(!J||typeof J!=="object")return 0;let V=0;for(let[X,M]of Object.entries(J))for(let W of Array.isArray(M)?M:[M]){if(typeof W!=="string"||!W.trim())continue;let B=await s(z,W.trim());if(!B){q.warn(`[events] ${X}: no listener or action called ${W}`);continue}if(!u(X,B.id))continue;let N=B.handle;T(X,(C)=>N(C,X)),V++}return V}async function s(z,q){let Q=[];for(let J of["Listeners","Actions"])for(let V of["ts","js"])Q.push(R(z,"app",J,`${q}.${V}`));for(let J of Q){if(!E(J))continue;try{let V=await import(J),X=V?.default??V,M=X?.handle;if(typeof M!=="function")continue;return{id:J,handle:M.bind(X)}}catch{continue}}return null}var v=Symbol.for("stacks.events.handler.error"),g=Symbol.for("stacks.events.handler.priority");function n(z){if(z&&typeof z==="object"||typeof z==="function"){let q=z[g];return typeof q==="number"&&Number.isFinite(q)?q:0}return 0}function w(z){return z.map((q,Q)=>({h:q,i:Q,p:n(q)})).sort((q,Q)=>Q.p-q.p||q.i-Q.i).map((q)=>q.h)}function _(z,q,Q){console.error(`[Events] ${z} for '${String(q)}':`,Q)}function b(z){return!!z&&typeof z.catch==="function"}function f(z){let q=z??new Map,Q=new Map,J=(U,D)=>{let $=Q.get(U);if(!$)$=new RegExp(`^${U.replace(/\*/g,".*")}$`),Q.set(U,$);return $.test(D)};function V(U,D,$){if($?.priority!==void 0&&Number.isFinite($.priority))D[g]=$.priority;let K=q.get(U);if(K)K.push(D);else q.set(U,[D])}function X(U,D){let $=(...K)=>{return M(U,$),D(...K)};$[v]=D,V(U,$)}function M(U,D){let $=q.get(U);if(!$)return;if(!D){q.set(U,[]);return}for(let K=$.length-1;K>=0;K--){let j=$[K];if(j===D||j?.[v]===D)$.splice(K,1)}}function W(U){if(U===void 0)q.clear();else q.delete(U)}function B(U){return q.get(U)?.length??0}function N(U,D){let $=q.get(U)?.slice(),K=q.get("*")?.slice(),j=$?w($):void 0,F=K?w(K):void 0;if(j)for(let Y of j)try{let Z=Y(D);if(b(Z))Z.catch((G)=>_("Async handler error",U,G))}catch(Z){_("Handler error",U,Z)}let O=String(U);if(q.forEach((Y,Z)=>{let G=String(Z);if(G===O||G==="*"||!G.includes("*"))return;if(J(G,O))for(let H of w(Y.slice()))try{let L=H(U,D);if(b(L))L.catch((h)=>_(`Async pattern handler '${G}' error`,U,h))}catch(L){_(`Pattern handler '${G}' error`,U,L)}}),F)for(let Y of F)try{let Z=Y(U,D);if(b(Z))Z.catch((G)=>_("Async wildcard handler error",U,G))}catch(Z){_("Wildcard handler error",U,Z)}}async function C(U,D){let $=[],K=async(O,Y)=>{if(!O)return;for(let Z of w(O.slice()))try{let G=Y?Z(U,D):Z(D);$.push(b(G)?await G:G)}catch(G){_("Awaited handler error",U,G),$.push(void 0)}};await K(q.get(U),!1);let j=String(U),F=[];q.forEach((O,Y)=>{let Z=String(Y);if(Z===j||Z==="*"||!Z.includes("*"))return;if(J(Z,j))F.push(Z)});for(let O of F)await K(q.get(O),!0);return await K(q.get("*"),!0),$}async function c(U,D){let $=[],K=async(O,Y)=>{if(!O)return;for(let Z of w(O.slice()))try{let G=Y?Z(U,D):Z(D),H=b(G)?await G:G;$.push({ok:!0,value:H})}catch(G){let H=G instanceof Error?G:Error(String(G));$.push({ok:!1,error:H})}};await K(q.get(U),!1);let j=String(U),F=[];q.forEach((O,Y)=>{let Z=String(Y);if(Z===j||Z==="*"||!Z.includes("*"))return;if(J(Z,j))F.push(Z)});for(let O of F)await K(q.get(O),!0);return await K(q.get("*"),!0),$}return{all:q,on:V,once:X,off:M,emit:N,emitAsync:C,emitAndCollect:c,removeAllListeners:W,listenerCount:B}}var Uq=f,Yq=f;function r(z,q){let Q=(J)=>`${q}:${J}`;return{on(J,V,X){z.on(Q(J),V,X)},once(J,V){z.once(Q(J),V)},off(J,V){z.off(Q(J),V)},emit(J,V){z.emit(Q(J),V)},emitAsync(J,V){return z.emitAsync(Q(J),V)},emitAndCollect(J,V){return z.emitAndCollect(Q(J),V)},listenerCount(J){return z.listenerCount(Q(J))}}}var A=f(),I=A,Vq=A,t=I.emit,Xq=I.emitAsync,Zq=I.emitAndCollect,$q=t,Gq=I.all,T=I.on,Mq=I.on,Dq=I.once,Kq=I.off;function Oq(z){return r(A,z)}export{Mq as useListen,Vq as useEvents,$q as useEvent,Oq as scopedEvents,r as scope,a as resetListenerRegistry,l as registerAppListeners,Dq as once,Kq as off,Uq as mitt,T as listen,A as events,I as emitter,Xq as dispatchAsync,Zq as dispatchAndCollect,t as dispatch,x as discoverListeners,Yq as default,f as createEmitter,Gq as all};
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.348",
5
+ "version": "0.70.350",
6
6
  "description": "Functional event emitting.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [