@statedelta-actions/events 0.3.0 → 0.5.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.
- package/README.md +29 -3
- package/dist/index.cjs +8 -4
- package/dist/index.d.cts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +8 -4
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -90,22 +90,45 @@ const result = ep.register([
|
|
|
90
90
|
ep.unregister("on-save"); // true se existia, false se não
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
+
#### Throw vs collected errors
|
|
94
|
+
|
|
95
|
+
`register` e `defineEvents` são atômicos: o registro local só é aplicado depois que o ActionEngine aceita todas as hidden actions. Comportamento por tipo de erro:
|
|
96
|
+
|
|
97
|
+
| Erro | Comportamento |
|
|
98
|
+
|------|---------------|
|
|
99
|
+
| Handler ausente para um tipo de diretiva em `then` (qualquer profundidade, inclusive `catch`) | **Lança `Error`** propagado do `actionEngine.register`. Estado local intocado. |
|
|
100
|
+
| Listener/event duplicado, missing required field, tier violation contra `EventDefinition` | Coletado em `errors[]`. Outros itens válidos no mesmo call ainda registram. |
|
|
101
|
+
| `validate()` de handler retorna invalid ou lança | Coletado em `errors[]`. |
|
|
102
|
+
|
|
103
|
+
Throw é reservado pra erros estruturais que não viram válidos em runtime — typo, handler esquecido, refactor incompleto. Soft errors são domain-level e merecem inspeção pelo consumer.
|
|
104
|
+
|
|
93
105
|
### Processing
|
|
94
106
|
|
|
95
107
|
```typescript
|
|
96
|
-
// Sync (throws se
|
|
108
|
+
// Sync (throws se algum listener é async ou interactive transitivamente)
|
|
97
109
|
const result = ep.processEvents(
|
|
98
110
|
[{ event: "save" }, { event: "damage", data: { amount: 10 } }],
|
|
99
111
|
ctx,
|
|
100
112
|
);
|
|
101
113
|
|
|
102
|
-
// Async (
|
|
114
|
+
// Async (throws se algum listener é interactive transitivamente)
|
|
103
115
|
const result = await ep.processEventsAsync(
|
|
104
116
|
[{ event: "save" }],
|
|
105
117
|
ctx,
|
|
106
118
|
);
|
|
119
|
+
|
|
120
|
+
// Interactive — retorna iterator drenável (sync ou async generator)
|
|
121
|
+
const session = ep.processEventsInteractive([{ event: "save" }], ctx);
|
|
122
|
+
let step = session.next();
|
|
123
|
+
while (!step.done) {
|
|
124
|
+
// step.value = payload do yield (PauseEvent ou payload de handler interactive)
|
|
125
|
+
step = session.next(/* resposta do consumer */);
|
|
126
|
+
}
|
|
127
|
+
// step.value = EventProcessingResult
|
|
107
128
|
```
|
|
108
129
|
|
|
130
|
+
`processEventsInteractive` lança se nenhum listener registrado é interactive transitivamente. Pausas fluem via `yield*` em 3 níveis (consumer → events generator → `actionEngine.invokeInteractive`). Halt scoping preservado: pause/halt num listener para os listeners daquele evento; próximos eventos na fila continuam.
|
|
131
|
+
|
|
109
132
|
### Batch
|
|
110
133
|
|
|
111
134
|
```typescript
|
|
@@ -124,9 +147,12 @@ ep.compile();
|
|
|
124
147
|
|
|
125
148
|
// Consultar modo atual
|
|
126
149
|
ep.compilationMode; // "interpret" | "jit"
|
|
127
|
-
ep.isAsync; // true se hooks
|
|
150
|
+
ep.isAsync; // true se hooks são async OU se algum listener é async transitivamente
|
|
151
|
+
ep.isInteractive; // true se algum listener é interactive transitivamente
|
|
128
152
|
```
|
|
129
153
|
|
|
154
|
+
`isAsync` e `isInteractive` são per-listener transitivos. Engine híbrido (handler async + listener cuja sub-árvore é 100% sync) mantém `processEvents` (sync) viável — só listeners que invocam handler async transitivamente forçam `processEventsAsync`, só listeners interactive transitivamente forçam `processEventsInteractive`. Detecção via mini-graph do ActionEngine, refrescada em register/unregister/endBatch. O dispatcher interactive é lazy — só construído na primeira chamada de `processEventsInteractive` (custo zero pra engines sem nada interactive).
|
|
155
|
+
|
|
130
156
|
---
|
|
131
157
|
|
|
132
158
|
## Hooks — EventHooks
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
'use strict';var core=require('@statedelta-actions/core');function
|
|
2
|
-
`),p=r?"async ":"",
|
|
1
|
+
'use strict';var core=require('@statedelta-actions/core');function N(){return {rulesEvaluated:0,rulesMatched:0,rulesSkipped:0,directivesApplied:0,directivesSkipped:0,subRunsCreated:0,errors:0}}function O(t,n){t.rulesEvaluated+=n.rulesEvaluated,t.rulesMatched+=n.rulesMatched,t.rulesSkipped+=n.rulesSkipped,t.directivesApplied+=n.directivesApplied,t.directivesSkipped+=n.directivesSkipped,t.subRunsCreated+=n.subRunsCreated,t.errors+=n.errors;}function M(t,n,r,o){let a=o?Object.assign({},o):{};for(let d of t)Object.assign(a,d(n,r,a));return a}function J(t){let n=t.filledNames.has("beforeEvent"),r=t.filledNames.has("afterEvent"),o=t.filledNames.has("onEventsComplete");return function(d,f,g,s,c,l){let E=[],y=[],e=[],k=N(),R=c.length>0;s.setContext(g);for(let p of f){let _=d.get(p.event);if(!_||_.length===0){y.push(p.event);continue}let b=[],A=[],S=[],C=[],i=N(),w=false,T,D={ctx:g,counters:i,event:p.event},L={$event:{type:p.event,data:p.data}};for(let h=0;h<_.length;h++){let m=_[h];if(i.rulesEvaluated++,n)try{let v=l.beforeEvent(m.definition,D);if(v==="skip"){A.push(h),i.rulesSkipped++;continue}if(v==="abort")break}catch(v){C.push({ruleIndex:h,error:`beforeEvent: ${v}`}),i.errors++;}b.push(h),i.rulesMatched++;let x;if(R)try{x=M(c,m.definition,g,L);}catch(v){C.push({ruleIndex:h,error:`Middleware: ${v}`}),i.errors++;continue}else x=L;let u=s.invoke(m.actionId,x);if(i.directivesApplied+=u.appliedCount,i.directivesSkipped+=u.skippedCount,i.errors+=u.errors.length,r)try{if(l.afterEvent(m.definition,u,D)==="abort")break}catch{}if(u.aborted){w=true,T=u.abortedBy;break}}e.push(...C),O(k,i),E.push({event:p.event,matched:b,skipped:A,notMatched:S,errors:C,halted:w,haltedBy:T,counters:i});}let I={eventResults:E,unprocessedEvents:y,errors:e,counters:k,totalEvents:f.length,processedEvents:E.length};if(o)try{l.onEventsComplete(I);}catch{}return I}}function z(t){let n=t.filledNames.has("beforeEvent"),r=t.filledNames.has("afterEvent"),o=t.filledNames.has("onEventsComplete");return async function(d,f,g,s,c,l){let E=[],y=[],e=[],k=N(),R=c.length>0;s.setContext(g);for(let p of f){let _=d.get(p.event);if(!_||_.length===0){y.push(p.event);continue}let b=[],A=[],S=[],C=[],i=N(),w=false,T,D={ctx:g,counters:i,event:p.event},L={$event:{type:p.event,data:p.data}};for(let h=0;h<_.length;h++){let m=_[h];if(i.rulesEvaluated++,n)try{let v=await l.beforeEvent(m.definition,D);if(v==="skip"){A.push(h),i.rulesSkipped++;continue}if(v==="abort")break}catch(v){C.push({ruleIndex:h,error:`beforeEvent: ${v}`}),i.errors++;}b.push(h),i.rulesMatched++;let x;if(R)try{x=M(c,m.definition,g,L);}catch(v){C.push({ruleIndex:h,error:`Middleware: ${v}`}),i.errors++;continue}else x=L;let u=await s.invokeAsync(m.actionId,x);if(i.directivesApplied+=u.appliedCount,i.directivesSkipped+=u.skippedCount,i.errors+=u.errors.length,r)try{if(await l.afterEvent(m.definition,u,D)==="abort")break}catch{}if(u.aborted){w=true,T=u.abortedBy;break}}e.push(...C),O(k,i),E.push({event:p.event,matched:b,skipped:A,notMatched:S,errors:C,halted:w,haltedBy:T,counters:i});}let I={eventResults:E,unprocessedEvents:y,errors:e,counters:k,totalEvents:f.length,processedEvents:E.length};if(o)try{await l.onEventsComplete(I);}catch{}return I}}function $(t,n){return n?z(t):J(t)}function P(){return {rulesEvaluated:0,rulesMatched:0,rulesSkipped:0,directivesApplied:0,directivesSkipped:0,subRunsCreated:0,errors:0}}function j(t,n){t.rulesEvaluated+=n.rulesEvaluated,t.rulesMatched+=n.rulesMatched,t.rulesSkipped+=n.rulesSkipped,t.directivesApplied+=n.directivesApplied,t.directivesSkipped+=n.directivesSkipped,t.subRunsCreated+=n.subRunsCreated,t.errors+=n.errors;}function K(t){let n=t.filledNames.has("beforeEvent"),r=t.filledNames.has("afterEvent"),o=t.filledNames.has("onEventsComplete");return function*(d,f,g,s,c,l){let E=[],y=[],e=[],k=P(),R=c.length>0;s.setContext(g);for(let p of f){let _=d.get(p.event);if(!_||_.length===0){y.push(p.event);continue}let b=[],A=[],S=[],C=[],i=P(),w=false,T,D={ctx:g,counters:i,event:p.event},L={$event:{type:p.event,data:p.data}};for(let h=0;h<_.length;h++){let m=_[h];if(i.rulesEvaluated++,n)try{let v=l.beforeEvent(m.definition,D);if(v==="skip"){A.push(h),i.rulesSkipped++;continue}if(v==="abort")break}catch(v){C.push({ruleIndex:h,error:`beforeEvent: ${v}`}),i.errors++;}b.push(h),i.rulesMatched++;let x;if(R)try{x=M(c,m.definition,g,L);}catch(v){C.push({ruleIndex:h,error:`Middleware: ${v}`}),i.errors++;continue}else x=L;let u;if(m.isInteractive?u=yield*s.invokeInteractive(m.actionId,x):u=s.invoke(m.actionId,x),i.directivesApplied+=u.appliedCount,i.directivesSkipped+=u.skippedCount,i.errors+=u.errors.length,r)try{if(l.afterEvent(m.definition,u,D)==="abort")break}catch{}if(u.aborted){w=true,T=u.abortedBy;break}}e.push(...C),j(k,i),E.push({event:p.event,matched:b,skipped:A,notMatched:S,errors:C,halted:w,haltedBy:T,counters:i});}let I={eventResults:E,unprocessedEvents:y,errors:e,counters:k,totalEvents:f.length,processedEvents:E.length};if(o)try{l.onEventsComplete(I);}catch{}return I}}function X(t){let n=t.filledNames.has("beforeEvent"),r=t.filledNames.has("afterEvent"),o=t.filledNames.has("onEventsComplete");return async function*(d,f,g,s,c,l){let E=[],y=[],e=[],k=P(),R=c.length>0;s.setContext(g);for(let p of f){let _=d.get(p.event);if(!_||_.length===0){y.push(p.event);continue}let b=[],A=[],S=[],C=[],i=P(),w=false,T,D={ctx:g,counters:i,event:p.event},L={$event:{type:p.event,data:p.data}};for(let h=0;h<_.length;h++){let m=_[h];if(i.rulesEvaluated++,n)try{let v=await l.beforeEvent(m.definition,D);if(v==="skip"){A.push(h),i.rulesSkipped++;continue}if(v==="abort")break}catch(v){C.push({ruleIndex:h,error:`beforeEvent: ${v}`}),i.errors++;}b.push(h),i.rulesMatched++;let x;if(R)try{x=M(c,m.definition,g,L);}catch(v){C.push({ruleIndex:h,error:`Middleware: ${v}`}),i.errors++;continue}else x=L;let u;if(m.isInteractive?u=yield*s.invokeInteractive(m.actionId,x):m.isAsync?u=await s.invokeAsync(m.actionId,x):u=s.invoke(m.actionId,x),i.directivesApplied+=u.appliedCount,i.directivesSkipped+=u.skippedCount,i.errors+=u.errors.length,r)try{if(await l.afterEvent(m.definition,u,D)==="abort")break}catch{}if(u.aborted){w=true,T=u.abortedBy;break}}e.push(...C),j(k,i),E.push({event:p.event,matched:b,skipped:A,notMatched:S,errors:C,halted:w,haltedBy:T,counters:i});}let I={eventResults:E,unprocessedEvents:y,errors:e,counters:k,totalEvents:f.length,processedEvents:E.length};if(o)try{await l.onEventsComplete(I);}catch{}return I}}function V(t,n){return n?X(t):K(t)}function H(t,n,r){let{filledNames:o,asyncNames:a}=t,d=A=>o.has(A),f=A=>a.has(A)?"await ":"",g=d("beforeEvent"),s=d("afterEvent"),c=d("onEventsComplete"),l=f("beforeEvent"),E=f("afterEvent"),y=f("onEventsComplete"),e=[];e.push("const eventResults=[];"),e.push("const unprocessedEvents=[];"),e.push("const aggErrors=[];"),e.push("const aggCounters={rulesEvaluated:0,rulesMatched:0,rulesSkipped:0,directivesApplied:0,directivesSkipped:0,subRunsCreated:0,errors:0};"),e.push("ae.setContext(ctx);"),c&&e.push("const _hookOnComplete=hooks.onEventsComplete;"),e.push("for(let _ei=0;_ei<events.length;_ei++){"),e.push("const ev=events[_ei];"),e.push("const _evListeners=listenerIndex.get(ev.event);"),e.push("if(!_evListeners||_evListeners.length===0){unprocessedEvents.push(ev.event);continue;}"),e.push("const matched=[];const skipped=[];const notMatched=[];"),e.push("const errors=[];"),e.push("const counters={rulesEvaluated:0,rulesMatched:0,rulesSkipped:0,directivesApplied:0,directivesSkipped:0,subRunsCreated:0,errors:0};"),e.push("let halted=false;let haltedBy;"),(g||s)&&e.push("const evalCtx={ctx,counters,event:ev.event};"),g&&e.push("const _hookBefore=hooks.beforeEvent;"),s&&e.push("const _hookAfter=hooks.afterEvent;"),e.push("const _ep={$event:{type:ev.event,data:ev.data}};"),e.push("for(let _ri=0;_ri<_evListeners.length;_ri++){"),e.push("const stored=_evListeners[_ri];"),e.push("counters.rulesEvaluated++;"),g&&(e.push("try{"),e.push(`const _bd=${l}_hookBefore(stored.definition,evalCtx);`),e.push('if(_bd==="skip"){skipped.push(_ri);counters.rulesSkipped++;continue;}'),e.push('if(_bd==="abort"){break;}'),e.push('}catch(_e){errors.push({ruleIndex:_ri,error:"beforeEvent: "+_e});counters.errors++;}')),e.push("matched.push(_ri);counters.rulesMatched++;"),n&&(e.push("let params;"),e.push('try{params=$.runMw(mw,stored.definition,ctx,_ep);}catch(_e){errors.push({ruleIndex:_ri,error:"Middleware: "+_e});counters.errors++;continue;}'));let k=n?"params":"_ep",R=r?`await ae.invokeAsync(stored.actionId,${k})`:`ae.invoke(stored.actionId,${k})`;e.push(`const ir=${R};`),e.push("counters.directivesApplied+=ir.appliedCount;counters.directivesSkipped+=ir.skippedCount;counters.errors+=ir.errors.length;"),s&&(e.push("try{"),e.push(`const _ad=${E}_hookAfter(stored.definition,ir,evalCtx);`),e.push('if(_ad==="abort"){break;}'),e.push("}catch(_e){}")),e.push("if(ir.aborted){halted=true;haltedBy=ir.abortedBy;break;}"),e.push("}"),e.push("aggCounters.rulesEvaluated+=counters.rulesEvaluated;"),e.push("aggCounters.rulesMatched+=counters.rulesMatched;"),e.push("aggCounters.rulesSkipped+=counters.rulesSkipped;"),e.push("aggCounters.directivesApplied+=counters.directivesApplied;"),e.push("aggCounters.directivesSkipped+=counters.directivesSkipped;"),e.push("aggCounters.subRunsCreated+=counters.subRunsCreated;"),e.push("aggCounters.errors+=counters.errors;"),e.push("for(let _k=0;_k<errors.length;_k++)aggErrors.push(errors[_k]);"),e.push("eventResults.push({event:ev.event,matched,skipped,notMatched,errors,halted,haltedBy,counters});"),e.push("}"),e.push("const _r={eventResults,unprocessedEvents,errors:aggErrors,counters:aggCounters,totalEvents:events.length,processedEvents:eventResults.length};"),c&&e.push(`try{${y}_hookOnComplete(_r);}catch(_e){}`),e.push("return _r;");let I=e.join(`
|
|
2
|
+
`),p=r?"async ":"",_=new Function("listenerIndex","events","ctx","ae","mw","hooks","$",`"use strict";
|
|
3
3
|
return(${p}()=>{
|
|
4
|
-
${
|
|
5
|
-
})();`),
|
|
4
|
+
${I}
|
|
5
|
+
})();`),b={};return n&&(b.runMw=M),function(S,C,i,w,T,D){return _(S,C,i,w,T,D,b)}}function Q(t,n,r){let{filledNames:o,asyncNames:a}=t,d=b=>o.has(b),f=b=>a.has(b)?"await ":"",g=d("beforeEvent"),s=d("afterEvent"),c=d("onEventsComplete"),l=f("beforeEvent"),E=f("afterEvent"),y=f("onEventsComplete"),e=[];e.push("const eventResults=[];"),e.push("const unprocessedEvents=[];"),e.push("const aggErrors=[];"),e.push("const aggCounters={rulesEvaluated:0,rulesMatched:0,rulesSkipped:0,directivesApplied:0,directivesSkipped:0,subRunsCreated:0,errors:0};"),e.push("ae.setContext(ctx);"),c&&e.push("const _hookOnComplete=hooks.onEventsComplete;"),e.push("for(let _ei=0;_ei<events.length;_ei++){"),e.push("const ev=events[_ei];"),e.push("const _evListeners=listenerIndex.get(ev.event);"),e.push("if(!_evListeners||_evListeners.length===0){unprocessedEvents.push(ev.event);continue;}"),e.push("const matched=[];const skipped=[];const notMatched=[];"),e.push("const errors=[];"),e.push("const counters={rulesEvaluated:0,rulesMatched:0,rulesSkipped:0,directivesApplied:0,directivesSkipped:0,subRunsCreated:0,errors:0};"),e.push("let halted=false;let haltedBy;"),(g||s)&&e.push("const evalCtx={ctx,counters,event:ev.event};"),g&&e.push("const _hookBefore=hooks.beforeEvent;"),s&&e.push("const _hookAfter=hooks.afterEvent;"),e.push("const _ep={$event:{type:ev.event,data:ev.data}};"),e.push("for(let _ri=0;_ri<_evListeners.length;_ri++){"),e.push("const stored=_evListeners[_ri];"),e.push("counters.rulesEvaluated++;"),g&&(e.push("try{"),e.push(`const _bd=${l}_hookBefore(stored.definition,evalCtx);`),e.push('if(_bd==="skip"){skipped.push(_ri);counters.rulesSkipped++;continue;}'),e.push('if(_bd==="abort"){break;}'),e.push('}catch(_e){errors.push({ruleIndex:_ri,error:"beforeEvent: "+_e});counters.errors++;}')),e.push("matched.push(_ri);counters.rulesMatched++;"),n&&(e.push("let params;"),e.push('try{params=$.runMw(mw,stored.definition,ctx,_ep);}catch(_e){errors.push({ruleIndex:_ri,error:"Middleware: "+_e});counters.errors++;continue;}'));let k=n?"params":"_ep";e.push("let ir;"),e.push("if(stored.isInteractive){"),e.push(`ir=yield* ae.invokeInteractive(stored.actionId,${k});`),r&&(e.push("}else if(stored.isAsync){"),e.push(`ir=await ae.invokeAsync(stored.actionId,${k});`)),e.push("}else{"),e.push(`ir=ae.invoke(stored.actionId,${k});`),e.push("}"),e.push("counters.directivesApplied+=ir.appliedCount;counters.directivesSkipped+=ir.skippedCount;counters.errors+=ir.errors.length;"),s&&(e.push("try{"),e.push(`const _ad=${E}_hookAfter(stored.definition,ir,evalCtx);`),e.push('if(_ad==="abort"){break;}'),e.push("}catch(_e){}")),e.push("if(ir.aborted){halted=true;haltedBy=ir.abortedBy;break;}"),e.push("}"),e.push("aggCounters.rulesEvaluated+=counters.rulesEvaluated;"),e.push("aggCounters.rulesMatched+=counters.rulesMatched;"),e.push("aggCounters.rulesSkipped+=counters.rulesSkipped;"),e.push("aggCounters.directivesApplied+=counters.directivesApplied;"),e.push("aggCounters.directivesSkipped+=counters.directivesSkipped;"),e.push("aggCounters.subRunsCreated+=counters.subRunsCreated;"),e.push("aggCounters.errors+=counters.errors;"),e.push("for(let _k=0;_k<errors.length;_k++)aggErrors.push(errors[_k]);"),e.push("eventResults.push({event:ev.event,matched,skipped,notMatched,errors,halted,haltedBy,counters});"),e.push("}"),e.push("const _r={eventResults,unprocessedEvents,errors:aggErrors,counters:aggCounters,totalEvents:events.length,processedEvents:eventResults.length};"),c&&e.push(`try{${y}_hookOnComplete(_r);}catch(_e){}`),e.push("return _r;");let R=e.join(`
|
|
6
|
+
`),I=r?"async function* ":"function* ",p=new Function("listenerIndex","events","ctx","ae","mw","hooks","$",`"use strict";
|
|
7
|
+
return(${I}(){
|
|
8
|
+
${R}
|
|
9
|
+
})();`),_={};return n&&(_.runMw=M),function(A,S,C,i,w,T){return p(A,S,C,i,w,T,_)}}function W(t){return !t.event||typeof t.event!="string"?{event:t.event??"(missing)",code:"INVALID_DEFINITION",message:"event definition must have a non-empty string event name"}:t.tags!==void 0&&!Array.isArray(t.tags)?{event:t.event,code:"INVALID_DEFINITION",message:"event definition tags must be an array of strings"}:t.tier!==void 0&&typeof t.tier!="number"?{event:t.event,code:"INVALID_DEFINITION",message:"event definition tier must be a number"}:null}function G(t){if(!t.id||typeof t.id!="string")return {listenerId:t.id??"(missing)",code:"INVALID_LISTENER",message:"listener must have a string id"};if(typeof t.priority!="number")return {listenerId:t.id,code:"INVALID_LISTENER",message:"listener must have a numeric priority"};if(typeof t.on=="string"){if(!t.on)return {listenerId:t.id,code:"INVALID_LISTENER",message:"listener.on must be a non-empty string or string[]"}}else if(Array.isArray(t.on)){if(t.on.length===0||t.on.some(n=>typeof n!="string"||!n))return {listenerId:t.id,code:"INVALID_LISTENER",message:"listener.on must be a non-empty string or string[] of non-empty strings"}}else return {listenerId:t.id,code:"INVALID_LISTENER",message:"listener.on must be a string or string[]"};return !Array.isArray(t.then)||t.then.length===0?{listenerId:t.id,code:"INVALID_LISTENER",message:"listener must have a non-empty then array"}:null}function q(t,n){let r=0,o=t.length;for(;r<o;){let a=r+o>>>1;t[a].priority>=n.priority?r=a+1:o=a;}t.splice(r,0,n);}function U(t,n){let r=t.indexOf(n);return r===-1?false:(t.splice(r,1),true)}var F=()=>{},B=class{_actionEngine;_middleware;_eventHooks;_requestedMode;_hookAnalysis;_isAsync;_hasAnyInteractiveListener=false;_dispatcher;_mode;_maybeAutoPromote;_interactiveDispatcher=null;_interactiveDispatcherIsAsync=false;_eventDefinitions=new Map;_listenerRegistry=new Map;_listenerIndex=new Map;_batch=null;constructor(n){if(this._actionEngine=n.actionEngine,this._middleware=n.middleware??[],this._eventHooks=n.eventHooks??{},this._requestedMode=n.mode??"auto",this._hookAnalysis=core.analyzeSlots(this._eventHooks,core.EVENT_SLOT_NAMES),this._isAsync=this._hookAnalysis.hasAnyAsync,this._requestedMode==="jit")this._dispatcher=this._buildJit(),this._mode="jit",this._maybeAutoPromote=F;else if(this._dispatcher=$(this._hookAnalysis,this._isAsync),this._mode="interpret",this._requestedMode==="auto"){let r=0,o=n.autoJitThreshold??8;this._maybeAutoPromote=()=>{++r>=o&&this._promote();};}else this._maybeAutoPromote=F;}get actionEngine(){return this._actionEngine}get isAsync(){return this._isAsync}get isInteractive(){return this._hasAnyInteractiveListener}get compilationMode(){return this._mode}get eventDefinitions(){return this._eventDefinitions}getEventDefinition(n){return this._eventDefinitions.get(n)}defineEvents(n){let r=[],o=[],a=[];for(let s of n){let c=W(s);if(c){r.push(c);continue}if(this._eventDefinitions.has(s.event)||a.some(E=>E.name===s.event)){r.push({event:s.event,code:"DUPLICATE_EVENT",message:`event definition "${s.event}" is already registered`});continue}let l=["eventdef"];s.tags&&l.push(...s.tags),o.push({id:`eventdef:${s.event}`,directives:[],tags:l,declarations:s.declarations,tier:s.tier,metadata:{...s.schema!==void 0&&{schema:s.schema},...s.description!==void 0&&{description:s.description}}}),a.push({name:s.event,def:s});}let d=[];if(o.length>0){let s=this._actionEngine.register(o);for(let c of s.errors){let l=this._actionIdToEventName(c.actionId);r.push({event:l??c.actionId,code:c.code??"ACTION_ERROR",message:c.error});}d=s.warnings;}let f=[];for(let{name:s,def:c}of a)this._eventDefinitions.set(s,c),f.push(s);let g={defined:f,errors:r,warnings:d};return this._batch&&(this._batch.definedEvents.push(...f),this._batch.defineErrors.push(...r),this._batch.warnings.push(...d)),g}register(n){let r=[],o=[],a=[],d=[];for(let s of n){let c=G(s);if(c){r.push(c);continue}if(this._listenerRegistry.has(s.id)||d.some(R=>R.id===s.id)){r.push({listenerId:s.id,code:"DUPLICATE_ID",message:`listener "${s.id}" is already registered`});continue}let l=typeof s.on=="string"?[s.on]:s.on,E=false;for(let R of l){let I=this._eventDefinitions.get(R);if(!I){o.push({actionId:`event:${s.id}`,code:"NO_EVENT_DEFINITION",message:`listener "${s.id}" listens to "${R}" but no event definition is registered for it`});continue}I.tier!==void 0&&s.declarations?.tier!==void 0&&s.declarations.tier<I.tier&&(r.push({listenerId:s.id,code:"TIER_VIOLATION",message:`listener "${s.id}" declares tier ${s.declarations.tier} but event "${R}" requires tier >= ${I.tier}`}),E=true);}if(E)continue;let y=`event:${s.id}`,e={definition:s,actionId:y,priority:s.priority,isAsync:false,isInteractive:false},k=["event"];s.tags&&k.push(...s.tags),a.push({id:y,tags:k,directives:s.then,declarations:s.declarations}),d.push({id:s.id,stored:e,eventNames:l});}if(a.length>0){let s=this._actionEngine.register(a);for(let c of s.errors){let l=this._actionIdToListenerId(c.actionId);r.push({listenerId:l??c.actionId,code:c.code??"ACTION_ERROR",message:c.error});}o.push(...s.warnings);}let f=[];for(let{id:s,stored:c,eventNames:l}of d){this._listenerRegistry.set(s,c);for(let E of l){let y=this._listenerIndex.get(E);y||(y=[],this._listenerIndex.set(E,y)),q(y,c);}f.push(s);}let g={registered:f,errors:r,warnings:o};return this._batch?(this._batch.registered.push(...f),this._batch.errors.push(...r),this._batch.warnings.push(...o)):f.length>0&&this._refreshListenerFlags(),g}unregister(n){let r=this._listenerRegistry.get(n);if(!r)return false;this._listenerRegistry.delete(n);let o=typeof r.definition.on=="string"?[r.definition.on]:r.definition.on;for(let a of o){let d=this._listenerIndex.get(a);d&&(U(d,r),d.length===0&&this._listenerIndex.delete(a));}return this._actionEngine.unregister(r.actionId),this._refreshListenerFlags(),true}processEvents(n,r){if(this._hasAnyInteractiveListener)throw new Error("Cannot call processEvents() \u2014 at least one listener is interactive (transitively). Use processEventsInteractive() instead.");if(this._isAsync)throw new Error("Cannot call processEvents() with async hooks or async listeners. Use processEventsAsync() instead.");let o=this._dispatcher(this._listenerIndex,n,r,this._actionEngine,this._middleware,this._eventHooks);return this._maybeAutoPromote(),o}async processEventsAsync(n,r){if(this._hasAnyInteractiveListener)throw new Error("Cannot call processEventsAsync() \u2014 at least one listener is interactive (transitively). Use processEventsInteractive() instead.");let o=await this._dispatcher(this._listenerIndex,n,r,this._actionEngine,this._middleware,this._eventHooks);return this._maybeAutoPromote(),o}processEventsInteractive(n,r){if(!this._hasAnyInteractiveListener)throw new Error("Cannot call processEventsInteractive() \u2014 no registered listener is interactive (transitively). Use processEvents() or processEventsAsync() instead.");return (this._interactiveDispatcher===null||this._interactiveDispatcherIsAsync!==this._isAsync)&&(this._interactiveDispatcher=this._mode==="jit"?Q(this._hookAnalysis,this._middleware.length>0,this._isAsync):V(this._hookAnalysis,this._isAsync),this._interactiveDispatcherIsAsync=this._isAsync),this._interactiveDispatcher(this._listenerIndex,n,r,this._actionEngine,this._middleware,this._eventHooks)}beginBatch(){this._batch||(this._batch={depth:0,registered:[],errors:[],warnings:[],definedEvents:[],defineErrors:[]}),this._batch.depth++,this._actionEngine.beginBatch();}endBatch(){if(!this._batch||this._batch.depth<=0)throw new Error("endBatch() called without matching beginBatch()");this._batch.depth--;let n=this._actionEngine.endBatch();if(this._batch.depth>0)return {registered:[],errors:[],warnings:[]};let r=this._batch;for(let a of n.errors){let d=this._actionIdToListenerId(a.actionId);r.errors.push({listenerId:d??a.actionId,code:a.code??"ACTION_ERROR",message:a.error});}r.warnings.push(...n.warnings);let o={registered:r.registered,errors:r.errors,warnings:r.warnings};return this._batch=null,this._refreshListenerFlags(),o}compile(){this._requestedMode!=="interpret"&&this._mode!=="jit"&&this._promote();}_promote(){this._dispatcher=this._buildJit(),this._mode="jit",this._maybeAutoPromote=F,this._interactiveDispatcher=null;}_buildJit(){return H(this._hookAnalysis,this._middleware.length>0,this._isAsync)}_refreshListenerFlags(){let n=false,r=false;for(let a of this._listenerRegistry.values())a.isAsync=this._actionEngine.isActionAsync(a.actionId)??false,a.isInteractive=this._actionEngine.isActionInteractive?.(a.actionId)??false,a.isAsync&&(n=true),a.isInteractive&&(r=true);this._hasAnyInteractiveListener=r;let o=this._hookAnalysis.hasAnyAsync||n;o!==this._isAsync&&(this._isAsync=o,this._rebuildDispatcher());}_rebuildDispatcher(){this._dispatcher=this._mode==="jit"?this._buildJit():$(this._hookAnalysis,this._isAsync);}_actionIdToListenerId(n){return n.startsWith("event:")?n.slice(6):null}_actionIdToEventName(n){return n.startsWith("eventdef:")?n.slice(9):null}};function ee(t){return new B(t)}function he(t="event"){return n=>{let r=n[t],o=typeof r=="string"&&r?[`eventdef:${r}`]:[];return {capabilities:["emit"],dependencies:o}}}exports.createEmitAnalyzer=he;exports.createEventProcessor=ee;
|
package/dist/index.d.cts
CHANGED
|
@@ -92,6 +92,24 @@ interface EventProcessorConfig<TCtx = unknown> {
|
|
|
92
92
|
mode?: "interpret" | "jit" | "auto";
|
|
93
93
|
autoJitThreshold?: number;
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Sessão de processamento de events em modo interactive — retornada por
|
|
97
|
+
* `processEventsInteractive(events, ctx)`. Drena via `next()`. O `done.value`
|
|
98
|
+
* final é `EventProcessingResult`. Halt scoping: pause em listener para os
|
|
99
|
+
* listeners daquele evento; próximos eventos na fila continuam normalmente.
|
|
100
|
+
*/
|
|
101
|
+
interface InteractiveEventSession extends Iterator<unknown, EventProcessingResult, unknown> {
|
|
102
|
+
next(value?: unknown): IteratorResult<unknown, EventProcessingResult>;
|
|
103
|
+
return(): IteratorResult<unknown, EventProcessingResult>;
|
|
104
|
+
throw(err?: unknown): IteratorResult<unknown, EventProcessingResult>;
|
|
105
|
+
[Symbol.iterator](): InteractiveEventSession;
|
|
106
|
+
}
|
|
107
|
+
interface AsyncInteractiveEventSession extends AsyncIterator<unknown, EventProcessingResult, unknown> {
|
|
108
|
+
next(value?: unknown): Promise<IteratorResult<unknown, EventProcessingResult>>;
|
|
109
|
+
return(): Promise<IteratorResult<unknown, EventProcessingResult>>;
|
|
110
|
+
throw(err?: unknown): Promise<IteratorResult<unknown, EventProcessingResult>>;
|
|
111
|
+
[Symbol.asyncIterator](): AsyncInteractiveEventSession;
|
|
112
|
+
}
|
|
95
113
|
interface IEventProcessor<TCtx = unknown> {
|
|
96
114
|
defineEvents(definitions: readonly EventDefinition[]): EventDefineResult;
|
|
97
115
|
getEventDefinition(event: string): EventDefinition | undefined;
|
|
@@ -100,11 +118,22 @@ interface IEventProcessor<TCtx = unknown> {
|
|
|
100
118
|
unregister(id: string): boolean;
|
|
101
119
|
processEvents(events: readonly QueuedEvent[], ctx: TCtx): EventProcessingResult;
|
|
102
120
|
processEventsAsync(events: readonly QueuedEvent[], ctx: TCtx): Promise<EventProcessingResult>;
|
|
121
|
+
/**
|
|
122
|
+
* Processa events em modo interactive — retorna iterator drenável.
|
|
123
|
+
* Lança se nenhum listener registrado é interactive transitivamente, ou se
|
|
124
|
+
* actionEngine não tem `interactive` configurado.
|
|
125
|
+
*
|
|
126
|
+
* Variante async (AsyncInteractiveEventSession) é retornada quando algum
|
|
127
|
+
* listener é async transitivamente OU algum hook é async.
|
|
128
|
+
*/
|
|
129
|
+
processEventsInteractive(events: readonly QueuedEvent[], ctx: TCtx): InteractiveEventSession | AsyncInteractiveEventSession;
|
|
103
130
|
beginBatch(): void;
|
|
104
131
|
endBatch(): EventRegisterResult;
|
|
105
132
|
compile(): void;
|
|
106
133
|
readonly actionEngine: IActionEngine<TCtx>;
|
|
107
134
|
readonly isAsync: boolean;
|
|
135
|
+
/** Algum listener registrado é interactive transitivamente? Cached. */
|
|
136
|
+
readonly isInteractive: boolean;
|
|
108
137
|
readonly compilationMode: "interpret" | "jit";
|
|
109
138
|
}
|
|
110
139
|
|
package/dist/index.d.ts
CHANGED
|
@@ -92,6 +92,24 @@ interface EventProcessorConfig<TCtx = unknown> {
|
|
|
92
92
|
mode?: "interpret" | "jit" | "auto";
|
|
93
93
|
autoJitThreshold?: number;
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Sessão de processamento de events em modo interactive — retornada por
|
|
97
|
+
* `processEventsInteractive(events, ctx)`. Drena via `next()`. O `done.value`
|
|
98
|
+
* final é `EventProcessingResult`. Halt scoping: pause em listener para os
|
|
99
|
+
* listeners daquele evento; próximos eventos na fila continuam normalmente.
|
|
100
|
+
*/
|
|
101
|
+
interface InteractiveEventSession extends Iterator<unknown, EventProcessingResult, unknown> {
|
|
102
|
+
next(value?: unknown): IteratorResult<unknown, EventProcessingResult>;
|
|
103
|
+
return(): IteratorResult<unknown, EventProcessingResult>;
|
|
104
|
+
throw(err?: unknown): IteratorResult<unknown, EventProcessingResult>;
|
|
105
|
+
[Symbol.iterator](): InteractiveEventSession;
|
|
106
|
+
}
|
|
107
|
+
interface AsyncInteractiveEventSession extends AsyncIterator<unknown, EventProcessingResult, unknown> {
|
|
108
|
+
next(value?: unknown): Promise<IteratorResult<unknown, EventProcessingResult>>;
|
|
109
|
+
return(): Promise<IteratorResult<unknown, EventProcessingResult>>;
|
|
110
|
+
throw(err?: unknown): Promise<IteratorResult<unknown, EventProcessingResult>>;
|
|
111
|
+
[Symbol.asyncIterator](): AsyncInteractiveEventSession;
|
|
112
|
+
}
|
|
95
113
|
interface IEventProcessor<TCtx = unknown> {
|
|
96
114
|
defineEvents(definitions: readonly EventDefinition[]): EventDefineResult;
|
|
97
115
|
getEventDefinition(event: string): EventDefinition | undefined;
|
|
@@ -100,11 +118,22 @@ interface IEventProcessor<TCtx = unknown> {
|
|
|
100
118
|
unregister(id: string): boolean;
|
|
101
119
|
processEvents(events: readonly QueuedEvent[], ctx: TCtx): EventProcessingResult;
|
|
102
120
|
processEventsAsync(events: readonly QueuedEvent[], ctx: TCtx): Promise<EventProcessingResult>;
|
|
121
|
+
/**
|
|
122
|
+
* Processa events em modo interactive — retorna iterator drenável.
|
|
123
|
+
* Lança se nenhum listener registrado é interactive transitivamente, ou se
|
|
124
|
+
* actionEngine não tem `interactive` configurado.
|
|
125
|
+
*
|
|
126
|
+
* Variante async (AsyncInteractiveEventSession) é retornada quando algum
|
|
127
|
+
* listener é async transitivamente OU algum hook é async.
|
|
128
|
+
*/
|
|
129
|
+
processEventsInteractive(events: readonly QueuedEvent[], ctx: TCtx): InteractiveEventSession | AsyncInteractiveEventSession;
|
|
103
130
|
beginBatch(): void;
|
|
104
131
|
endBatch(): EventRegisterResult;
|
|
105
132
|
compile(): void;
|
|
106
133
|
readonly actionEngine: IActionEngine<TCtx>;
|
|
107
134
|
readonly isAsync: boolean;
|
|
135
|
+
/** Algum listener registrado é interactive transitivamente? Cached. */
|
|
136
|
+
readonly isInteractive: boolean;
|
|
108
137
|
readonly compilationMode: "interpret" | "jit";
|
|
109
138
|
}
|
|
110
139
|
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import {analyzeSlots,EVENT_SLOT_NAMES}from'@statedelta-actions/core';function
|
|
2
|
-
`),p=r?"async ":"",
|
|
1
|
+
import {analyzeSlots,EVENT_SLOT_NAMES}from'@statedelta-actions/core';function N(){return {rulesEvaluated:0,rulesMatched:0,rulesSkipped:0,directivesApplied:0,directivesSkipped:0,subRunsCreated:0,errors:0}}function O(t,n){t.rulesEvaluated+=n.rulesEvaluated,t.rulesMatched+=n.rulesMatched,t.rulesSkipped+=n.rulesSkipped,t.directivesApplied+=n.directivesApplied,t.directivesSkipped+=n.directivesSkipped,t.subRunsCreated+=n.subRunsCreated,t.errors+=n.errors;}function M(t,n,r,o){let a=o?Object.assign({},o):{};for(let d of t)Object.assign(a,d(n,r,a));return a}function J(t){let n=t.filledNames.has("beforeEvent"),r=t.filledNames.has("afterEvent"),o=t.filledNames.has("onEventsComplete");return function(d,f,g,s,c,l){let E=[],y=[],e=[],k=N(),R=c.length>0;s.setContext(g);for(let p of f){let _=d.get(p.event);if(!_||_.length===0){y.push(p.event);continue}let b=[],A=[],S=[],C=[],i=N(),w=false,T,D={ctx:g,counters:i,event:p.event},L={$event:{type:p.event,data:p.data}};for(let h=0;h<_.length;h++){let m=_[h];if(i.rulesEvaluated++,n)try{let v=l.beforeEvent(m.definition,D);if(v==="skip"){A.push(h),i.rulesSkipped++;continue}if(v==="abort")break}catch(v){C.push({ruleIndex:h,error:`beforeEvent: ${v}`}),i.errors++;}b.push(h),i.rulesMatched++;let x;if(R)try{x=M(c,m.definition,g,L);}catch(v){C.push({ruleIndex:h,error:`Middleware: ${v}`}),i.errors++;continue}else x=L;let u=s.invoke(m.actionId,x);if(i.directivesApplied+=u.appliedCount,i.directivesSkipped+=u.skippedCount,i.errors+=u.errors.length,r)try{if(l.afterEvent(m.definition,u,D)==="abort")break}catch{}if(u.aborted){w=true,T=u.abortedBy;break}}e.push(...C),O(k,i),E.push({event:p.event,matched:b,skipped:A,notMatched:S,errors:C,halted:w,haltedBy:T,counters:i});}let I={eventResults:E,unprocessedEvents:y,errors:e,counters:k,totalEvents:f.length,processedEvents:E.length};if(o)try{l.onEventsComplete(I);}catch{}return I}}function z(t){let n=t.filledNames.has("beforeEvent"),r=t.filledNames.has("afterEvent"),o=t.filledNames.has("onEventsComplete");return async function(d,f,g,s,c,l){let E=[],y=[],e=[],k=N(),R=c.length>0;s.setContext(g);for(let p of f){let _=d.get(p.event);if(!_||_.length===0){y.push(p.event);continue}let b=[],A=[],S=[],C=[],i=N(),w=false,T,D={ctx:g,counters:i,event:p.event},L={$event:{type:p.event,data:p.data}};for(let h=0;h<_.length;h++){let m=_[h];if(i.rulesEvaluated++,n)try{let v=await l.beforeEvent(m.definition,D);if(v==="skip"){A.push(h),i.rulesSkipped++;continue}if(v==="abort")break}catch(v){C.push({ruleIndex:h,error:`beforeEvent: ${v}`}),i.errors++;}b.push(h),i.rulesMatched++;let x;if(R)try{x=M(c,m.definition,g,L);}catch(v){C.push({ruleIndex:h,error:`Middleware: ${v}`}),i.errors++;continue}else x=L;let u=await s.invokeAsync(m.actionId,x);if(i.directivesApplied+=u.appliedCount,i.directivesSkipped+=u.skippedCount,i.errors+=u.errors.length,r)try{if(await l.afterEvent(m.definition,u,D)==="abort")break}catch{}if(u.aborted){w=true,T=u.abortedBy;break}}e.push(...C),O(k,i),E.push({event:p.event,matched:b,skipped:A,notMatched:S,errors:C,halted:w,haltedBy:T,counters:i});}let I={eventResults:E,unprocessedEvents:y,errors:e,counters:k,totalEvents:f.length,processedEvents:E.length};if(o)try{await l.onEventsComplete(I);}catch{}return I}}function $(t,n){return n?z(t):J(t)}function P(){return {rulesEvaluated:0,rulesMatched:0,rulesSkipped:0,directivesApplied:0,directivesSkipped:0,subRunsCreated:0,errors:0}}function j(t,n){t.rulesEvaluated+=n.rulesEvaluated,t.rulesMatched+=n.rulesMatched,t.rulesSkipped+=n.rulesSkipped,t.directivesApplied+=n.directivesApplied,t.directivesSkipped+=n.directivesSkipped,t.subRunsCreated+=n.subRunsCreated,t.errors+=n.errors;}function K(t){let n=t.filledNames.has("beforeEvent"),r=t.filledNames.has("afterEvent"),o=t.filledNames.has("onEventsComplete");return function*(d,f,g,s,c,l){let E=[],y=[],e=[],k=P(),R=c.length>0;s.setContext(g);for(let p of f){let _=d.get(p.event);if(!_||_.length===0){y.push(p.event);continue}let b=[],A=[],S=[],C=[],i=P(),w=false,T,D={ctx:g,counters:i,event:p.event},L={$event:{type:p.event,data:p.data}};for(let h=0;h<_.length;h++){let m=_[h];if(i.rulesEvaluated++,n)try{let v=l.beforeEvent(m.definition,D);if(v==="skip"){A.push(h),i.rulesSkipped++;continue}if(v==="abort")break}catch(v){C.push({ruleIndex:h,error:`beforeEvent: ${v}`}),i.errors++;}b.push(h),i.rulesMatched++;let x;if(R)try{x=M(c,m.definition,g,L);}catch(v){C.push({ruleIndex:h,error:`Middleware: ${v}`}),i.errors++;continue}else x=L;let u;if(m.isInteractive?u=yield*s.invokeInteractive(m.actionId,x):u=s.invoke(m.actionId,x),i.directivesApplied+=u.appliedCount,i.directivesSkipped+=u.skippedCount,i.errors+=u.errors.length,r)try{if(l.afterEvent(m.definition,u,D)==="abort")break}catch{}if(u.aborted){w=true,T=u.abortedBy;break}}e.push(...C),j(k,i),E.push({event:p.event,matched:b,skipped:A,notMatched:S,errors:C,halted:w,haltedBy:T,counters:i});}let I={eventResults:E,unprocessedEvents:y,errors:e,counters:k,totalEvents:f.length,processedEvents:E.length};if(o)try{l.onEventsComplete(I);}catch{}return I}}function X(t){let n=t.filledNames.has("beforeEvent"),r=t.filledNames.has("afterEvent"),o=t.filledNames.has("onEventsComplete");return async function*(d,f,g,s,c,l){let E=[],y=[],e=[],k=P(),R=c.length>0;s.setContext(g);for(let p of f){let _=d.get(p.event);if(!_||_.length===0){y.push(p.event);continue}let b=[],A=[],S=[],C=[],i=P(),w=false,T,D={ctx:g,counters:i,event:p.event},L={$event:{type:p.event,data:p.data}};for(let h=0;h<_.length;h++){let m=_[h];if(i.rulesEvaluated++,n)try{let v=await l.beforeEvent(m.definition,D);if(v==="skip"){A.push(h),i.rulesSkipped++;continue}if(v==="abort")break}catch(v){C.push({ruleIndex:h,error:`beforeEvent: ${v}`}),i.errors++;}b.push(h),i.rulesMatched++;let x;if(R)try{x=M(c,m.definition,g,L);}catch(v){C.push({ruleIndex:h,error:`Middleware: ${v}`}),i.errors++;continue}else x=L;let u;if(m.isInteractive?u=yield*s.invokeInteractive(m.actionId,x):m.isAsync?u=await s.invokeAsync(m.actionId,x):u=s.invoke(m.actionId,x),i.directivesApplied+=u.appliedCount,i.directivesSkipped+=u.skippedCount,i.errors+=u.errors.length,r)try{if(await l.afterEvent(m.definition,u,D)==="abort")break}catch{}if(u.aborted){w=true,T=u.abortedBy;break}}e.push(...C),j(k,i),E.push({event:p.event,matched:b,skipped:A,notMatched:S,errors:C,halted:w,haltedBy:T,counters:i});}let I={eventResults:E,unprocessedEvents:y,errors:e,counters:k,totalEvents:f.length,processedEvents:E.length};if(o)try{await l.onEventsComplete(I);}catch{}return I}}function V(t,n){return n?X(t):K(t)}function H(t,n,r){let{filledNames:o,asyncNames:a}=t,d=A=>o.has(A),f=A=>a.has(A)?"await ":"",g=d("beforeEvent"),s=d("afterEvent"),c=d("onEventsComplete"),l=f("beforeEvent"),E=f("afterEvent"),y=f("onEventsComplete"),e=[];e.push("const eventResults=[];"),e.push("const unprocessedEvents=[];"),e.push("const aggErrors=[];"),e.push("const aggCounters={rulesEvaluated:0,rulesMatched:0,rulesSkipped:0,directivesApplied:0,directivesSkipped:0,subRunsCreated:0,errors:0};"),e.push("ae.setContext(ctx);"),c&&e.push("const _hookOnComplete=hooks.onEventsComplete;"),e.push("for(let _ei=0;_ei<events.length;_ei++){"),e.push("const ev=events[_ei];"),e.push("const _evListeners=listenerIndex.get(ev.event);"),e.push("if(!_evListeners||_evListeners.length===0){unprocessedEvents.push(ev.event);continue;}"),e.push("const matched=[];const skipped=[];const notMatched=[];"),e.push("const errors=[];"),e.push("const counters={rulesEvaluated:0,rulesMatched:0,rulesSkipped:0,directivesApplied:0,directivesSkipped:0,subRunsCreated:0,errors:0};"),e.push("let halted=false;let haltedBy;"),(g||s)&&e.push("const evalCtx={ctx,counters,event:ev.event};"),g&&e.push("const _hookBefore=hooks.beforeEvent;"),s&&e.push("const _hookAfter=hooks.afterEvent;"),e.push("const _ep={$event:{type:ev.event,data:ev.data}};"),e.push("for(let _ri=0;_ri<_evListeners.length;_ri++){"),e.push("const stored=_evListeners[_ri];"),e.push("counters.rulesEvaluated++;"),g&&(e.push("try{"),e.push(`const _bd=${l}_hookBefore(stored.definition,evalCtx);`),e.push('if(_bd==="skip"){skipped.push(_ri);counters.rulesSkipped++;continue;}'),e.push('if(_bd==="abort"){break;}'),e.push('}catch(_e){errors.push({ruleIndex:_ri,error:"beforeEvent: "+_e});counters.errors++;}')),e.push("matched.push(_ri);counters.rulesMatched++;"),n&&(e.push("let params;"),e.push('try{params=$.runMw(mw,stored.definition,ctx,_ep);}catch(_e){errors.push({ruleIndex:_ri,error:"Middleware: "+_e});counters.errors++;continue;}'));let k=n?"params":"_ep",R=r?`await ae.invokeAsync(stored.actionId,${k})`:`ae.invoke(stored.actionId,${k})`;e.push(`const ir=${R};`),e.push("counters.directivesApplied+=ir.appliedCount;counters.directivesSkipped+=ir.skippedCount;counters.errors+=ir.errors.length;"),s&&(e.push("try{"),e.push(`const _ad=${E}_hookAfter(stored.definition,ir,evalCtx);`),e.push('if(_ad==="abort"){break;}'),e.push("}catch(_e){}")),e.push("if(ir.aborted){halted=true;haltedBy=ir.abortedBy;break;}"),e.push("}"),e.push("aggCounters.rulesEvaluated+=counters.rulesEvaluated;"),e.push("aggCounters.rulesMatched+=counters.rulesMatched;"),e.push("aggCounters.rulesSkipped+=counters.rulesSkipped;"),e.push("aggCounters.directivesApplied+=counters.directivesApplied;"),e.push("aggCounters.directivesSkipped+=counters.directivesSkipped;"),e.push("aggCounters.subRunsCreated+=counters.subRunsCreated;"),e.push("aggCounters.errors+=counters.errors;"),e.push("for(let _k=0;_k<errors.length;_k++)aggErrors.push(errors[_k]);"),e.push("eventResults.push({event:ev.event,matched,skipped,notMatched,errors,halted,haltedBy,counters});"),e.push("}"),e.push("const _r={eventResults,unprocessedEvents,errors:aggErrors,counters:aggCounters,totalEvents:events.length,processedEvents:eventResults.length};"),c&&e.push(`try{${y}_hookOnComplete(_r);}catch(_e){}`),e.push("return _r;");let I=e.join(`
|
|
2
|
+
`),p=r?"async ":"",_=new Function("listenerIndex","events","ctx","ae","mw","hooks","$",`"use strict";
|
|
3
3
|
return(${p}()=>{
|
|
4
|
-
${
|
|
5
|
-
})();`),
|
|
4
|
+
${I}
|
|
5
|
+
})();`),b={};return n&&(b.runMw=M),function(S,C,i,w,T,D){return _(S,C,i,w,T,D,b)}}function Q(t,n,r){let{filledNames:o,asyncNames:a}=t,d=b=>o.has(b),f=b=>a.has(b)?"await ":"",g=d("beforeEvent"),s=d("afterEvent"),c=d("onEventsComplete"),l=f("beforeEvent"),E=f("afterEvent"),y=f("onEventsComplete"),e=[];e.push("const eventResults=[];"),e.push("const unprocessedEvents=[];"),e.push("const aggErrors=[];"),e.push("const aggCounters={rulesEvaluated:0,rulesMatched:0,rulesSkipped:0,directivesApplied:0,directivesSkipped:0,subRunsCreated:0,errors:0};"),e.push("ae.setContext(ctx);"),c&&e.push("const _hookOnComplete=hooks.onEventsComplete;"),e.push("for(let _ei=0;_ei<events.length;_ei++){"),e.push("const ev=events[_ei];"),e.push("const _evListeners=listenerIndex.get(ev.event);"),e.push("if(!_evListeners||_evListeners.length===0){unprocessedEvents.push(ev.event);continue;}"),e.push("const matched=[];const skipped=[];const notMatched=[];"),e.push("const errors=[];"),e.push("const counters={rulesEvaluated:0,rulesMatched:0,rulesSkipped:0,directivesApplied:0,directivesSkipped:0,subRunsCreated:0,errors:0};"),e.push("let halted=false;let haltedBy;"),(g||s)&&e.push("const evalCtx={ctx,counters,event:ev.event};"),g&&e.push("const _hookBefore=hooks.beforeEvent;"),s&&e.push("const _hookAfter=hooks.afterEvent;"),e.push("const _ep={$event:{type:ev.event,data:ev.data}};"),e.push("for(let _ri=0;_ri<_evListeners.length;_ri++){"),e.push("const stored=_evListeners[_ri];"),e.push("counters.rulesEvaluated++;"),g&&(e.push("try{"),e.push(`const _bd=${l}_hookBefore(stored.definition,evalCtx);`),e.push('if(_bd==="skip"){skipped.push(_ri);counters.rulesSkipped++;continue;}'),e.push('if(_bd==="abort"){break;}'),e.push('}catch(_e){errors.push({ruleIndex:_ri,error:"beforeEvent: "+_e});counters.errors++;}')),e.push("matched.push(_ri);counters.rulesMatched++;"),n&&(e.push("let params;"),e.push('try{params=$.runMw(mw,stored.definition,ctx,_ep);}catch(_e){errors.push({ruleIndex:_ri,error:"Middleware: "+_e});counters.errors++;continue;}'));let k=n?"params":"_ep";e.push("let ir;"),e.push("if(stored.isInteractive){"),e.push(`ir=yield* ae.invokeInteractive(stored.actionId,${k});`),r&&(e.push("}else if(stored.isAsync){"),e.push(`ir=await ae.invokeAsync(stored.actionId,${k});`)),e.push("}else{"),e.push(`ir=ae.invoke(stored.actionId,${k});`),e.push("}"),e.push("counters.directivesApplied+=ir.appliedCount;counters.directivesSkipped+=ir.skippedCount;counters.errors+=ir.errors.length;"),s&&(e.push("try{"),e.push(`const _ad=${E}_hookAfter(stored.definition,ir,evalCtx);`),e.push('if(_ad==="abort"){break;}'),e.push("}catch(_e){}")),e.push("if(ir.aborted){halted=true;haltedBy=ir.abortedBy;break;}"),e.push("}"),e.push("aggCounters.rulesEvaluated+=counters.rulesEvaluated;"),e.push("aggCounters.rulesMatched+=counters.rulesMatched;"),e.push("aggCounters.rulesSkipped+=counters.rulesSkipped;"),e.push("aggCounters.directivesApplied+=counters.directivesApplied;"),e.push("aggCounters.directivesSkipped+=counters.directivesSkipped;"),e.push("aggCounters.subRunsCreated+=counters.subRunsCreated;"),e.push("aggCounters.errors+=counters.errors;"),e.push("for(let _k=0;_k<errors.length;_k++)aggErrors.push(errors[_k]);"),e.push("eventResults.push({event:ev.event,matched,skipped,notMatched,errors,halted,haltedBy,counters});"),e.push("}"),e.push("const _r={eventResults,unprocessedEvents,errors:aggErrors,counters:aggCounters,totalEvents:events.length,processedEvents:eventResults.length};"),c&&e.push(`try{${y}_hookOnComplete(_r);}catch(_e){}`),e.push("return _r;");let R=e.join(`
|
|
6
|
+
`),I=r?"async function* ":"function* ",p=new Function("listenerIndex","events","ctx","ae","mw","hooks","$",`"use strict";
|
|
7
|
+
return(${I}(){
|
|
8
|
+
${R}
|
|
9
|
+
})();`),_={};return n&&(_.runMw=M),function(A,S,C,i,w,T){return p(A,S,C,i,w,T,_)}}function W(t){return !t.event||typeof t.event!="string"?{event:t.event??"(missing)",code:"INVALID_DEFINITION",message:"event definition must have a non-empty string event name"}:t.tags!==void 0&&!Array.isArray(t.tags)?{event:t.event,code:"INVALID_DEFINITION",message:"event definition tags must be an array of strings"}:t.tier!==void 0&&typeof t.tier!="number"?{event:t.event,code:"INVALID_DEFINITION",message:"event definition tier must be a number"}:null}function G(t){if(!t.id||typeof t.id!="string")return {listenerId:t.id??"(missing)",code:"INVALID_LISTENER",message:"listener must have a string id"};if(typeof t.priority!="number")return {listenerId:t.id,code:"INVALID_LISTENER",message:"listener must have a numeric priority"};if(typeof t.on=="string"){if(!t.on)return {listenerId:t.id,code:"INVALID_LISTENER",message:"listener.on must be a non-empty string or string[]"}}else if(Array.isArray(t.on)){if(t.on.length===0||t.on.some(n=>typeof n!="string"||!n))return {listenerId:t.id,code:"INVALID_LISTENER",message:"listener.on must be a non-empty string or string[] of non-empty strings"}}else return {listenerId:t.id,code:"INVALID_LISTENER",message:"listener.on must be a string or string[]"};return !Array.isArray(t.then)||t.then.length===0?{listenerId:t.id,code:"INVALID_LISTENER",message:"listener must have a non-empty then array"}:null}function q(t,n){let r=0,o=t.length;for(;r<o;){let a=r+o>>>1;t[a].priority>=n.priority?r=a+1:o=a;}t.splice(r,0,n);}function U(t,n){let r=t.indexOf(n);return r===-1?false:(t.splice(r,1),true)}var F=()=>{},B=class{_actionEngine;_middleware;_eventHooks;_requestedMode;_hookAnalysis;_isAsync;_hasAnyInteractiveListener=false;_dispatcher;_mode;_maybeAutoPromote;_interactiveDispatcher=null;_interactiveDispatcherIsAsync=false;_eventDefinitions=new Map;_listenerRegistry=new Map;_listenerIndex=new Map;_batch=null;constructor(n){if(this._actionEngine=n.actionEngine,this._middleware=n.middleware??[],this._eventHooks=n.eventHooks??{},this._requestedMode=n.mode??"auto",this._hookAnalysis=analyzeSlots(this._eventHooks,EVENT_SLOT_NAMES),this._isAsync=this._hookAnalysis.hasAnyAsync,this._requestedMode==="jit")this._dispatcher=this._buildJit(),this._mode="jit",this._maybeAutoPromote=F;else if(this._dispatcher=$(this._hookAnalysis,this._isAsync),this._mode="interpret",this._requestedMode==="auto"){let r=0,o=n.autoJitThreshold??8;this._maybeAutoPromote=()=>{++r>=o&&this._promote();};}else this._maybeAutoPromote=F;}get actionEngine(){return this._actionEngine}get isAsync(){return this._isAsync}get isInteractive(){return this._hasAnyInteractiveListener}get compilationMode(){return this._mode}get eventDefinitions(){return this._eventDefinitions}getEventDefinition(n){return this._eventDefinitions.get(n)}defineEvents(n){let r=[],o=[],a=[];for(let s of n){let c=W(s);if(c){r.push(c);continue}if(this._eventDefinitions.has(s.event)||a.some(E=>E.name===s.event)){r.push({event:s.event,code:"DUPLICATE_EVENT",message:`event definition "${s.event}" is already registered`});continue}let l=["eventdef"];s.tags&&l.push(...s.tags),o.push({id:`eventdef:${s.event}`,directives:[],tags:l,declarations:s.declarations,tier:s.tier,metadata:{...s.schema!==void 0&&{schema:s.schema},...s.description!==void 0&&{description:s.description}}}),a.push({name:s.event,def:s});}let d=[];if(o.length>0){let s=this._actionEngine.register(o);for(let c of s.errors){let l=this._actionIdToEventName(c.actionId);r.push({event:l??c.actionId,code:c.code??"ACTION_ERROR",message:c.error});}d=s.warnings;}let f=[];for(let{name:s,def:c}of a)this._eventDefinitions.set(s,c),f.push(s);let g={defined:f,errors:r,warnings:d};return this._batch&&(this._batch.definedEvents.push(...f),this._batch.defineErrors.push(...r),this._batch.warnings.push(...d)),g}register(n){let r=[],o=[],a=[],d=[];for(let s of n){let c=G(s);if(c){r.push(c);continue}if(this._listenerRegistry.has(s.id)||d.some(R=>R.id===s.id)){r.push({listenerId:s.id,code:"DUPLICATE_ID",message:`listener "${s.id}" is already registered`});continue}let l=typeof s.on=="string"?[s.on]:s.on,E=false;for(let R of l){let I=this._eventDefinitions.get(R);if(!I){o.push({actionId:`event:${s.id}`,code:"NO_EVENT_DEFINITION",message:`listener "${s.id}" listens to "${R}" but no event definition is registered for it`});continue}I.tier!==void 0&&s.declarations?.tier!==void 0&&s.declarations.tier<I.tier&&(r.push({listenerId:s.id,code:"TIER_VIOLATION",message:`listener "${s.id}" declares tier ${s.declarations.tier} but event "${R}" requires tier >= ${I.tier}`}),E=true);}if(E)continue;let y=`event:${s.id}`,e={definition:s,actionId:y,priority:s.priority,isAsync:false,isInteractive:false},k=["event"];s.tags&&k.push(...s.tags),a.push({id:y,tags:k,directives:s.then,declarations:s.declarations}),d.push({id:s.id,stored:e,eventNames:l});}if(a.length>0){let s=this._actionEngine.register(a);for(let c of s.errors){let l=this._actionIdToListenerId(c.actionId);r.push({listenerId:l??c.actionId,code:c.code??"ACTION_ERROR",message:c.error});}o.push(...s.warnings);}let f=[];for(let{id:s,stored:c,eventNames:l}of d){this._listenerRegistry.set(s,c);for(let E of l){let y=this._listenerIndex.get(E);y||(y=[],this._listenerIndex.set(E,y)),q(y,c);}f.push(s);}let g={registered:f,errors:r,warnings:o};return this._batch?(this._batch.registered.push(...f),this._batch.errors.push(...r),this._batch.warnings.push(...o)):f.length>0&&this._refreshListenerFlags(),g}unregister(n){let r=this._listenerRegistry.get(n);if(!r)return false;this._listenerRegistry.delete(n);let o=typeof r.definition.on=="string"?[r.definition.on]:r.definition.on;for(let a of o){let d=this._listenerIndex.get(a);d&&(U(d,r),d.length===0&&this._listenerIndex.delete(a));}return this._actionEngine.unregister(r.actionId),this._refreshListenerFlags(),true}processEvents(n,r){if(this._hasAnyInteractiveListener)throw new Error("Cannot call processEvents() \u2014 at least one listener is interactive (transitively). Use processEventsInteractive() instead.");if(this._isAsync)throw new Error("Cannot call processEvents() with async hooks or async listeners. Use processEventsAsync() instead.");let o=this._dispatcher(this._listenerIndex,n,r,this._actionEngine,this._middleware,this._eventHooks);return this._maybeAutoPromote(),o}async processEventsAsync(n,r){if(this._hasAnyInteractiveListener)throw new Error("Cannot call processEventsAsync() \u2014 at least one listener is interactive (transitively). Use processEventsInteractive() instead.");let o=await this._dispatcher(this._listenerIndex,n,r,this._actionEngine,this._middleware,this._eventHooks);return this._maybeAutoPromote(),o}processEventsInteractive(n,r){if(!this._hasAnyInteractiveListener)throw new Error("Cannot call processEventsInteractive() \u2014 no registered listener is interactive (transitively). Use processEvents() or processEventsAsync() instead.");return (this._interactiveDispatcher===null||this._interactiveDispatcherIsAsync!==this._isAsync)&&(this._interactiveDispatcher=this._mode==="jit"?Q(this._hookAnalysis,this._middleware.length>0,this._isAsync):V(this._hookAnalysis,this._isAsync),this._interactiveDispatcherIsAsync=this._isAsync),this._interactiveDispatcher(this._listenerIndex,n,r,this._actionEngine,this._middleware,this._eventHooks)}beginBatch(){this._batch||(this._batch={depth:0,registered:[],errors:[],warnings:[],definedEvents:[],defineErrors:[]}),this._batch.depth++,this._actionEngine.beginBatch();}endBatch(){if(!this._batch||this._batch.depth<=0)throw new Error("endBatch() called without matching beginBatch()");this._batch.depth--;let n=this._actionEngine.endBatch();if(this._batch.depth>0)return {registered:[],errors:[],warnings:[]};let r=this._batch;for(let a of n.errors){let d=this._actionIdToListenerId(a.actionId);r.errors.push({listenerId:d??a.actionId,code:a.code??"ACTION_ERROR",message:a.error});}r.warnings.push(...n.warnings);let o={registered:r.registered,errors:r.errors,warnings:r.warnings};return this._batch=null,this._refreshListenerFlags(),o}compile(){this._requestedMode!=="interpret"&&this._mode!=="jit"&&this._promote();}_promote(){this._dispatcher=this._buildJit(),this._mode="jit",this._maybeAutoPromote=F,this._interactiveDispatcher=null;}_buildJit(){return H(this._hookAnalysis,this._middleware.length>0,this._isAsync)}_refreshListenerFlags(){let n=false,r=false;for(let a of this._listenerRegistry.values())a.isAsync=this._actionEngine.isActionAsync(a.actionId)??false,a.isInteractive=this._actionEngine.isActionInteractive?.(a.actionId)??false,a.isAsync&&(n=true),a.isInteractive&&(r=true);this._hasAnyInteractiveListener=r;let o=this._hookAnalysis.hasAnyAsync||n;o!==this._isAsync&&(this._isAsync=o,this._rebuildDispatcher());}_rebuildDispatcher(){this._dispatcher=this._mode==="jit"?this._buildJit():$(this._hookAnalysis,this._isAsync);}_actionIdToListenerId(n){return n.startsWith("event:")?n.slice(6):null}_actionIdToEventName(n){return n.startsWith("eventdef:")?n.slice(9):null}};function ee(t){return new B(t)}function he(t="event"){return n=>{let r=n[t],o=typeof r=="string"&&r?[`eventdef:${r}`]:[];return {capabilities:["emit"],dependencies:o}}}export{he as createEmitAnalyzer,ee as createEventProcessor};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statedelta-actions/events",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Event processing engine with listener dispatch and JIT optimization",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
"README.md"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@statedelta-actions/core": "0.
|
|
22
|
-
"@statedelta-actions/actions": "0.
|
|
21
|
+
"@statedelta-actions/core": "0.5.0",
|
|
22
|
+
"@statedelta-actions/actions": "0.5.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@statedelta-actions/analyzer": "0.
|
|
26
|
-
"@statedelta-actions/graph": "0.
|
|
25
|
+
"@statedelta-actions/analyzer": "0.4.1",
|
|
26
|
+
"@statedelta-actions/graph": "0.4.1"
|
|
27
27
|
},
|
|
28
28
|
"author": "Anderson D. Rosa <andersondrosa@outlook.com>",
|
|
29
29
|
"license": "MIT",
|