@stacksjs/events 0.75.36 → 0.75.37

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.
@@ -41,6 +41,29 @@ export declare function defineListener<const T extends EventSubscription>(listen
41
41
  export declare function discoverListeners(options?: DiscoverOptions): Promise<number>;
42
42
  /** For tests, and for a dev server that genuinely wants to start over. */
43
43
  export declare function resetListenerRegistry(): void;
44
+ /**
45
+ * Whether this process has started registering the application's listeners.
46
+ * True from the moment {@link bootAppListeners} is called, not when it
47
+ * finishes, so a listener that dispatches while it is being imported does not
48
+ * read as a process that never booted.
49
+ */
50
+ export declare function appListenersBooted(): boolean;
51
+ /**
52
+ * Register the application's listeners in this process, once.
53
+ *
54
+ * Every entry point that runs application code calls this - the HTTP server
55
+ * (through `injectGlobalAutoImports`), the scheduler, the queue worker, a
56
+ * seeder, an application command - and a process that goes through two of
57
+ * them (a dev server that also runs the scheduler, a command that calls the
58
+ * seeder) still registers once: the first call's promise is what every later
59
+ * call gets. The per-listener registry below that makes the same guarantee
60
+ * for anything that calls {@link registerAppListeners} directly.
61
+ *
62
+ * Returns how many listeners the first call registered. When the application
63
+ * declares listeners and none could be registered, it says so here, at
64
+ * startup, rather than leaving the first missing notification to say it.
65
+ */
66
+ export declare function bootAppListeners(options?: RegisterOptions): Promise<number>;
44
67
  /**
45
68
  * Register every listener the application declares, from both conventions.
46
69
  *
package/dist/index.d.ts CHANGED
@@ -324,6 +324,6 @@ export {
324
324
  // Boot-time listener auto-discovery (stacksjs/stacks#1878 E-3,
325
325
  // closing F-3 from #1874). Scans `app/Listeners/**/*.ts` for
326
326
  // default-exported `{ listensTo, handle }` modules and registers them.
327
- export { defineListener, discoverListeners, registerAppListeners, resetListenerRegistry, resetNameRegistries } from './discover';
327
+ export { appListenersBooted, bootAppListeners, defineListener, discoverListeners, registerAppListeners, resetListenerRegistry, resetNameRegistries } from './discover';
328
328
  // Default export keeps `import mitt from '@stacksjs/events'` shape working.
329
329
  export default createEmitter;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // @bun
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 O from"process";function z(e){return e}async function C(e={}){let n=e.dir??k(O.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 f=await import(a),v=f?.default??f;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 E of X(v.listensTo)){if(!D(E,a))continue;R(E,(x)=>v.handle(x,E)),o++}}catch(f){r.error(`[events/discover] failed to import ${a}: ${f instanceof Error?f.message:String(f)}`)}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??O.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 f of Array.isArray(a)?a:[a]){if(typeof f!=="string"||!f.trim())continue;let v=await ie(e,f.trim());if(!v){n.warn(`[events] ${o}: no listener or action called ${f}`);continue}if(!D(o,v.id))continue;let{handle:E,validations:x}=v;R(o,(H)=>(te(o,f,H,x,n),E(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[f,v]of Object.entries(r)){let E=v?.rule?.validate;if(typeof E!=="function")continue;try{if(!E(o[f]).valid)a.push(f)}catch{a.push(f)}}if(a.length)s.warn(`[events] ${e}: payload does not match what ${n} declares (${a.join(", ")})`)}var P=new Map;async function N(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(([E,x])=>[E,q(a,x)]))}catch{return null}})();return P.set(r,o),o}async function re(e,n){let t=await N(e,"listeners","listeners"),r=await N(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,f=a?.handle;if(typeof f!=="function")continue;return{id:s,handle:f.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){if(e.length<2)return 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 WeakMap,r=(i,y,d)=>{let u=t.get(d),p=u?.key===i?u.re:void 0;if(!p)p=new RegExp(`^${i.replace(/\*/g,".*")}$`),t.set(d,{key:i,re:p});return p.test(y)};function s(i,y,d){if(d?.priority!==void 0&&Number.isFinite(d.priority))y[V]=d.priority;let u=n.get(i);if(u)u.push(y);else n.set(i,[y])}function o(i,y){let d=(...u)=>(a(i,d),y(...u));d[U]=y,s(i,d)}function a(i,y){let d=n.get(i);if(!d)return;if(!y){n.set(i,[]);return}for(let u=d.length-1;u>=0;u--){let p=d[u];if(p===y||p?.[U]===y)d.splice(u,1)}}function f(i){if(i===void 0)n.clear();else n.delete(i)}function v(i){return n.get(i)?.length??0}function E(i,y){let d=n.get(i)?.slice(),u=n.get("*")?.slice(),p=d?A(d):void 0,w=u?A(u):void 0;if(p)for(let m of p)try{let c=m(y);if(b(c))c.catch((l)=>S("Async handler error",i,l))}catch(c){S("Handler error",i,c)}let g=String(i);if(n.forEach((m,c)=>{let l=String(c);if(l===g||l==="*"||!l.includes("*"))return;if(r(l,g,m))for(let _ of A(m.slice()))try{let L=_(i,y);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 m of w)try{let c=m(i,y);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,y){let d=[],u=async(g,m)=>{if(!g)return;for(let c of A(g.slice()))try{let l=m?c(i,y):c(y);d.push(b(l)?await l:l)}catch(l){S("Awaited handler error",i,l),d.push(void 0)}};await u(n.get(i),!1);let p=String(i),w=[];n.forEach((g,m)=>{let c=String(m);if(c===p||c==="*"||!c.includes("*"))return;if(r(c,p,g))w.push(c)});for(let g of w)await u(n.get(g),!0);return await u(n.get("*"),!0),d}async function H(i,y){let d=[],u=async(g,m)=>{if(!g)return;for(let c of A(g.slice()))try{let l=m?c(i,y):c(y),_=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 u(n.get(i),!1);let p=String(i),w=[];n.forEach((g,m)=>{let c=String(m);if(c===p||c==="*"||!c.includes("*"))return;if(r(c,p,g))w.push(c)});for(let g of w)await u(n.get(g),!0);return await u(n.get("*"),!0),d}return{all:n,on:s,once:o,off:a,emit:E,emitAsync:x,emitAndCollect:H,removeAllListeners:f,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,W=I[F]??(I[F]=M()),h=W,me=W,{emit:de,emitAsync:Ee,emitAndCollect:ke}=h,we=de,{all:he,on:R,on:xe,once:Se,off:_e}=h;function Ae(e){return ce(W,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,W 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};
2
+ import{existsSync as _,readdirSync as ne,statSync as te}from"fs";import{extname as re,join as k,resolve as se}from"path";import M from"process";function oe(e){return e}async function U(e={}){let n=e.dir??k(M.cwd(),"app","Listeners"),t=e.extensions??[".ts",".js"],r={warn:e.log?.warn??((i)=>console.warn(i)),error:e.log?.error??((i)=>console.error(i)),info:e.log?.info??((i)=>console.info(i))};if(!_(n))return 0;let s=V(n,t);if(s.length===0)return 0;let o=0;for(let i of s)try{let u=await import(i),v=u?.default??u;if(typeof v==="function")continue;if(!ie(v)){r.warn(`[events/discover] ${i}: default export doesn't match ListenerModule shape ({ listensTo, handle }), skipping`);continue}for(let E of ae(v.listensTo)){if(!G(E,i))continue;W(E,(b)=>v.handle(b,E)),o++}}catch(u){r.error(`[events/discover] failed to import ${i}: ${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 V(e,n){let t=[],r=ne(e);for(let s of r){let o=k(e,s),i=te(o);if(i.isDirectory())t.push(...V(o,n));else if(i.isFile()&&n.includes(re(s)))t.push(o)}return t}function ie(e){let n=e?.listensTo;return!!e&&typeof e==="object"&&(typeof n==="string"||Array.isArray(n))&&typeof e.handle==="function"}function ae(e){return(Array.isArray(e)?e:[e]).map((t)=>String(t).trim()).filter(Boolean)}var I=Symbol.for("stacks.events.claimedListeners"),C=globalThis[I]??(globalThis[I]=new Set);function G(e,n){let t=`${e}\x00${n}`;if(C.has(t))return!1;return C.add(t),!0}function ce(){C.clear(),delete x()[R],x()[K]=J}var R=Symbol.for("stacks.events.appListenersBoot"),K=Symbol.for("stacks.events.dispatchObserver");function x(){return globalThis}function O(){return x()[R]!==void 0}function de(e={}){let n=x(),t=n[R];if(t)return t;let r=(async()=>{let s=e.base??M.cwd(),o=await q(e);if(o===0){let i=await Y(s);if(i>0)(e.log?.warn??((v)=>console.warn(v)))(`[events] app/Events.ts declares ${i} listener${i===1?"":"s"}, but none could be registered in this process, so the events they handle will reach nobody. See the errors above.`)}return o})();return n[R]=r,r}async function Y(e){let n=["ts","js"].map((t)=>k(e,"app",`Events.${t}`)).find((t)=>_(t));if(!n)return 0;try{let t=await import(n),r=t?.default??t;if(!r||typeof r!=="object")return 0;return Object.values(r).flatMap((s)=>Array.isArray(s)?s:[s]).filter((s)=>typeof s==="string"&&s.trim()!=="").length}catch{return 0}}function J(e){let n=x();if(delete n[K],O())return;let t=M.cwd();Y(t).then((r)=>{if(r===0||O())return;console.warn(`[events] "${e}" was dispatched, but this process never registered the application's listeners, so nothing handles it or any later event (app/Events.ts declares ${r}). An entry point that runs application code must call injectGlobalAutoImports() from @stacksjs/server, or bootAppListeners() from @stacksjs/events, before its first dispatch.`)})}if(!x()[K]&&!O())x()[K]=J;async function q(e={}){let n=e.base??M.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 le(n,t),r+=await U({...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 le(e,n){let t=["ts","js"].map((o)=>k(e,"app",`Events.${o}`)).find((o)=>_(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,i]of Object.entries(r))for(let u of Array.isArray(i)?i:[i]){if(typeof u!=="string"||!u.trim())continue;let v=await pe(e,u.trim());if(!v){n.warn(`[events] ${o}: no listener or action called ${u}`);continue}if(!G(o,v.id))continue;let{handle:E,validations:b}=v;W(o,(T)=>(ue(o,u,T,b,n),E(T,o))),s++}return s}function ue(e,n,t,r,s){if(!r||typeof t!=="object"||t===null)return;let o=t,i=[];for(let[u,v]of Object.entries(r)){let E=v?.rule?.validate;if(typeof E!=="function")continue;try{if(!E(o[u]).valid)i.push(u)}catch{i.push(u)}}if(i.length)s.warn(`[events] ${e}: payload does not match what ${n} declares (${i.join(", ")})`)}var j=new Map;async function F(e,n,t){let r=`${e}:${n}`,s=j.get(r);if(s)return s;let o=(async()=>{try{let i=k(e,"storage","framework","auto-imports"),v=(await import(k(i,`${n}.ts`)))[t];if(!v)return null;return Object.fromEntries(Object.entries(v).map(([E,b])=>[E,se(i,b)]))}catch{return null}})();return j.set(r,o),o}async function fe(e,n){let t=await F(e,"listeners","listeners"),r=await F(e,"actions","actions");if(!t&&!r)return null;return t?.[n]??r?.[`Actions/${n}`]??null}function ye(){j.clear()}function ve(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))}async function pe(e,n){let t=[],r=await fe(e,n);if(r)t.push(r);for(let s of ve(e))for(let o of["Listeners","Actions"])for(let i of["ts","js"])t.push(k(s,o,`${n}.${i}`));for(let s of t){if(!_(s))continue;try{let o=await import(s),i=o?.default??o,u=i?.handle;if(typeof u!=="function")continue;return{id:s,handle:u.bind(i),validations:i?.validations}}catch{continue}}return null}var z=Symbol.for("stacks.events.handler.error"),Z=Symbol.for("stacks.events.handler.priority");function ge(e){if(e&&typeof e==="object"||typeof e==="function"){let n=e[Z];return typeof n==="number"&&Number.isFinite(n)?n:0}return 0}function H(e){if(e.length<2)return e;return e.map((n,t)=>({h:n,i:t,p:ge(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 L(e){return!!e&&typeof e.catch==="function"}function N(e){let n=e??new Map,t=new WeakMap,r=(a,y,d)=>{let f=t.get(d),p=f?.key===a?f.re:void 0;if(!p)p=new RegExp(`^${a.replace(/\*/g,".*")}$`),t.set(d,{key:a,re:p});return p.test(y)};function s(a,y,d){if(d?.priority!==void 0&&Number.isFinite(d.priority))y[Z]=d.priority;let f=n.get(a);if(f)f.push(y);else n.set(a,[y])}function o(a,y){let d=(...f)=>(i(a,d),y(...f));d[z]=y,s(a,d)}function i(a,y){let d=n.get(a);if(!d)return;if(!y){n.set(a,[]);return}for(let f=d.length-1;f>=0;f--){let p=d[f];if(p===y||p?.[z]===y)d.splice(f,1)}}function u(a){if(a===void 0)n.clear();else n.delete(a)}function v(a){return n.get(a)?.length??0}function E(a,y){let d=n.get(a)?.slice(),f=n.get("*")?.slice(),p=d?H(d):void 0,h=f?H(f):void 0;if(p)for(let m of p)try{let c=m(y);if(L(c))c.catch((l)=>S("Async handler error",a,l))}catch(c){S("Handler error",a,c)}let g=String(a);if(n.forEach((m,c)=>{let l=String(c);if(l===g||l==="*"||!l.includes("*"))return;if(r(l,g,m))for(let A of H(m.slice()))try{let P=A(a,y);if(L(P))P.catch((ee)=>S(`Async pattern handler '${l}' error`,a,ee))}catch(P){S(`Pattern handler '${l}' error`,a,P)}}),h)for(let m of h)try{let c=m(a,y);if(L(c))c.catch((l)=>S("Async wildcard handler error",a,l))}catch(c){S("Wildcard handler error",a,c)}}async function b(a,y){let d=[],f=async(g,m)=>{if(!g)return;for(let c of H(g.slice()))try{let l=m?c(a,y):c(y);d.push(L(l)?await l:l)}catch(l){S("Awaited handler error",a,l),d.push(void 0)}};await f(n.get(a),!1);let p=String(a),h=[];n.forEach((g,m)=>{let c=String(m);if(c===p||c==="*"||!c.includes("*"))return;if(r(c,p,g))h.push(c)});for(let g of h)await f(n.get(g),!0);return await f(n.get("*"),!0),d}async function T(a,y){let d=[],f=async(g,m)=>{if(!g)return;for(let c of H(g.slice()))try{let l=m?c(a,y):c(y),A=L(l)?await l:l;d.push({ok:!0,value:A})}catch(l){let A=l instanceof Error?l:Error(String(l));d.push({ok:!1,error:A})}};await f(n.get(a),!1);let p=String(a),h=[];n.forEach((g,m)=>{let c=String(m);if(c===p||c==="*"||!c.includes("*"))return;if(r(c,p,g))h.push(c)});for(let g of h)await f(n.get(g),!0);return await f(n.get("*"),!0),d}return{all:n,on:s,once:o,off:i,emit:E,emitAsync:b,emitAndCollect:T,removeAllListeners:u,listenerCount:v}}var Ae=N,je=N;function me(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 _e(e){return e}var Q=Symbol.for("stacks.events.emitter"),X=globalThis,D=X[Q]??(X[Q]=N()),w=D,He=D,Ee=Symbol.for("stacks.events.dispatchObserver");function B(e){let n=globalThis[Ee];if(n)n(String(e))}var ke=(e,n)=>(B(e),w.emit(e,n)),Le=(e,n)=>(B(e),w.emitAsync(e,n)),Te=(e,n)=>(B(e),w.emitAndCollect(e,n)),Pe=ke,{all:Re,on:W,on:Ke,once:$e,off:Oe}=w;function Me(e){return me(D,e)}export{Re as all,O as appListenersBooted,de as bootAppListeners,N as createEmitter,je as default,_e as defineEvents,oe as defineListener,U as discoverListeners,ke as dispatch,Te as dispatchAndCollect,Le as dispatchAsync,w as emitter,D as events,W as listen,Ae as mitt,Oe as off,$e as once,q as registerAppListeners,ce as resetListenerRegistry,ye as resetNameRegistries,me as scope,Me as scopedEvents,Pe as useEvent,He as useEvents,Ke 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.75.36",
5
+ "version": "0.75.37",
6
6
  "description": "Functional event emitting.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [