@statedelta-actions/actions 0.1.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 ADDED
@@ -0,0 +1,541 @@
1
+ # @statedelta-actions/actions
2
+
3
+ Motor de execução de diretivas com validação em register-time e compilação JIT.
4
+
5
+ Defina ações como objetos JS declarativos. Registre. O engine valida estrutura, normaliza diretivas pra forma canônica, compila executores otimizados. Em runtime, invoke é O(1) lookup + execução — zero validação, zero análise.
6
+
7
+ ## Filosofia
8
+
9
+ **Engine = V8. Runtime puro.**
10
+
11
+ O engine é um executor. Não analisa dependências, não computa grafos, não valida contratos. Registro valida estrutura e compila. Invocação executa. Análise estática (grafo, capabilities, ciclos, composition control) é responsabilidade do `@statedelta-actions/analyzer` — uma camada externa opcional.
12
+
13
+ Ações são **declarativas**. Uma action é um ID mais uma lista ordenada de diretivas — objetos JS declarativos despachados por um campo de tipo (`type` por padrão). O engine não sabe o que "state", "emit" ou "action" significam. Handlers dão significado às diretivas. O engine orquestra a execução.
14
+
15
+ **Handlers têm fases.** Um handler não é só um executor. Ele pode validar estrutura da diretiva em register-time, contribuir código JIT, e executar em runtime. Cada fase é opcional — uma função simples funciona como handler (compat V1). Uma definição completa desbloqueia todo o pipeline. A fase `analyze` existe na interface mas é consumida pelo `ActionAnalyzer`, não pelo engine.
16
+
17
+ ## Instalação
18
+
19
+ ```bash
20
+ pnpm add @statedelta-actions/actions
21
+ ```
22
+
23
+ ## Início Rápido
24
+
25
+ ```typescript
26
+ import { createActionEngine } from "@statedelta-actions/actions";
27
+
28
+ // 1. Defina handlers — dão significado aos tipos de diretiva
29
+ const handlers = {
30
+ state: {
31
+ execute: (directive, frame) => {
32
+ const { target, value } = directive;
33
+ frame.ctx.state[target] = value;
34
+ return { ok: true, data: value };
35
+ },
36
+ },
37
+ emit: {
38
+ execute: (directive, frame) => {
39
+ frame.ctx.events.push(directive.event);
40
+ return { ok: true };
41
+ },
42
+ },
43
+ action: {
44
+ execute: (directive, frame, engine) => {
45
+ const result = engine.invoke(directive.id, directive.params, frame);
46
+ return { ok: result.success, data: result.data };
47
+ },
48
+ },
49
+ };
50
+
51
+ // 2. Crie o engine
52
+ const engine = createActionEngine({ handlers });
53
+
54
+ // 3. Registre ações
55
+ const result = engine.register([
56
+ {
57
+ id: "heal",
58
+ directives: [
59
+ { type: "state", target: "hp", value: 100 },
60
+ { type: "emit", event: "healed" },
61
+ ],
62
+ },
63
+ {
64
+ id: "combat",
65
+ directives: [
66
+ { type: "action", id: "heal" },
67
+ { type: "emit", event: "combat:done" },
68
+ ],
69
+ },
70
+ ]);
71
+
72
+ // result.registered → ["heal", "combat"]
73
+ // result.errors → []
74
+ // result.warnings → []
75
+
76
+ // 4. Defina contexto e invoque
77
+ engine.setContext({ state: {}, events: [] });
78
+
79
+ const r = engine.invoke("heal");
80
+ // r.success → true
81
+ // r.appliedCount → 2
82
+ ```
83
+
84
+ ## Handlers
85
+
86
+ Um handler processa diretivas de um tipo específico. Dois formatos:
87
+
88
+ ### V1 — Função simples
89
+
90
+ ```typescript
91
+ const handlers = {
92
+ log: (directive, frame, engine) => {
93
+ console.log(directive.message);
94
+ return { ok: true };
95
+ },
96
+ };
97
+ ```
98
+
99
+ Compatível com versões anteriores. Sem análise em register-time. Emite warning `NO_ANALYZE`.
100
+
101
+ ### V2 — Definição completa
102
+
103
+ ```typescript
104
+ const handlers = {
105
+ state: {
106
+ // Register-time: valida estrutura da diretiva
107
+ validate(directive) {
108
+ if (!directive.target) return { valid: false, error: "missing target" };
109
+ },
110
+
111
+ // Runtime: executa a diretiva
112
+ execute(directive, frame, engine) {
113
+ frame.ctx.state[directive.target] = directive.value;
114
+ return { ok: true, data: directive.value };
115
+ },
116
+
117
+ // Usado pelo ActionAnalyzer (não pelo engine):
118
+ // analyze(directive) {
119
+ // return { capabilities: ["write"], dependencies: [] };
120
+ // },
121
+ },
122
+ };
123
+ ```
124
+
125
+ | Fase | Quando | Propósito |
126
+ |------|--------|-----------|
127
+ | `validate` | Register | Validação estrutural (rejeita diretivas malformadas) |
128
+ | `execute` | Runtime | Processa a diretiva e retorna resultado |
129
+ | `analyze` | — | Consumido pelo `ActionAnalyzer` externo, não pelo engine |
130
+
131
+ ## Ações
132
+
133
+ Uma ação é um ID mais diretivas:
134
+
135
+ ```typescript
136
+ engine.register([{
137
+ id: "checkout",
138
+ directives: [
139
+ { type: "validate", schema: "cart" },
140
+ { type: "state", target: "status", value: "processing" },
141
+ { type: "action", id: "checkout/charge" },
142
+ { type: "emit", event: "checkout:complete" },
143
+ ],
144
+ }]);
145
+ ```
146
+
147
+ ### Categorias de Diretiva
148
+
149
+ Três categorias. Todas têm campo `type` na forma canônica. O consumer pode usar a forma sugar (shorthand) — o engine normaliza em register-time.
150
+
151
+ **Binding** — escrita no scope de execução:
152
+
153
+ ```typescript
154
+ // Sugar (authoring)
155
+ { const: "tax", value: 0.1 }
156
+ { let: "total", value: "$", resolve: (ctx, scope) => ({ value: scope.subtotal * 1.1 }) }
157
+
158
+ // Forma canônica (após normalização no register)
159
+ { type: "const", name: "tax", value: 0.1 }
160
+ { type: "let", name: "total", value: "$", resolve: (ctx, scope) => ({ value: scope.subtotal * 1.1 }) }
161
+ ```
162
+
163
+ **Control** — saída antecipada:
164
+
165
+ ```typescript
166
+ // Sugar (authoring)
167
+ { return: "done" }
168
+ { throw: "saldo insuficiente" }
169
+
170
+ // Forma canônica (após normalização no register)
171
+ { type: "return", value: "done" } // success: true, data: "done"
172
+ { type: "throw", message: "saldo insuficiente" } // success: false
173
+ ```
174
+
175
+ **Handler** — dispatch pro handler registrado:
176
+
177
+ ```typescript
178
+ { type: "state", target: "hp", value: 100, as: "prev" }
179
+ { type: "action", id: "heal", catch: [{ type: "emit", event: "heal:failed" }] }
180
+ ```
181
+
182
+ Após normalização, **toda diretiva tem `type`**. O interpreter e JIT operam sobre formato uniforme — um único dispatch via `type` field, sem branching de categorias.
183
+
184
+ Os nomes `const`, `let`, `return`, `throw` são **tipos reservados** — o engine rejeita handlers com esses nomes.
185
+
186
+ Diretivas suportam:
187
+ - **`as`** — captura `result.data` no scope: `scope["prev"] = result.data`
188
+ - **`catch`** — em caso de falha, executa sub-diretivas com `scope.$exception`
189
+ - **`halt`** — handler retorna `{ ok: true, halt: true }` para saída antecipada
190
+ - **`resolve`** — campos dinâmicos mesclados antes da chamada: `resolve(ctx, scope) → campos mesclados`
191
+
192
+ ## Registro
193
+
194
+ ```typescript
195
+ const result = engine.register(actions);
196
+ ```
197
+
198
+ O pipeline de registro:
199
+
200
+ 1. **Validate** — valida estrutura via `handler.validate()` (rejeita diretivas malformadas)
201
+ 2. **Normalize** — converte sugar forms (`{ const: ... }`, `{ return: ... }`) pra forma canônica (`{ type: "const", ... }`)
202
+ 3. **Store** — armazena no registry com diretivas normalizadas
203
+ 4. **Compile** — compila executor (interpret/JIT) sobre formato canônico
204
+ 5. **Emit** — emite evento `register` via lifecycle events
205
+
206
+ Retorna `RegisterResult`:
207
+
208
+ ```typescript
209
+ {
210
+ registered: string[]; // IDs registrados com sucesso
211
+ errors: RegisterError[]; // Falhas de validação
212
+ warnings: RegisterWarning[]; // NO_ANALYZE, ANALYZE_ERROR
213
+ }
214
+ ```
215
+
216
+ ### Desregistrar
217
+
218
+ ```typescript
219
+ engine.unregister("checkout");
220
+ // Também remove filhas: "checkout/charge", "checkout/validate", etc.
221
+ ```
222
+
223
+ ## Modo Batch
224
+
225
+ Batch agrupa múltiplos registros e adia emissão de eventos pro `endBatch()`:
226
+
227
+ ```typescript
228
+ engine.beginBatch();
229
+ engine.register([actionA]);
230
+ engine.register([actionB]);
231
+ const result = engine.endBatch(); // Único evento "register" emitido
232
+ ```
233
+
234
+ Suporta aninhamento — `endBatch()` interno é no-op. Processamento acontece na profundidade 0.
235
+
236
+ ## Invocação
237
+
238
+ ```typescript
239
+ // Defina contexto primeiro
240
+ engine.setContext(ctx);
241
+ const result = engine.invoke("heal");
242
+ const result = engine.invoke("heal", { amount: 50 });
243
+
244
+ // Ou contexto com escopo
245
+ engine.context(ctx, () => {
246
+ engine.invoke("heal");
247
+ engine.invoke("combat");
248
+ });
249
+
250
+ // Async (obrigatório se algum hook for async)
251
+ const result = await engine.invokeAsync("heal");
252
+ ```
253
+
254
+ Retorna `DirectiveResult`:
255
+
256
+ ```typescript
257
+ {
258
+ success: boolean;
259
+ aborted: boolean;
260
+ abortedBy?: string; // "halt" | "throw" | "maxDepth"
261
+ appliedCount: number;
262
+ skippedCount: number;
263
+ errors: DirectiveError[];
264
+ data?: unknown; // De return directive ou halt
265
+ counters: FrameCounters;
266
+ }
267
+ ```
268
+
269
+ **Nunca lança exceções.** Erros são coletados em `result.errors`. Exceções de handlers são capturadas e reportadas.
270
+
271
+ ### Sub-Actions (Visibilidade)
272
+
273
+ Ações com `/` no ID são privadas:
274
+
275
+ ```typescript
276
+ engine.register([
277
+ { id: "checkout/validate", directives: [...] }, // privada
278
+ { id: "checkout", directives: [
279
+ { type: "action", id: "checkout/validate" }, // ok — escopo do pai
280
+ ]},
281
+ ]);
282
+
283
+ engine.invoke("checkout/validate"); // erro — não acessível da raiz
284
+ ```
285
+
286
+ ## Lifecycle Events
287
+
288
+ O engine emite eventos de ciclo de vida via `on()`. Retorna função de unsubscribe idempotente:
289
+
290
+ ```typescript
291
+ const unsub = engine.on("register", (event) => {
292
+ console.log("Registrados:", event.registered);
293
+ console.log("Resultado:", event.result);
294
+ });
295
+
296
+ engine.on("unregister", (event) => {
297
+ console.log("Removido:", event.id);
298
+ console.log("Cascata:", event.cascaded);
299
+ });
300
+
301
+ // Cancelar subscription
302
+ unsub();
303
+ ```
304
+
305
+ | Evento | Payload | Quando |
306
+ |--------|---------|--------|
307
+ | `register` | `{ actions, result, registered }` | Após `register()` ou `endBatch()` |
308
+ | `unregister` | `{ id, cascaded }` | Após `unregister()` |
309
+
310
+ Em batch mode, o evento `register` é emitido uma única vez no `endBatch()` com todas as actions do batch.
311
+
312
+ ## Read-Only Accessors
313
+
314
+ Acessores de leitura para introspection por camadas externas (e.g. analyzer):
315
+
316
+ ```typescript
317
+ // Map de handler definitions V2 registradas
318
+ engine.handlerDefinitions; // ReadonlyMap<string, HandlerDefinition>
319
+
320
+ // Set de IDs de todas as actions no registry
321
+ engine.registeredIds; // ReadonlySet<string>
322
+
323
+ // Lê uma action definition pelo ID
324
+ engine.getActionDefinition("heal"); // ActionDefinition | undefined
325
+
326
+ // Campo de tipo pra dispatch de diretivas
327
+ engine.typeField; // string (default: "type")
328
+
329
+ // Mapa de permissões de diretivas (computado no boot, imutável)
330
+ engine.directivePermissions; // ReadonlyMap<string, DirectivePermission>
331
+
332
+ // Slots de hooks preenchidos (nomes dos hooks registrados)
333
+ engine.directiveHookSlots; // ReadonlySet<string>
334
+
335
+ // Slots async (nomes dos hooks que são async)
336
+ engine.asyncSlots; // ReadonlySet<string>
337
+ ```
338
+
339
+ ## Modos de Compilação
340
+
341
+ ```typescript
342
+ createActionEngine({ handlers, mode: "interpret" }); // Interpretador loop-based (dev)
343
+ createActionEngine({ handlers, mode: "jit" }); // Compila tudo no register (prod)
344
+ createActionEngine({ handlers, mode: "auto" }); // Interpreta primeiro, promove após N invocações (padrão)
345
+ ```
346
+
347
+ | Modo | Register | Runtime | Ideal para |
348
+ |------|----------|---------|------------|
349
+ | `interpret` | Rápido | Loop interpretado | Desenvolvimento, debug |
350
+ | `jit` | Mais lento (compila) | `new Function` compilado | Produção, ações estáveis |
351
+ | `auto` | Rápido | Promove per-action após threshold | Uso geral (padrão) |
352
+
353
+ Threshold de auto-promote (padrão: 8):
354
+
355
+ ```typescript
356
+ createActionEngine({ handlers, mode: "auto", autoJitThreshold: 4 });
357
+ ```
358
+
359
+ Forçar compilação de todas as ações registradas:
360
+
361
+ ```typescript
362
+ engine.compile();
363
+ ```
364
+
365
+ Informações de compilação:
366
+
367
+ ```typescript
368
+ engine.isAsync; // true se hooks async detectados
369
+ engine.compilationMode; // "interpret" | "jit" (modo atual, não o requestado)
370
+ ```
371
+
372
+ ## Hooks
373
+
374
+ Três pontos de hook em nível de diretiva:
375
+
376
+ ```typescript
377
+ createActionEngine({
378
+ handlers,
379
+ directiveHooks: {
380
+ beforeDirective(directive, frame) {
381
+ // Retorne "skip" pra pular, "abort" pra abortar
382
+ // Retorne { directive } pra substituir, { ctx } pra sobrescrever contexto
383
+ },
384
+ afterDirective(directive, result, frame) {
385
+ // Retorne "abort" pra parar execução
386
+ },
387
+ onDirectivesComplete(result) {
388
+ // Fire-and-forget — observa resultado final
389
+ },
390
+ },
391
+ });
392
+ ```
393
+
394
+ Hooks podem ser sync ou async. Hooks async tornam o engine async (`engine.isAsync === true`), exigindo `invokeAsync()`.
395
+
396
+ **Custo zero quando ausente.** A compilação JIT não emite código de hook para hooks não registrados.
397
+
398
+ ## Handler Permissions
399
+
400
+ Controle declarativo de quais diretivas uma instância do engine pode usar. Útil pra governança (sandbox parent→child) e arquitetura (query actions não devem mutar estado).
401
+
402
+ ```typescript
403
+ // Whitelist: só estes tipos permitidos
404
+ createActionEngine({
405
+ handlers,
406
+ allowedDirectives: ["state:query", "emit", "action"],
407
+ });
408
+
409
+ // Blacklist: estes tipos bloqueados
410
+ createActionEngine({
411
+ handlers,
412
+ blockedDirectives: ["state:dispatch", "emit"],
413
+ });
414
+
415
+ // Blacklist com motivações
416
+ createActionEngine({
417
+ handlers,
418
+ blockedDirectives: [
419
+ { pattern: "state:dispatch", reason: "sandbox read-only", source: "parent:root" },
420
+ { pattern: "emit", reason: "events disabled", source: "config" },
421
+ ],
422
+ });
423
+ ```
424
+
425
+ **Regras:**
426
+ - `allowedDirectives` e `blockedDirectives` são **mutuamente exclusivos**. Se ambos fornecidos: erro no constructor.
427
+ - Se nenhum fornecido: tudo permitido (default, zero overhead).
428
+ - Diretivas estáticas (`const`, `let`, `return`, `throw`) são **sempre permitidas** — não podem ser bloqueadas.
429
+ - Patterns com wildcard `*` são suportados: `"state:*"`, `"*:dispatch"`, `"*"`.
430
+
431
+ **O engine não bloqueia execução.** Permissions são config, não enforcement. Actions com handler denied **registram e executam normalmente**. Quem valida violations é o `ActionAnalyzer`. Quem decide a política (rejeitar boot, warning, ignorar) é o consumer.
432
+
433
+ ```typescript
434
+ // Consultar permissões
435
+ const perms = engine.directivePermissions;
436
+
437
+ perms.get("emit");
438
+ // → { status: "available" }
439
+
440
+ perms.get("state:dispatch");
441
+ // → { status: "denied", reason: "sandbox read-only", source: "parent:root" }
442
+
443
+ // Handler inexistente: não está no mapa (unavailable é derivado)
444
+ perms.has("notify");
445
+ // → false
446
+ ```
447
+
448
+ ## Referência de Configuração
449
+
450
+ ```typescript
451
+ interface IActionEngineConfig<TCtx> {
452
+ handlers: HandlerInputMap<TCtx>; // Obrigatório — handlers de diretivas
453
+ typeField?: string; // Campo de dispatch (padrão: "type")
454
+ directiveHooks?: DirectiveHooks<TCtx>; // Hooks de diretiva
455
+ limits?: Partial<FrameLimits>; // maxDepth (10), maxRules, maxDirectives
456
+ mode?: "interpret" | "jit" | "auto"; // Modo de compilação (padrão: "auto")
457
+ autoJitThreshold?: number; // Auto-promote após N invocações (padrão: 8)
458
+ allowedDirectives?: DirectivePermissionEntry[]; // Whitelist com pattern matching
459
+ blockedDirectives?: DirectivePermissionEntry[]; // Blacklist com pattern matching
460
+ }
461
+ ```
462
+
463
+ ## Exports
464
+
465
+ ```typescript
466
+ // Factory
467
+ import { createActionEngine } from "@statedelta-actions/actions";
468
+
469
+ // Tipos (V1)
470
+ import type {
471
+ DirectiveHandler,
472
+ DirectiveHandlerMap,
473
+ DirectiveHooks,
474
+ DirectiveExecutorFn,
475
+ DirectiveRunnerFn,
476
+ } from "@statedelta-actions/actions";
477
+
478
+ // Tipos (V2)
479
+ import type {
480
+ HandlerDefinition,
481
+ HandlerAnalysis,
482
+ ValidationResult,
483
+ HandlerInput,
484
+ HandlerInputMap,
485
+ ActionDefinition,
486
+ RegisterResult,
487
+ RegisterError,
488
+ RegisterWarning,
489
+ IActionEngineConfig,
490
+ IActionEngine,
491
+ } from "@statedelta-actions/actions";
492
+
493
+ // Lifecycle Events
494
+ import type {
495
+ RegisterEvent,
496
+ UnregisterEvent,
497
+ EngineEventMap,
498
+ EngineEventName,
499
+ } from "@statedelta-actions/actions";
500
+
501
+ // Directive Permissions
502
+ import type {
503
+ DirectivePermissionStatus,
504
+ DirectivePermission,
505
+ DirectivePermissionConfig,
506
+ DirectivePermissionEntry,
507
+ } from "@statedelta-actions/actions";
508
+
509
+ // Register Pipeline
510
+ import { normalizeDirectives, RESERVED_TYPES } from "@statedelta-actions/actions";
511
+
512
+ // Emitter
513
+ import { SimpleEmitter } from "@statedelta-actions/actions";
514
+ import type { Listener } from "@statedelta-actions/actions";
515
+
516
+ // Interpreter
517
+ import { createDirectiveInterpreter } from "@statedelta-actions/actions";
518
+
519
+ // JIT (generic)
520
+ import { buildDirectiveExecutor } from "@statedelta-actions/actions";
521
+ import type { GeneratedDirectiveExecutor } from "@statedelta-actions/actions";
522
+
523
+ // JIT (per-action)
524
+ import { buildActionExecutor } from "@statedelta-actions/actions";
525
+ import type { GeneratedActionExecutor } from "@statedelta-actions/actions";
526
+ ```
527
+
528
+ ## Analyzer
529
+
530
+ Funcionalidades de análise estática foram extraídas para o pacote `@statedelta-actions/analyzer`:
531
+
532
+ - **Grafo de dependências** — capabilities, leaf, maxDepth, ciclos
533
+ - **Declarations** — trust boundaries, conflitos de contrato
534
+ - **Propagators** — propriedades computadas e propagadas pelo grafo
535
+ - **Composition Control** — manifest declarativo, tags, matchers, transitividade
536
+
537
+ O analyzer consome os read-only accessors e lifecycle events do engine. Consulte a documentação do `@statedelta-actions/analyzer` para detalhes.
538
+
539
+ ## Licença
540
+
541
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,9 @@
1
+ 'use strict';var core=require('@statedelta-actions/core');var F=class{_listeners=new Map;on(e,i){let n=this._listeners.get(e);n||(n=new Set,this._listeners.set(e,n)),n.add(i);let s=false;return ()=>{s||(s=true,n.delete(i),n.size===0&&this._listeners.delete(e));}}once(e,i){let n=this.on(e,s=>{n(),i(s);});return n}emit(e,i){let n=this._listeners.get(e);if(!n||n.size===0)return;let s=[...n];for(let r=0;r<s.length;r++)try{s[r](i);}catch(c){console.error(`[SimpleEmitter] Listener error on "${e}":`,c);}}listenerCount(e){return this._listeners.get(e)?.size??0}hasListeners(e){let i=this._listeners.get(e);return i!==void 0&&i.size>0}off(e){this._listeners.delete(e);}removeAllListeners(){this._listeners.clear();}};var S=new Set(["const","let","return","throw"]);function W(t,e,i,n){let s=[];for(let r=0;r<t.directives.length;r++){let c=t.directives[r];if("const"in c||"let"in c||"return"in c||"throw"in c)continue;let h=c[n];if(!h){s.push(`directive[${r}]: missing type field "${n}"`);continue}if(!e[h]){s.push(`directive[${r}]: no handler for type "${h}"`);continue}let x=i.get(h);if(x?.validate)try{let D=x.validate(c);D&&!D.valid&&s.push(`directive[${r}]: ${D.error??"validation failed"}`);}catch(D){s.push(`directive[${r}]: validate threw: ${D}`);}let m=c.catch;if(m&&Array.isArray(m))for(let D=0;D<m.length;D++){let R=m[D];if("const"in R||"let"in R||"return"in R||"throw"in R)continue;let v=R[n];v&&!e[v]&&s.push(`directive[${r}].catch[${D}]: no handler for type "${v}"`);}}return s}function H(t,e){let i=t.length,n=new Array(i);for(let s=0;s<i;s++){let r=t[s];if("const"in r)n[s]=q(r,"const");else if("let"in r)n[s]=q(r,"let");else if("return"in r)n[s]=te(r);else if("throw"in r)n[s]=re(r);else {let c=r.catch;Array.isArray(c)&&c.length>0?n[s]={...r,catch:H(c)}:n[s]=r;}}return n}function q(t,e){let{[e]:i,...n}=t;return {...n,type:e,name:i}}function te(t){let{return:e,...i}=t;return {...i,type:"return",value:e}}function re(t){let{throw:e,...i}=t;return {...i,type:"throw",message:e}}function M(t,e,i,n,s,r,c){return {success:false,aborted:true,abortedBy:t,appliedCount:e,skippedCount:i,errors:n,processedCount:s,totalCount:r,counters:c}}function ie(t){let e=t.filledNames.has("beforeDirective"),i=t.filledNames.has("afterDirective"),n=t.filledNames.has("onDirectivesComplete");return function(r,c,h,x,m,D,R){let v=Math.min(r.length,R),l=[],f=0,_=0,{counters:u,scope:C}=c,A=c.ctx;for(let a=0;a<v;a++){let p=r[a],$=p[m];if($==="const"||$==="let"){let o=p.name;if(typeof p.resolve=="function")try{C[o]=p.resolve(A,C).value;}catch(d){l.push({directiveIndex:a,error:`Binding resolve: ${d}`}),u.errors++;}else C[o]=p.value;continue}if($==="return"){let o=a+1;if(typeof p.resolve=="function")try{let d=p.resolve(A,C),b="value"in d?d.value:"return"in d?d.return:p.value;return {success:!0,aborted:!1,appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:b}}catch(d){l.push({directiveIndex:a,error:`Control resolve: ${d}`}),u.errors++;}else return {success:true,aborted:false,appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:p.value};continue}if($==="throw"){let o=a+1;if(typeof p.resolve=="function")try{let d=p.resolve(A,C),b="message"in d?d.message:"throw"in d?d.throw:p.message;return {success:!1,aborted:!0,abortedBy:"throw",appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:b}}catch(d){l.push({directiveIndex:a,error:`Control resolve: ${d}`}),u.errors++;}else return {success:false,aborted:true,abortedBy:"throw",appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:p.message};continue}let y=p,E=c;if(e)try{let o=core.processIntercept(x.beforeDirective(y,c),"beforeDirective");if(o.action===core.Intercept.SKIP){_++,u.directivesSkipped++;continue}if(o.action===core.Intercept.ABORT)return M(o.abortReason,f,_,l,a,v,u);o.ctx!==void 0&&(E=c.withCtx(o.ctx)),o.directive!==void 0&&(y=o.directive);}catch(o){l.push({directiveIndex:a,error:`Hook beforeDirective: ${o}`}),u.errors++;}if(typeof y.resolve=="function")try{let o=y.resolve(E.ctx,E.scope);y={...y,...o};}catch(o){l.push({directiveIndex:a,error:`Directive resolve: ${o}`}),u.errors++;continue}let w=y[m],I=w?h[w]:void 0;if(!I){l.push({directiveIndex:a,error:`No handler for directive type: ${w??"undefined"}`}),u.errors++;continue}let g;try{g=I(y,E,D);}catch(o){g={ok:false,error:String(o)};}let T=a+1;if(g.ok){if(f++,u.directivesApplied++,typeof y.as=="string"&&(C[y.as]=g.data),g.halt)return {success:true,aborted:true,abortedBy:"halt",appliedCount:f,skippedCount:_,errors:l,processedCount:T,totalCount:v,counters:u,data:g.data}}else {if(g.halt)return {success:false,aborted:true,abortedBy:"halt",appliedCount:f,skippedCount:_,errors:l,processedCount:T,totalCount:v,counters:u,data:g.data};let o=y.catch;if(Array.isArray(o)&&o.length>0){C.$exception=g.error??"handler failed";let d=D.runDirectives(o,E);f+=d.appliedCount;for(let b=0;b<d.errors.length;b++)l.push(d.errors[b]);if(d.aborted)return {success:d.success,aborted:true,abortedBy:d.abortedBy,appliedCount:f,skippedCount:_,errors:l,processedCount:T,totalCount:v,counters:u,data:d.data}}else l.push({directiveIndex:a,error:g.error??"handler failed"}),u.errors++;}if(i)try{if(x.afterDirective(y,g,E)==="abort")return M("afterDirective",f,_,l,T,v,u)}catch(o){l.push({directiveIndex:a,error:`Hook afterDirective: ${o}`}),u.errors++;}}let k={success:true,aborted:false,appliedCount:f,skippedCount:_,errors:l,processedCount:v,totalCount:v,counters:u};if(n)try{x.onDirectivesComplete(k);}catch{}return k}}function ne(t){let e=t.filledNames.has("beforeDirective"),i=t.filledNames.has("afterDirective"),n=t.filledNames.has("onDirectivesComplete");return async function(r,c,h,x,m,D,R){let v=Math.min(r.length,R),l=[],f=0,_=0,{counters:u,scope:C}=c,A=c.ctx;for(let a=0;a<v;a++){let p=r[a],$=p[m];if($==="const"||$==="let"){let o=p.name;if(typeof p.resolve=="function")try{C[o]=p.resolve(A,C).value;}catch(d){l.push({directiveIndex:a,error:`Binding resolve: ${d}`}),u.errors++;}else C[o]=p.value;continue}if($==="return"){let o=a+1;if(typeof p.resolve=="function")try{let d=p.resolve(A,C),b="value"in d?d.value:"return"in d?d.return:p.value;return {success:!0,aborted:!1,appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:b}}catch(d){l.push({directiveIndex:a,error:`Control resolve: ${d}`}),u.errors++;}else return {success:true,aborted:false,appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:p.value};continue}if($==="throw"){let o=a+1;if(typeof p.resolve=="function")try{let d=p.resolve(A,C),b="message"in d?d.message:"throw"in d?d.throw:p.message;return {success:!1,aborted:!0,abortedBy:"throw",appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:b}}catch(d){l.push({directiveIndex:a,error:`Control resolve: ${d}`}),u.errors++;}else return {success:false,aborted:true,abortedBy:"throw",appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:p.message};continue}let y=p,E=c;if(e)try{let o=core.processIntercept(await x.beforeDirective(y,c),"beforeDirective");if(o.action===core.Intercept.SKIP){_++,u.directivesSkipped++;continue}if(o.action===core.Intercept.ABORT)return M(o.abortReason,f,_,l,a,v,u);o.ctx!==void 0&&(E=c.withCtx(o.ctx)),o.directive!==void 0&&(y=o.directive);}catch(o){l.push({directiveIndex:a,error:`Hook beforeDirective: ${o}`}),u.errors++;}if(typeof y.resolve=="function")try{let o=y.resolve(E.ctx,E.scope);y={...y,...o};}catch(o){l.push({directiveIndex:a,error:`Directive resolve: ${o}`}),u.errors++;continue}let w=y[m],I=w?h[w]:void 0;if(!I){l.push({directiveIndex:a,error:`No handler for directive type: ${w??"undefined"}`}),u.errors++;continue}let g;try{g=I(y,E,D);}catch(o){g={ok:false,error:String(o)};}let T=a+1;if(g.ok){if(f++,u.directivesApplied++,typeof y.as=="string"&&(C[y.as]=g.data),g.halt)return {success:true,aborted:true,abortedBy:"halt",appliedCount:f,skippedCount:_,errors:l,processedCount:T,totalCount:v,counters:u,data:g.data}}else {if(g.halt)return {success:false,aborted:true,abortedBy:"halt",appliedCount:f,skippedCount:_,errors:l,processedCount:T,totalCount:v,counters:u,data:g.data};let o=y.catch;if(Array.isArray(o)&&o.length>0){C.$exception=g.error??"handler failed";let d=await D.runDirectivesAsync(o,E);f+=d.appliedCount;for(let b=0;b<d.errors.length;b++)l.push(d.errors[b]);if(d.aborted)return {success:d.success,aborted:true,abortedBy:d.abortedBy,appliedCount:f,skippedCount:_,errors:l,processedCount:T,totalCount:v,counters:u,data:d.data}}else l.push({directiveIndex:a,error:g.error??"handler failed"}),u.errors++;}if(i)try{if(await x.afterDirective(y,g,E)==="abort")return M("afterDirective",f,_,l,T,v,u)}catch(o){l.push({directiveIndex:a,error:`Hook afterDirective: ${o}`}),u.errors++;}}let k={success:true,aborted:false,appliedCount:f,skippedCount:_,errors:l,processedCount:v,totalCount:v,counters:u};if(n)try{await x.onDirectivesComplete(k);}catch{}return k}}function B(t,e){return e?ne(t):ie(t)}function j(t){let{filledNames:e,hasAnyAsync:i}=t,n=m=>e.has(m),s=m=>t.asyncNames.has(m)?"await ":"",r=[];for(let m of e)r.push(`const ${m} = directiveHooks.${m};`);r.push("const len = Math.min(directives.length, maxDirectives);"),r.push("const errors = []; let appliedCount = 0; let skippedCount = 0;"),r.push("const counters = frame.counters;"),r.push("for (let i = 0; i < len; i++) {"),r.push(" let directive = directives[i];"),n("beforeDirective")?(r.push(" let _df = frame;"),r.push(" try {"),r.push(` const _bd = ${s("beforeDirective")}beforeDirective(directive, frame);`),r.push(' if (_bd === "skip") { skippedCount++; counters.directivesSkipped++; continue; }'),r.push(' if (_bd === "abort") return { success: false, aborted: true, abortedBy: "beforeDirective", appliedCount, skippedCount, errors, processedCount: i, totalCount: len, counters };'),r.push(' if (typeof _bd === "object" && _bd !== null) {'),r.push(' if ("abort" in _bd) return { success: false, aborted: true, abortedBy: _bd.abort, appliedCount, skippedCount, errors, processedCount: i, totalCount: len, counters };'),r.push(' if ("ctx" in _bd) _df = frame.withCtx(_bd.ctx);'),r.push(' if ("directive" in _bd) directive = _bd.directive;'),r.push(" }"),r.push(' } catch (_e) { errors.push({ directiveIndex: i, error: "Hook beforeDirective: " + _e }); counters.errors++; }')):r.push(" const _df = frame;"),r.push(' if (typeof directive.resolve === "function") {'),r.push(" try { const _r = directive.resolve(_df.ctx); directive = Object.assign({}, directive, _r); }"),r.push(' catch (_e) { errors.push({ directiveIndex: i, error: "Directive resolve: " + _e }); counters.errors++; continue; }'),r.push(" }"),r.push(" const _type = directive[typeField];"),r.push(" const _handler = _type ? handlers[_type] : undefined;"),r.push(' if (!_handler) { errors.push({ directiveIndex: i, error: "No handler for directive type: " + (_type || "undefined") }); counters.errors++; continue; }'),r.push(" let _result;"),r.push(" try { _result = _handler(directive, _df, engine); } catch (_e) { errors.push({ directiveIndex: i, error: String(_e) }); counters.errors++; continue; }"),r.push(" if (_result.ok) { appliedCount++; counters.directivesApplied++; }"),r.push(' else { errors.push({ directiveIndex: i, error: _result.error || "handler failed" }); counters.errors++; }'),n("afterDirective")&&(r.push(" try {"),r.push(` const _ad = ${s("afterDirective")}afterDirective(directive, _result, _df);`),r.push(' if (_ad === "abort") return { success: false, aborted: true, abortedBy: "afterDirective", appliedCount, skippedCount, errors, processedCount: i + 1, totalCount: len, counters };'),r.push(' } catch (_e) { errors.push({ directiveIndex: i, error: "Hook afterDirective: " + _e }); counters.errors++; }')),r.push("}"),r.push("const _finalResult = { success: true, aborted: false, appliedCount, skippedCount, errors, processedCount: len, totalCount: len, counters };"),n("onDirectivesComplete")&&r.push(`try { ${s("onDirectivesComplete")}onDirectivesComplete(_finalResult); } catch (_e) {}`),r.push("return _finalResult;");let c=r.join(`
2
+ `),h=i?"async ":"";return {fn:new Function("directives","frame","handlers","directiveHooks","typeField","engine","maxDirectives",`"use strict";
3
+ return (${h}() => {
4
+ ${c}
5
+ })();`),isAsync:i}}function N(t,e,i){return `return{success:false,aborted:true,abortedBy:${t},appliedCount,skippedCount,errors,processedCount:${e},totalCount:${i},counters};`}function se(t,e){return `return{success:true,aborted:true,abortedBy:"halt",appliedCount,skippedCount,errors,processedCount:${t},totalCount:${e},counters,data:_result.data};`}function oe(t,e){return `return{success:false,aborted:true,abortedBy:"halt",appliedCount,skippedCount,errors,processedCount:${t},totalCount:${e},counters,data:_result.data};`}function ce(t,e,i){let n=JSON.stringify(e.name);typeof e.resolve=="function"?(t.push("try{"),t.push(`scope[${n}]=$.d[${i}].resolve(ctx,scope).value;`),t.push(`}catch(_e){errors.push({directiveIndex:${i},error:"Binding resolve: "+_e});counters.errors++;}`)):t.push(`scope[${n}]=$.d[${i}].value;`);}function ae(t,e,i,n){let s=typeof e.resolve=="function",r=i+1;s?(t.push("try{"),t.push(`const _rv=$.d[${i}].resolve(ctx,scope);`),t.push(`return{success:true,aborted:false,appliedCount,skippedCount,errors,processedCount:${r},totalCount:${n},counters,data:"value" in _rv?_rv.value:"return" in _rv?_rv.return:$.d[${i}].value};`),t.push(`}catch(_e){errors.push({directiveIndex:${i},error:"Control resolve: "+_e});counters.errors++;}`)):t.push(`return{success:true,aborted:false,appliedCount,skippedCount,errors,processedCount:${r},totalCount:${n},counters,data:$.d[${i}].value};`);}function ue(t,e,i,n){let s=typeof e.resolve=="function",r=i+1;s?(t.push("try{"),t.push(`const _rv=$.d[${i}].resolve(ctx,scope);`),t.push(`return{success:false,aborted:true,abortedBy:"throw",appliedCount,skippedCount,errors,processedCount:${r},totalCount:${n},counters,data:"message" in _rv?_rv.message:"throw" in _rv?_rv.throw:$.d[${i}].message};`),t.push(`}catch(_e){errors.push({directiveIndex:${i},error:"Control resolve: "+_e});counters.errors++;}`)):t.push(`return{success:false,aborted:true,abortedBy:"throw",appliedCount,skippedCount,errors,processedCount:${r},totalCount:${n},counters,data:$.d[${i}].message};`);}function de(t,e,i,n,s,r,c,h,x,m){let D=e[s],R=r.get(D),v=typeof e.resolve=="function",l=typeof e.as=="string",f=Array.isArray(e.catch)&&e.catch.length>0,_=l?JSON.stringify(e.as):"",u=i+1;t.push(`_b${i}:{`);let C=c||v,A=c;C&&t.push(`let _dir=$.d[${i}];`),A&&t.push("let _df=frame;"),c&&(t.push("try{"),t.push(`const _bd=${x}_hookBefore($.d[${i}],frame);`),t.push(`if(_bd==="skip"){skippedCount++;counters.directivesSkipped++;break _b${i};}`),t.push(`if(_bd==="abort")${N('"beforeDirective"',i,n)}`),t.push('if(typeof _bd==="object"&&_bd!==null){'),t.push(`if("abort" in _bd)${N("_bd.abort",i,n)}`),t.push('if("ctx" in _bd)_df=frame.withCtx(_bd.ctx);'),t.push('if("directive" in _bd)_dir=_bd.directive;'),t.push("}"),t.push(`}catch(_e){errors.push({directiveIndex:${i},error:"Hook beforeDirective: "+_e});counters.errors++;}`)),c?(t.push('if(typeof _dir.resolve==="function"){'),t.push("try{const _r=_dir.resolve(_df.ctx,scope);_dir=Object.assign({},_dir,_r);}"),t.push(`catch(_e){errors.push({directiveIndex:${i},error:"Directive resolve: "+_e});counters.errors++;break _b${i};}}`)):v&&(t.push(`try{const _r=$.d[${i}].resolve(ctx,scope);_dir=Object.assign({},$.d[${i}],_r);}`),t.push(`catch(_e){errors.push({directiveIndex:${i},error:"Directive resolve: "+_e});counters.errors++;break _b${i};}`));let k=C?"_dir":`$.d[${i}]`,a=A?"_df":"frame";t.push("let _result;"),t.push(`try{_result=${R}(${k},${a},$.engine);}`),t.push("catch(_e){_result={ok:false,error:String(_e)};}"),t.push("if(_result.ok){"),t.push("appliedCount++;counters.directivesApplied++;"),l&&t.push(`scope[${_}]=_result.data;`),t.push(`if(_result.halt)${se(u,n)}`),t.push("}else{"),t.push(`if(_result.halt)${oe(u,n)}`),f?(t.push('scope.$exception=_result.error||"handler failed";'),t.push(`const _cr=$.runner($.d[${i}].catch,${a});`),t.push("appliedCount+=_cr.appliedCount;"),t.push("for(let _j=0;_j<_cr.errors.length;_j++)errors.push(_cr.errors[_j]);"),t.push(`if(_cr.aborted)return{success:_cr.success,aborted:true,abortedBy:_cr.abortedBy,appliedCount,skippedCount,errors,processedCount:${u},totalCount:${n},counters,data:_cr.data};`)):t.push(`errors.push({directiveIndex:${i},error:_result.error||"handler failed"});counters.errors++;`),t.push("}"),h&&(t.push("try{"),t.push(`const _ad=${m}_hookAfter(${k},_result,${a});`),t.push(`if(_ad==="abort")${N('"afterDirective"',u,n)}`),t.push(`}catch(_e){errors.push({directiveIndex:${i},error:"Hook afterDirective: "+_e});counters.errors++;}`)),t.push("}");}function O(t,e,i){let n=[],s=t.length,{filledNames:r,hasAnyAsync:c,asyncNames:h}=e,x=r.has("beforeDirective"),m=r.has("afterDirective"),D=r.has("onDirectivesComplete"),R=h.has("beforeDirective")?"await ":"",v=h.has("afterDirective")?"await ":"",l=h.has("onDirectivesComplete")?"await ":"",f=new Set;for(let a of t){let p=a[i];p&&!S.has(p)&&f.add(p);}let _=new Map,u=0;for(let a of f)_.set(a,`_h${u++}`);n.push("const counters=frame.counters;"),n.push("const ctx=frame.ctx;"),n.push("const errors=[];"),n.push("let appliedCount=0;"),n.push("let skippedCount=0;");for(let[a,p]of _)n.push(`const ${p}=$.h[${JSON.stringify(a)}];`);x&&n.push("const _hookBefore=$.hooks.beforeDirective;"),m&&n.push("const _hookAfter=$.hooks.afterDirective;");for(let a=0;a<t.length;a++){let p=t[a];switch(p[i]){case "const":case "let":ce(n,p,a);break;case "return":ae(n,p,a,s);break;case "throw":ue(n,p,a,s);break;default:de(n,p,a,s,i,_,x,m,R,v);break}}n.push(`const _finalResult={success:true,aborted:false,appliedCount,skippedCount,errors,processedCount:${s},totalCount:${s},counters};`),D&&n.push(`try{${l}$.hooks.onDirectivesComplete(_finalResult);}catch(_e){}`),n.push("return _finalResult;");let C=n.join(`
6
+ `),A=c?"async ":"";return {fn:new Function("frame","scope","$",`"use strict";
7
+ return(${A}()=>{
8
+ ${C}
9
+ })();`),isAsync:c}}function K(t,e,i){return {success:false,aborted:false,appliedCount:0,skippedCount:0,processedCount:0,totalCount:0,errors:[{directiveIndex:-1,error:e}],counters:t,...i}}function U(t,e){return K(e,`Action not found: "${t}"`)}function G(t,e,i){return K(i,`Max depth ${e} exceeded invoking "${t}"`,{aborted:true,abortedBy:"maxDepth"})}function Y(t,e){return K(e,`Action "${t}" is private (sub-action). Can only be invoked from within its parent scope.`)}function le(t){return typeof t=="object"&&t!==null&&"execute"in t}function Q(t){let e=Object.create(null),i=new Map;for(let n of Object.keys(t)){let s=t[n];le(s)?(e[n]=s.execute,i.set(n,s)):(e[n]=s,i.set(n,{execute:s}));}return {handlers:e,definitions:i}}function X(t,e){if(t==="*")return true;if(!t.includes("*"))return t===e;let i=t.replace(/[.+^${}()|[\]\\]/g,"\\$&");return new RegExp("^"+i.replace(/\*/g,".*")+"$").test(e)}function Z(t){return typeof t=="string"?{pattern:t}:t}function L(t,e,i){let n=new Map;if(!e&&!i){for(let s of t)n.set(s,{status:"available"});return n}if(e){let s=e.map(Z);for(let r of t){let c=s.some(h=>X(h.pattern,r));n.set(r,{status:c?"available":"denied"});}}else {let s=i.map(Z);for(let r of t){let c=s.find(h=>X(h.pattern,r));c?n.set(r,{status:"denied",reason:c.reason,source:c.source}):n.set(r,{status:"available"});}}return n}var ve=8,fe="type",z={maxDepth:10,maxRules:1e4,maxDirectives:1e5},V=class{_directiveExecutor;_mode;_ctx;_requestedMode;_threshold;_limits;_typeField;_handlers;_definitions;_directiveHooks;_directiveAnalysis;_isAsync;_directivePermissions;_registry=new Map;_emitter=new F;_batchDepth=0;_batchErrors=[];_batchWarnings=[];_batchActions=[];_batchRegistered=[];_registeredIds=new Set;_directiveRunner;_engineRef;constructor(e){this._requestedMode=e.mode??"auto",this._threshold=e.autoJitThreshold??ve,this._typeField=e.typeField??fe,this._limits={maxDepth:e.limits?.maxDepth??z.maxDepth,maxRules:e.limits?.maxRules??z.maxRules,maxDirectives:e.limits?.maxDirectives??z.maxDirectives};let{handlers:i,definitions:n}=Q(e.handlers);for(let s of Object.keys(e.handlers))if(S.has(s))throw new Error(`Handler type "${s}" is reserved for engine-internal directives`);if(e.allowedDirectives&&e.blockedDirectives)throw new Error("allowedDirectives and blockedDirectives are mutually exclusive. Provide one or neither.");this._handlers=i,this._definitions=n,this._directivePermissions=L(Object.keys(i),e.allowedDirectives,e.blockedDirectives),this._directiveHooks=e.directiveHooks??{},this._directiveAnalysis=core.analyzeSlots(this._directiveHooks,core.DIRECTIVE_SLOT_NAMES),this._isAsync=this._directiveAnalysis.hasAnyAsync,this._engineRef={runDirectives:(s,r)=>this._executeDirectives(s,r),runDirectivesAsync:(s,r)=>this._executeDirectivesAsync(s,r),invoke:(s,r,c)=>this._invokeInternal(s,r,c),invokeAsync:(s,r,c)=>this._invokeInternalAsync(s,r,c),evaluateRules:()=>{throw new Error("evaluateRules() not available in ActionEngine context. Use createRuleEngine().")},evaluateRulesAsync:()=>{throw new Error("evaluateRulesAsync() not available in ActionEngine context. Use createRuleEngine().")}},this._directiveRunner=(s,r)=>this._directiveExecutor(s,r,this._handlers,this._directiveHooks,this._typeField,this._engineRef,this._limits.maxDirectives),this._requestedMode==="jit"?(this._directiveExecutor=this._buildJitDirectiveExecutor(),this._mode="jit"):(this._directiveExecutor=B(this._directiveAnalysis,this._isAsync),this._mode="interpret");}register(e){let i=[],n=[],s=[],r=[];for(let h of e){if(!h.id){n.push({actionId:"",error:"Action must have an id"});continue}let x=W(h,this._handlers,this._definitions,this._typeField);if(x.length>0){for(let m of x)n.push({actionId:h.id,error:m});continue}r.push(h);}for(let h of r){let x=H(h.directives,this._typeField),m={definition:h,directives:x,compiled:null,invokeCount:0};this._requestedMode==="jit"&&(m.compiled=this._compileAction(x)),this._registry.set(h.id,m),this._registeredIds.add(h.id),i.push(h.id);}if(this._batchDepth>0){this._batchErrors.push(...n),this._batchWarnings.push(...s);for(let h of r)this._batchActions.push(h);return this._batchRegistered.push(...i),{registered:i,errors:n,warnings:s}}let c={registered:i,errors:n,warnings:s};return i.length>0&&this._emitter.emit("register",{actions:r,result:c,registered:i}),c}unregister(e){let i=this._registry.delete(e);i&&this._registeredIds.delete(e);let n=e+"/",s=[];for(let r of this._registry.keys())r.startsWith(n)&&(this._registry.delete(r),this._registeredIds.delete(r),s.push(r));return i&&this._emitter.emit("unregister",{id:e,cascaded:s}),i}invoke(e,i){if(this._isAsync)throw new Error("Cannot call invoke() with async hooks. Use invokeAsync() instead.");let n=this._requireCtx(),s=core.createRootFrame(n,this._limits);return this._invokeInternal(e,i,s)}async invokeAsync(e,i){let n=this._requireCtx(),s=core.createRootFrame(n,this._limits);return this._invokeInternalAsync(e,i,s)}setContext(e){this._ctx=e;}context(e,i){let n=this._ctx;this._ctx=e;try{return i()}finally{this._ctx=n;}}beginBatch(){this._batchDepth++,this._batchDepth===1&&(this._batchErrors=[],this._batchWarnings=[],this._batchActions=[],this._batchRegistered=[]);}endBatch(){if(this._batchDepth<=0)throw new Error("endBatch() called without matching beginBatch()");if(this._batchDepth--,this._batchDepth>0)return {registered:[],errors:[],warnings:[]};let e={registered:this._batchRegistered,errors:this._batchErrors,warnings:this._batchWarnings};return this._batchRegistered.length>0&&this._emitter.emit("register",{actions:this._batchActions,result:e,registered:this._batchRegistered}),e}on(e,i){return this._emitter.on(e,i)}get handlerDefinitions(){return this._definitions}get registeredIds(){return this._registeredIds}getActionDefinition(e){return this._registry.get(e)?.definition}get typeField(){return this._typeField}get directivePermissions(){return this._directivePermissions}get isAsync(){return this._isAsync}get compilationMode(){return this._mode}get directiveHookSlots(){return this._directiveAnalysis.filledNames}get asyncSlots(){return this._directiveAnalysis.asyncNames}compile(){if(this._requestedMode!=="interpret"){this._mode!=="jit"&&this._promote();for(let e of this._registry.values())e.compiled||(e.compiled=this._compileAction(e.directives));}}_invokeInternal(e,i,n){let s=this._prepareInvoke(e,i,n);if("success"in s)return s;let{stored:r,childFrame:c,childScope:h}=s;if(r.compiled)return r.compiled.fn(c,h,r.compiled.$);let x=this._directiveRunner(r.directives,c);return this._maybeAutoPromote(r),x}async _invokeInternalAsync(e,i,n){let s=this._prepareInvoke(e,i,n);if("success"in s)return s;let{stored:r,childFrame:c,childScope:h}=s;if(r.compiled)return r.compiled.fn(c,h,r.compiled.$);let x=this._directiveRunner(r.directives,c);return this._maybeAutoPromote(r),x}_prepareInvoke(e,i,n){let s=this._registry.get(e);if(!s)return U(e,n.counters);if(e.includes("/")&&!this._isAccessible(e,n))return Y(e,n.counters);if(n.depth>=n.limits.maxDepth)return G(e,n.limits.maxDepth,n.counters);let r=Object.create(n.scope);i&&Object.assign(r,i);let c=n.child("action:"+e,0,e).withScope(r);return {stored:s,childFrame:c,childScope:r}}_maybeAutoPromote(e){this._requestedMode==="auto"&&++e.invokeCount>=this._threshold&&(e.compiled=this._compileAction(e.directives),this._mode!=="jit"&&this._promote());}_executeDirectives(e,i){return this._directiveExecutor(e,i,this._handlers,this._directiveHooks,this._typeField,this._engineRef,this._limits.maxDirectives)}async _executeDirectivesAsync(e,i){return this._directiveExecutor(e,i,this._handlers,this._directiveHooks,this._typeField,this._engineRef,this._limits.maxDirectives)}_compileAction(e){let{fn:i}=O(e,this._directiveAnalysis,this._typeField),n={d:e,h:this._handlers,hooks:this._directiveHooks,engine:this._engineRef,runner:this._directiveRunner};return {fn:i,$:n}}_isAccessible(e,i){let s="action:"+e.slice(0,e.lastIndexOf("/"));return i.path.includes(s)}_requireCtx(){if(this._ctx===void 0)throw new Error("No context set. Call setContext(ctx) or use context(ctx, fn) before invoke.");return this._ctx}_promote(){this._directiveExecutor=this._buildJitDirectiveExecutor(),this._mode="jit";}_buildJitDirectiveExecutor(){let{fn:e}=j(this._directiveAnalysis);return e}};function _e(t){return new V(t)}exports.RESERVED_TYPES=S;exports.SimpleEmitter=F;exports.buildActionExecutor=O;exports.buildDirectiveExecutor=j;exports.createActionEngine=_e;exports.createDirectiveInterpreter=B;exports.normalizeDirectives=H;
@@ -0,0 +1,277 @@
1
+ import { Directive, ExecutionFrame, RuleEngineRef, ApplyResult, HookFn, InterceptResult, AbortDecision, DirectiveResult, ActionEngineRef, FrameLimits, SlotAnalysis } from '@statedelta-actions/core';
2
+
3
+ type DirectiveHandler<TCtx> = (directive: Directive, frame: ExecutionFrame<TCtx>, engine: RuleEngineRef<TCtx>) => ApplyResult;
4
+ type DirectiveHandlerMap<TCtx> = Record<string, DirectiveHandler<TCtx>>;
5
+ interface DirectiveHooks<TCtx> {
6
+ beforeDirective?: HookFn<[
7
+ directive: Directive,
8
+ frame: ExecutionFrame<TCtx>
9
+ ], InterceptResult<TCtx>>;
10
+ afterDirective?: HookFn<[
11
+ directive: Directive,
12
+ result: ApplyResult,
13
+ frame: ExecutionFrame<TCtx>
14
+ ], AbortDecision>;
15
+ onDirectivesComplete?: HookFn<[result: DirectiveResult], void>;
16
+ }
17
+ type DirectiveExecutorFn<TCtx> = (directives: readonly Directive[], frame: ExecutionFrame<TCtx>, handlers: DirectiveHandlerMap<TCtx>, directiveHooks: DirectiveHooks<TCtx>, typeField: string, engine: RuleEngineRef<TCtx>, maxDirectives: number) => DirectiveResult | Promise<DirectiveResult>;
18
+ type DirectiveRunnerFn<TCtx> = (directives: readonly Directive[], frame: ExecutionFrame<TCtx>) => DirectiveResult | Promise<DirectiveResult>;
19
+ interface HandlerAnalysis {
20
+ capabilities: string[];
21
+ dependencies: string[];
22
+ }
23
+ interface ValidationResult {
24
+ valid: boolean;
25
+ error?: string;
26
+ warnings?: string[];
27
+ }
28
+ interface HandlerDefinition<TCtx> {
29
+ /** Register-time: extrai capabilities e dependências. */
30
+ analyze?: (directive: Directive) => HandlerAnalysis;
31
+ /** Register-time: valida estrutura da directive. */
32
+ validate?: (directive: Directive) => ValidationResult | void;
33
+ /** JIT-time: contribui código inline per-action (Fase 2c). */
34
+ compile?: (directive: Directive, compiler: unknown) => string | void;
35
+ /** Runtime: executa a directive (obrigatório). */
36
+ execute: (directive: Directive, frame: ExecutionFrame<TCtx>, engine: ActionEngineRef<TCtx>) => ApplyResult;
37
+ }
38
+ /**
39
+ * Aceita handler V1 (função) ou V2 (objeto com fases).
40
+ * Backwards compat: função simples é tratada como { execute: fn }.
41
+ */
42
+ type HandlerInput<TCtx> = DirectiveHandler<TCtx> | HandlerDefinition<TCtx>;
43
+ type HandlerInputMap<TCtx> = Record<string, HandlerInput<TCtx>>;
44
+ interface ActionDefinition<TCtx = unknown> {
45
+ /** ID único da Action. */
46
+ id: string;
47
+ /** Directives estáticas. */
48
+ directives: readonly Directive<TCtx>[];
49
+ /**
50
+ * Tags categóricas explícitas (identidade).
51
+ * O que a action É: "controller", "service", "admin", "ui".
52
+ * Não propagam via grafo. Usadas pelo composition control.
53
+ */
54
+ tags?: readonly string[];
55
+ /** Schema de params aceitos (opcional, Fase 2d). */
56
+ params?: Record<string, unknown>;
57
+ /** Metadata opaca pro consumer (opcional). */
58
+ metadata?: Record<string, unknown>;
59
+ /**
60
+ * Tier — nível mínimo necessário pra invocar esta action.
61
+ * Propagado transitivamente via Math.max pelo analyzer.
62
+ *
63
+ * Se declarado, o analyzer valida: tier declarado >= tier inferido (max da sub-árvore).
64
+ * Se não declarado, apenas infere (sem restrição).
65
+ *
66
+ * O engine ignora este campo — é puramente declarativo pro analyzer.
67
+ * Requer tierPropagator habilitado no grafo.
68
+ */
69
+ tier?: number;
70
+ /**
71
+ * Declarações — contratos públicos (trust boundaries).
72
+ * Cada key = nome de um propagator registrado no grafo.
73
+ *
74
+ * O engine infere capabilities/propriedades via handler.analyze() + grafo.
75
+ * Declarations são o contrato que o autor assina.
76
+ * Se inferência contradiz declaração → DECLARATION_CONFLICT reportado.
77
+ * Dependentes veem o valor DECLARADO (barreira de propagação).
78
+ *
79
+ * Ex: { readonly: true, leaf: true }
80
+ */
81
+ declarations?: Record<string, unknown>;
82
+ }
83
+ /** Emitido após register() ou endBatch(). */
84
+ interface RegisterEvent<TCtx = unknown> {
85
+ readonly actions: readonly ActionDefinition<TCtx>[];
86
+ readonly result: RegisterResult;
87
+ readonly registered: readonly string[];
88
+ }
89
+ /** Emitido após unregister(). */
90
+ interface UnregisterEvent {
91
+ readonly id: string;
92
+ readonly cascaded: readonly string[];
93
+ }
94
+ /** Mapa de eventos tipados do engine. */
95
+ interface EngineEventMap<TCtx = unknown> {
96
+ register: RegisterEvent<TCtx>;
97
+ unregister: UnregisterEvent;
98
+ }
99
+ /** Union dos nomes de lifecycle events. */
100
+ type EngineEventName = keyof EngineEventMap;
101
+ interface RegisterError {
102
+ actionId: string;
103
+ error: string;
104
+ code?: string;
105
+ }
106
+ interface RegisterWarning {
107
+ actionId: string;
108
+ code: string;
109
+ message: string;
110
+ }
111
+ interface RegisterResult {
112
+ registered: readonly string[];
113
+ errors: readonly RegisterError[];
114
+ warnings: readonly RegisterWarning[];
115
+ }
116
+ /** Status de uma diretiva no contexto da instância. */
117
+ type DirectivePermissionStatus = "available" | "denied";
118
+ /**
119
+ * Informação completa de permissão de uma diretiva.
120
+ * O mapa só contém handlers que existem (available ou denied).
121
+ * `unavailable` é derivado: key referenciada mas sem handler registrado.
122
+ */
123
+ interface DirectivePermission {
124
+ readonly status: DirectivePermissionStatus;
125
+ /** Motivação do bloqueio (humana). Presente apenas em denied. */
126
+ readonly reason?: string;
127
+ /** Quem bloqueou (auditoria). Presente apenas em denied. */
128
+ readonly source?: string;
129
+ }
130
+ /** Forma estruturada de entrada de permissão na config. */
131
+ interface DirectivePermissionConfig {
132
+ readonly pattern: string;
133
+ readonly reason?: string;
134
+ readonly source?: string;
135
+ }
136
+ /**
137
+ * Entrada de permissão: string (shorthand) ou objeto com pattern + motivação.
138
+ * String pura é equivalente a `{ pattern: string }`.
139
+ */
140
+ type DirectivePermissionEntry = string | DirectivePermissionConfig;
141
+ interface IActionEngineConfig<TCtx> {
142
+ /** Handlers com fases (V2) ou funções simples (V1 compat). */
143
+ handlers: HandlerInputMap<TCtx>;
144
+ /** Campo de tipo pra dispatch (default: "type"). */
145
+ typeField?: string;
146
+ /** Hooks de directive. */
147
+ directiveHooks?: DirectiveHooks<TCtx>;
148
+ /** Limites de execução. */
149
+ limits?: Partial<FrameLimits>;
150
+ /** Modo de compilação. */
151
+ mode?: "interpret" | "jit" | "auto";
152
+ /** Threshold pra auto-promote (default: 8). */
153
+ autoJitThreshold?: number;
154
+ /**
155
+ * Whitelist de diretivas permitidas (pattern matching com wildcard `*`).
156
+ * Mutuamente exclusivo com `blockedDirectives`.
157
+ * Se nenhum fornecido: tudo permitido (default).
158
+ * Diretivas estáticas (const/let/return/throw) são sempre permitidas.
159
+ */
160
+ allowedDirectives?: readonly DirectivePermissionEntry[];
161
+ /**
162
+ * Blacklist de diretivas bloqueadas (pattern matching com wildcard `*`).
163
+ * Mutuamente exclusivo com `allowedDirectives`.
164
+ * Se nenhum fornecido: tudo permitido (default).
165
+ * Diretivas estáticas (const/let/return/throw) são sempre permitidas.
166
+ */
167
+ blockedDirectives?: readonly DirectivePermissionEntry[];
168
+ }
169
+ interface IActionEngine<TCtx> {
170
+ /** Registra actions. Valida, analisa, indexa no grafo, compila. */
171
+ register(actions: readonly ActionDefinition<TCtx>[]): RegisterResult;
172
+ /** Remove action do registry. Cascade: remove children (path-based). */
173
+ unregister(id: string): boolean;
174
+ /** Inicia batch. Registros acumulados, análise adiada pro endBatch. */
175
+ beginBatch(): void;
176
+ /** Finaliza batch. Executa análise, typecheck, indexação. */
177
+ endBatch(): RegisterResult;
178
+ /** Invoca action por ID. Lookup O(1). */
179
+ invoke(id: string, params?: Record<string, unknown>): DirectiveResult;
180
+ /** Invoca action async. */
181
+ invokeAsync(id: string, params?: Record<string, unknown>): Promise<DirectiveResult>;
182
+ /** Seta ctx global. */
183
+ setContext(ctx: TCtx): void;
184
+ /** Override temporário de ctx dentro do callback. */
185
+ context<R>(ctx: TCtx, fn: () => R): R;
186
+ /**
187
+ * Subscribe em lifecycle events do engine.
188
+ * Retorna função de unsubscribe idempotente.
189
+ */
190
+ on<K extends keyof EngineEventMap<TCtx> & string>(event: K, listener: (payload: EngineEventMap<TCtx>[K]) => void): () => void;
191
+ /** Handler definitions registradas (V2). Leitura por camadas externas. */
192
+ readonly handlerDefinitions: ReadonlyMap<string, HandlerDefinition<TCtx>>;
193
+ /** IDs de todas as actions no registry. */
194
+ readonly registeredIds: ReadonlySet<string>;
195
+ /** Lê uma action definition pelo ID. undefined se não registrada. */
196
+ getActionDefinition(id: string): ActionDefinition<TCtx> | undefined;
197
+ /** Campo de tipo pra dispatch de diretivas (default: "type"). */
198
+ readonly typeField: string;
199
+ /**
200
+ * Mapa de permissões de diretivas, computado no boot (imutável).
201
+ * Contém apenas handlers registrados (available ou denied).
202
+ * `unavailable` é derivado: key não presente = handler inexistente.
203
+ */
204
+ readonly directivePermissions: ReadonlyMap<string, DirectivePermission>;
205
+ readonly isAsync: boolean;
206
+ readonly compilationMode: "interpret" | "jit";
207
+ compile(): void;
208
+ readonly directiveHookSlots: ReadonlySet<string>;
209
+ readonly asyncSlots: ReadonlySet<string>;
210
+ }
211
+
212
+ /**
213
+ * Type-safe event emitter. Zero deps. Browser-compatible.
214
+ *
215
+ * Usage:
216
+ * ```ts
217
+ * type Events = {
218
+ * register: { ids: string[] };
219
+ * disable: { id: string };
220
+ * };
221
+ * const emitter = new SimpleEmitter<Events>();
222
+ * const unsub = emitter.on("register", (e) => console.log(e.ids));
223
+ * emitter.emit("register", { ids: ["a"] });
224
+ * unsub();
225
+ * ```
226
+ */
227
+ type Listener<T> = (payload: T) => void;
228
+ declare class SimpleEmitter<TEvents = Record<string, unknown>> {
229
+ private readonly _listeners;
230
+ /**
231
+ * Subscribe to an event. Returns idempotent unsubscribe function.
232
+ * Same listener on same event is deduplicated (Set semantics).
233
+ */
234
+ on<K extends keyof TEvents & string>(event: K, listener: Listener<TEvents[K]>): () => void;
235
+ /**
236
+ * Subscribe for a single emission, then auto-unsubscribe.
237
+ * Returns unsubscribe (can cancel before first emission).
238
+ */
239
+ once<K extends keyof TEvents & string>(event: K, listener: Listener<TEvents[K]>): () => void;
240
+ /**
241
+ * Emit event to all listeners.
242
+ * - Iterates a snapshot — safe if listeners add/remove during emit.
243
+ * - Listener errors are isolated: caught, logged, don't block others.
244
+ */
245
+ emit<K extends keyof TEvents & string>(event: K, payload: TEvents[K]): void;
246
+ /** Number of listeners for a specific event (0 if none). */
247
+ listenerCount<K extends keyof TEvents & string>(event: K): number;
248
+ /** True if at least one listener exists for the event. */
249
+ hasListeners<K extends keyof TEvents & string>(event: K): boolean;
250
+ /** Remove all listeners for a specific event. */
251
+ off<K extends keyof TEvents & string>(event: K): void;
252
+ /** Remove ALL listeners from ALL events. */
253
+ removeAllListeners(): void;
254
+ }
255
+
256
+ declare const RESERVED_TYPES: Set<string>;
257
+ declare function normalizeDirectives<TCtx>(directives: readonly Directive<TCtx>[], typeField: string): Directive<TCtx>[];
258
+
259
+ declare function createDirectiveInterpreter<TCtx>(analysis: SlotAnalysis, isAsync: boolean): DirectiveExecutorFn<TCtx>;
260
+
261
+ declare function createActionEngine<TCtx>(config: IActionEngineConfig<TCtx>): IActionEngine<TCtx>;
262
+
263
+ type RuntimeDirectiveExecutorFn = (directives: readonly unknown[], frame: unknown, handlers: unknown, directiveHooks: unknown, typeField: string, engine: unknown, maxDirectives: number) => unknown;
264
+ interface GeneratedDirectiveExecutor {
265
+ fn: RuntimeDirectiveExecutorFn;
266
+ isAsync: boolean;
267
+ }
268
+ declare function buildDirectiveExecutor(analysis: SlotAnalysis): GeneratedDirectiveExecutor;
269
+
270
+ type RuntimeActionExecutorFn = (frame: unknown, scope: unknown, $: unknown) => unknown;
271
+ interface GeneratedActionExecutor {
272
+ fn: RuntimeActionExecutorFn;
273
+ isAsync: boolean;
274
+ }
275
+ declare function buildActionExecutor(directives: readonly Directive[], analysis: SlotAnalysis, typeField: string): GeneratedActionExecutor;
276
+
277
+ export { type ActionDefinition, type DirectiveExecutorFn, type DirectiveHandler, type DirectiveHandlerMap, type DirectiveHooks, type DirectivePermission, type DirectivePermissionConfig, type DirectivePermissionEntry, type DirectivePermissionStatus, type DirectiveRunnerFn, type EngineEventMap, type EngineEventName, type GeneratedActionExecutor, type GeneratedDirectiveExecutor, type HandlerAnalysis, type HandlerDefinition, type HandlerInput, type HandlerInputMap, type IActionEngine, type IActionEngineConfig, type Listener, RESERVED_TYPES, type RegisterError, type RegisterEvent, type RegisterResult, type RegisterWarning, SimpleEmitter, type UnregisterEvent, type ValidationResult, buildActionExecutor, buildDirectiveExecutor, createActionEngine, createDirectiveInterpreter, normalizeDirectives };
@@ -0,0 +1,277 @@
1
+ import { Directive, ExecutionFrame, RuleEngineRef, ApplyResult, HookFn, InterceptResult, AbortDecision, DirectiveResult, ActionEngineRef, FrameLimits, SlotAnalysis } from '@statedelta-actions/core';
2
+
3
+ type DirectiveHandler<TCtx> = (directive: Directive, frame: ExecutionFrame<TCtx>, engine: RuleEngineRef<TCtx>) => ApplyResult;
4
+ type DirectiveHandlerMap<TCtx> = Record<string, DirectiveHandler<TCtx>>;
5
+ interface DirectiveHooks<TCtx> {
6
+ beforeDirective?: HookFn<[
7
+ directive: Directive,
8
+ frame: ExecutionFrame<TCtx>
9
+ ], InterceptResult<TCtx>>;
10
+ afterDirective?: HookFn<[
11
+ directive: Directive,
12
+ result: ApplyResult,
13
+ frame: ExecutionFrame<TCtx>
14
+ ], AbortDecision>;
15
+ onDirectivesComplete?: HookFn<[result: DirectiveResult], void>;
16
+ }
17
+ type DirectiveExecutorFn<TCtx> = (directives: readonly Directive[], frame: ExecutionFrame<TCtx>, handlers: DirectiveHandlerMap<TCtx>, directiveHooks: DirectiveHooks<TCtx>, typeField: string, engine: RuleEngineRef<TCtx>, maxDirectives: number) => DirectiveResult | Promise<DirectiveResult>;
18
+ type DirectiveRunnerFn<TCtx> = (directives: readonly Directive[], frame: ExecutionFrame<TCtx>) => DirectiveResult | Promise<DirectiveResult>;
19
+ interface HandlerAnalysis {
20
+ capabilities: string[];
21
+ dependencies: string[];
22
+ }
23
+ interface ValidationResult {
24
+ valid: boolean;
25
+ error?: string;
26
+ warnings?: string[];
27
+ }
28
+ interface HandlerDefinition<TCtx> {
29
+ /** Register-time: extrai capabilities e dependências. */
30
+ analyze?: (directive: Directive) => HandlerAnalysis;
31
+ /** Register-time: valida estrutura da directive. */
32
+ validate?: (directive: Directive) => ValidationResult | void;
33
+ /** JIT-time: contribui código inline per-action (Fase 2c). */
34
+ compile?: (directive: Directive, compiler: unknown) => string | void;
35
+ /** Runtime: executa a directive (obrigatório). */
36
+ execute: (directive: Directive, frame: ExecutionFrame<TCtx>, engine: ActionEngineRef<TCtx>) => ApplyResult;
37
+ }
38
+ /**
39
+ * Aceita handler V1 (função) ou V2 (objeto com fases).
40
+ * Backwards compat: função simples é tratada como { execute: fn }.
41
+ */
42
+ type HandlerInput<TCtx> = DirectiveHandler<TCtx> | HandlerDefinition<TCtx>;
43
+ type HandlerInputMap<TCtx> = Record<string, HandlerInput<TCtx>>;
44
+ interface ActionDefinition<TCtx = unknown> {
45
+ /** ID único da Action. */
46
+ id: string;
47
+ /** Directives estáticas. */
48
+ directives: readonly Directive<TCtx>[];
49
+ /**
50
+ * Tags categóricas explícitas (identidade).
51
+ * O que a action É: "controller", "service", "admin", "ui".
52
+ * Não propagam via grafo. Usadas pelo composition control.
53
+ */
54
+ tags?: readonly string[];
55
+ /** Schema de params aceitos (opcional, Fase 2d). */
56
+ params?: Record<string, unknown>;
57
+ /** Metadata opaca pro consumer (opcional). */
58
+ metadata?: Record<string, unknown>;
59
+ /**
60
+ * Tier — nível mínimo necessário pra invocar esta action.
61
+ * Propagado transitivamente via Math.max pelo analyzer.
62
+ *
63
+ * Se declarado, o analyzer valida: tier declarado >= tier inferido (max da sub-árvore).
64
+ * Se não declarado, apenas infere (sem restrição).
65
+ *
66
+ * O engine ignora este campo — é puramente declarativo pro analyzer.
67
+ * Requer tierPropagator habilitado no grafo.
68
+ */
69
+ tier?: number;
70
+ /**
71
+ * Declarações — contratos públicos (trust boundaries).
72
+ * Cada key = nome de um propagator registrado no grafo.
73
+ *
74
+ * O engine infere capabilities/propriedades via handler.analyze() + grafo.
75
+ * Declarations são o contrato que o autor assina.
76
+ * Se inferência contradiz declaração → DECLARATION_CONFLICT reportado.
77
+ * Dependentes veem o valor DECLARADO (barreira de propagação).
78
+ *
79
+ * Ex: { readonly: true, leaf: true }
80
+ */
81
+ declarations?: Record<string, unknown>;
82
+ }
83
+ /** Emitido após register() ou endBatch(). */
84
+ interface RegisterEvent<TCtx = unknown> {
85
+ readonly actions: readonly ActionDefinition<TCtx>[];
86
+ readonly result: RegisterResult;
87
+ readonly registered: readonly string[];
88
+ }
89
+ /** Emitido após unregister(). */
90
+ interface UnregisterEvent {
91
+ readonly id: string;
92
+ readonly cascaded: readonly string[];
93
+ }
94
+ /** Mapa de eventos tipados do engine. */
95
+ interface EngineEventMap<TCtx = unknown> {
96
+ register: RegisterEvent<TCtx>;
97
+ unregister: UnregisterEvent;
98
+ }
99
+ /** Union dos nomes de lifecycle events. */
100
+ type EngineEventName = keyof EngineEventMap;
101
+ interface RegisterError {
102
+ actionId: string;
103
+ error: string;
104
+ code?: string;
105
+ }
106
+ interface RegisterWarning {
107
+ actionId: string;
108
+ code: string;
109
+ message: string;
110
+ }
111
+ interface RegisterResult {
112
+ registered: readonly string[];
113
+ errors: readonly RegisterError[];
114
+ warnings: readonly RegisterWarning[];
115
+ }
116
+ /** Status de uma diretiva no contexto da instância. */
117
+ type DirectivePermissionStatus = "available" | "denied";
118
+ /**
119
+ * Informação completa de permissão de uma diretiva.
120
+ * O mapa só contém handlers que existem (available ou denied).
121
+ * `unavailable` é derivado: key referenciada mas sem handler registrado.
122
+ */
123
+ interface DirectivePermission {
124
+ readonly status: DirectivePermissionStatus;
125
+ /** Motivação do bloqueio (humana). Presente apenas em denied. */
126
+ readonly reason?: string;
127
+ /** Quem bloqueou (auditoria). Presente apenas em denied. */
128
+ readonly source?: string;
129
+ }
130
+ /** Forma estruturada de entrada de permissão na config. */
131
+ interface DirectivePermissionConfig {
132
+ readonly pattern: string;
133
+ readonly reason?: string;
134
+ readonly source?: string;
135
+ }
136
+ /**
137
+ * Entrada de permissão: string (shorthand) ou objeto com pattern + motivação.
138
+ * String pura é equivalente a `{ pattern: string }`.
139
+ */
140
+ type DirectivePermissionEntry = string | DirectivePermissionConfig;
141
+ interface IActionEngineConfig<TCtx> {
142
+ /** Handlers com fases (V2) ou funções simples (V1 compat). */
143
+ handlers: HandlerInputMap<TCtx>;
144
+ /** Campo de tipo pra dispatch (default: "type"). */
145
+ typeField?: string;
146
+ /** Hooks de directive. */
147
+ directiveHooks?: DirectiveHooks<TCtx>;
148
+ /** Limites de execução. */
149
+ limits?: Partial<FrameLimits>;
150
+ /** Modo de compilação. */
151
+ mode?: "interpret" | "jit" | "auto";
152
+ /** Threshold pra auto-promote (default: 8). */
153
+ autoJitThreshold?: number;
154
+ /**
155
+ * Whitelist de diretivas permitidas (pattern matching com wildcard `*`).
156
+ * Mutuamente exclusivo com `blockedDirectives`.
157
+ * Se nenhum fornecido: tudo permitido (default).
158
+ * Diretivas estáticas (const/let/return/throw) são sempre permitidas.
159
+ */
160
+ allowedDirectives?: readonly DirectivePermissionEntry[];
161
+ /**
162
+ * Blacklist de diretivas bloqueadas (pattern matching com wildcard `*`).
163
+ * Mutuamente exclusivo com `allowedDirectives`.
164
+ * Se nenhum fornecido: tudo permitido (default).
165
+ * Diretivas estáticas (const/let/return/throw) são sempre permitidas.
166
+ */
167
+ blockedDirectives?: readonly DirectivePermissionEntry[];
168
+ }
169
+ interface IActionEngine<TCtx> {
170
+ /** Registra actions. Valida, analisa, indexa no grafo, compila. */
171
+ register(actions: readonly ActionDefinition<TCtx>[]): RegisterResult;
172
+ /** Remove action do registry. Cascade: remove children (path-based). */
173
+ unregister(id: string): boolean;
174
+ /** Inicia batch. Registros acumulados, análise adiada pro endBatch. */
175
+ beginBatch(): void;
176
+ /** Finaliza batch. Executa análise, typecheck, indexação. */
177
+ endBatch(): RegisterResult;
178
+ /** Invoca action por ID. Lookup O(1). */
179
+ invoke(id: string, params?: Record<string, unknown>): DirectiveResult;
180
+ /** Invoca action async. */
181
+ invokeAsync(id: string, params?: Record<string, unknown>): Promise<DirectiveResult>;
182
+ /** Seta ctx global. */
183
+ setContext(ctx: TCtx): void;
184
+ /** Override temporário de ctx dentro do callback. */
185
+ context<R>(ctx: TCtx, fn: () => R): R;
186
+ /**
187
+ * Subscribe em lifecycle events do engine.
188
+ * Retorna função de unsubscribe idempotente.
189
+ */
190
+ on<K extends keyof EngineEventMap<TCtx> & string>(event: K, listener: (payload: EngineEventMap<TCtx>[K]) => void): () => void;
191
+ /** Handler definitions registradas (V2). Leitura por camadas externas. */
192
+ readonly handlerDefinitions: ReadonlyMap<string, HandlerDefinition<TCtx>>;
193
+ /** IDs de todas as actions no registry. */
194
+ readonly registeredIds: ReadonlySet<string>;
195
+ /** Lê uma action definition pelo ID. undefined se não registrada. */
196
+ getActionDefinition(id: string): ActionDefinition<TCtx> | undefined;
197
+ /** Campo de tipo pra dispatch de diretivas (default: "type"). */
198
+ readonly typeField: string;
199
+ /**
200
+ * Mapa de permissões de diretivas, computado no boot (imutável).
201
+ * Contém apenas handlers registrados (available ou denied).
202
+ * `unavailable` é derivado: key não presente = handler inexistente.
203
+ */
204
+ readonly directivePermissions: ReadonlyMap<string, DirectivePermission>;
205
+ readonly isAsync: boolean;
206
+ readonly compilationMode: "interpret" | "jit";
207
+ compile(): void;
208
+ readonly directiveHookSlots: ReadonlySet<string>;
209
+ readonly asyncSlots: ReadonlySet<string>;
210
+ }
211
+
212
+ /**
213
+ * Type-safe event emitter. Zero deps. Browser-compatible.
214
+ *
215
+ * Usage:
216
+ * ```ts
217
+ * type Events = {
218
+ * register: { ids: string[] };
219
+ * disable: { id: string };
220
+ * };
221
+ * const emitter = new SimpleEmitter<Events>();
222
+ * const unsub = emitter.on("register", (e) => console.log(e.ids));
223
+ * emitter.emit("register", { ids: ["a"] });
224
+ * unsub();
225
+ * ```
226
+ */
227
+ type Listener<T> = (payload: T) => void;
228
+ declare class SimpleEmitter<TEvents = Record<string, unknown>> {
229
+ private readonly _listeners;
230
+ /**
231
+ * Subscribe to an event. Returns idempotent unsubscribe function.
232
+ * Same listener on same event is deduplicated (Set semantics).
233
+ */
234
+ on<K extends keyof TEvents & string>(event: K, listener: Listener<TEvents[K]>): () => void;
235
+ /**
236
+ * Subscribe for a single emission, then auto-unsubscribe.
237
+ * Returns unsubscribe (can cancel before first emission).
238
+ */
239
+ once<K extends keyof TEvents & string>(event: K, listener: Listener<TEvents[K]>): () => void;
240
+ /**
241
+ * Emit event to all listeners.
242
+ * - Iterates a snapshot — safe if listeners add/remove during emit.
243
+ * - Listener errors are isolated: caught, logged, don't block others.
244
+ */
245
+ emit<K extends keyof TEvents & string>(event: K, payload: TEvents[K]): void;
246
+ /** Number of listeners for a specific event (0 if none). */
247
+ listenerCount<K extends keyof TEvents & string>(event: K): number;
248
+ /** True if at least one listener exists for the event. */
249
+ hasListeners<K extends keyof TEvents & string>(event: K): boolean;
250
+ /** Remove all listeners for a specific event. */
251
+ off<K extends keyof TEvents & string>(event: K): void;
252
+ /** Remove ALL listeners from ALL events. */
253
+ removeAllListeners(): void;
254
+ }
255
+
256
+ declare const RESERVED_TYPES: Set<string>;
257
+ declare function normalizeDirectives<TCtx>(directives: readonly Directive<TCtx>[], typeField: string): Directive<TCtx>[];
258
+
259
+ declare function createDirectiveInterpreter<TCtx>(analysis: SlotAnalysis, isAsync: boolean): DirectiveExecutorFn<TCtx>;
260
+
261
+ declare function createActionEngine<TCtx>(config: IActionEngineConfig<TCtx>): IActionEngine<TCtx>;
262
+
263
+ type RuntimeDirectiveExecutorFn = (directives: readonly unknown[], frame: unknown, handlers: unknown, directiveHooks: unknown, typeField: string, engine: unknown, maxDirectives: number) => unknown;
264
+ interface GeneratedDirectiveExecutor {
265
+ fn: RuntimeDirectiveExecutorFn;
266
+ isAsync: boolean;
267
+ }
268
+ declare function buildDirectiveExecutor(analysis: SlotAnalysis): GeneratedDirectiveExecutor;
269
+
270
+ type RuntimeActionExecutorFn = (frame: unknown, scope: unknown, $: unknown) => unknown;
271
+ interface GeneratedActionExecutor {
272
+ fn: RuntimeActionExecutorFn;
273
+ isAsync: boolean;
274
+ }
275
+ declare function buildActionExecutor(directives: readonly Directive[], analysis: SlotAnalysis, typeField: string): GeneratedActionExecutor;
276
+
277
+ export { type ActionDefinition, type DirectiveExecutorFn, type DirectiveHandler, type DirectiveHandlerMap, type DirectiveHooks, type DirectivePermission, type DirectivePermissionConfig, type DirectivePermissionEntry, type DirectivePermissionStatus, type DirectiveRunnerFn, type EngineEventMap, type EngineEventName, type GeneratedActionExecutor, type GeneratedDirectiveExecutor, type HandlerAnalysis, type HandlerDefinition, type HandlerInput, type HandlerInputMap, type IActionEngine, type IActionEngineConfig, type Listener, RESERVED_TYPES, type RegisterError, type RegisterEvent, type RegisterResult, type RegisterWarning, SimpleEmitter, type UnregisterEvent, type ValidationResult, buildActionExecutor, buildDirectiveExecutor, createActionEngine, createDirectiveInterpreter, normalizeDirectives };
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ import {processIntercept,Intercept,analyzeSlots,DIRECTIVE_SLOT_NAMES,createRootFrame}from'@statedelta-actions/core';var F=class{_listeners=new Map;on(e,i){let n=this._listeners.get(e);n||(n=new Set,this._listeners.set(e,n)),n.add(i);let s=false;return ()=>{s||(s=true,n.delete(i),n.size===0&&this._listeners.delete(e));}}once(e,i){let n=this.on(e,s=>{n(),i(s);});return n}emit(e,i){let n=this._listeners.get(e);if(!n||n.size===0)return;let s=[...n];for(let r=0;r<s.length;r++)try{s[r](i);}catch(c){console.error(`[SimpleEmitter] Listener error on "${e}":`,c);}}listenerCount(e){return this._listeners.get(e)?.size??0}hasListeners(e){let i=this._listeners.get(e);return i!==void 0&&i.size>0}off(e){this._listeners.delete(e);}removeAllListeners(){this._listeners.clear();}};var S=new Set(["const","let","return","throw"]);function W(t,e,i,n){let s=[];for(let r=0;r<t.directives.length;r++){let c=t.directives[r];if("const"in c||"let"in c||"return"in c||"throw"in c)continue;let h=c[n];if(!h){s.push(`directive[${r}]: missing type field "${n}"`);continue}if(!e[h]){s.push(`directive[${r}]: no handler for type "${h}"`);continue}let x=i.get(h);if(x?.validate)try{let D=x.validate(c);D&&!D.valid&&s.push(`directive[${r}]: ${D.error??"validation failed"}`);}catch(D){s.push(`directive[${r}]: validate threw: ${D}`);}let m=c.catch;if(m&&Array.isArray(m))for(let D=0;D<m.length;D++){let R=m[D];if("const"in R||"let"in R||"return"in R||"throw"in R)continue;let v=R[n];v&&!e[v]&&s.push(`directive[${r}].catch[${D}]: no handler for type "${v}"`);}}return s}function H(t,e){let i=t.length,n=new Array(i);for(let s=0;s<i;s++){let r=t[s];if("const"in r)n[s]=q(r,"const");else if("let"in r)n[s]=q(r,"let");else if("return"in r)n[s]=te(r);else if("throw"in r)n[s]=re(r);else {let c=r.catch;Array.isArray(c)&&c.length>0?n[s]={...r,catch:H(c)}:n[s]=r;}}return n}function q(t,e){let{[e]:i,...n}=t;return {...n,type:e,name:i}}function te(t){let{return:e,...i}=t;return {...i,type:"return",value:e}}function re(t){let{throw:e,...i}=t;return {...i,type:"throw",message:e}}function M(t,e,i,n,s,r,c){return {success:false,aborted:true,abortedBy:t,appliedCount:e,skippedCount:i,errors:n,processedCount:s,totalCount:r,counters:c}}function ie(t){let e=t.filledNames.has("beforeDirective"),i=t.filledNames.has("afterDirective"),n=t.filledNames.has("onDirectivesComplete");return function(r,c,h,x,m,D,R){let v=Math.min(r.length,R),l=[],f=0,_=0,{counters:u,scope:C}=c,A=c.ctx;for(let a=0;a<v;a++){let p=r[a],$=p[m];if($==="const"||$==="let"){let o=p.name;if(typeof p.resolve=="function")try{C[o]=p.resolve(A,C).value;}catch(d){l.push({directiveIndex:a,error:`Binding resolve: ${d}`}),u.errors++;}else C[o]=p.value;continue}if($==="return"){let o=a+1;if(typeof p.resolve=="function")try{let d=p.resolve(A,C),b="value"in d?d.value:"return"in d?d.return:p.value;return {success:!0,aborted:!1,appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:b}}catch(d){l.push({directiveIndex:a,error:`Control resolve: ${d}`}),u.errors++;}else return {success:true,aborted:false,appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:p.value};continue}if($==="throw"){let o=a+1;if(typeof p.resolve=="function")try{let d=p.resolve(A,C),b="message"in d?d.message:"throw"in d?d.throw:p.message;return {success:!1,aborted:!0,abortedBy:"throw",appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:b}}catch(d){l.push({directiveIndex:a,error:`Control resolve: ${d}`}),u.errors++;}else return {success:false,aborted:true,abortedBy:"throw",appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:p.message};continue}let y=p,E=c;if(e)try{let o=processIntercept(x.beforeDirective(y,c),"beforeDirective");if(o.action===Intercept.SKIP){_++,u.directivesSkipped++;continue}if(o.action===Intercept.ABORT)return M(o.abortReason,f,_,l,a,v,u);o.ctx!==void 0&&(E=c.withCtx(o.ctx)),o.directive!==void 0&&(y=o.directive);}catch(o){l.push({directiveIndex:a,error:`Hook beforeDirective: ${o}`}),u.errors++;}if(typeof y.resolve=="function")try{let o=y.resolve(E.ctx,E.scope);y={...y,...o};}catch(o){l.push({directiveIndex:a,error:`Directive resolve: ${o}`}),u.errors++;continue}let w=y[m],I=w?h[w]:void 0;if(!I){l.push({directiveIndex:a,error:`No handler for directive type: ${w??"undefined"}`}),u.errors++;continue}let g;try{g=I(y,E,D);}catch(o){g={ok:false,error:String(o)};}let T=a+1;if(g.ok){if(f++,u.directivesApplied++,typeof y.as=="string"&&(C[y.as]=g.data),g.halt)return {success:true,aborted:true,abortedBy:"halt",appliedCount:f,skippedCount:_,errors:l,processedCount:T,totalCount:v,counters:u,data:g.data}}else {if(g.halt)return {success:false,aborted:true,abortedBy:"halt",appliedCount:f,skippedCount:_,errors:l,processedCount:T,totalCount:v,counters:u,data:g.data};let o=y.catch;if(Array.isArray(o)&&o.length>0){C.$exception=g.error??"handler failed";let d=D.runDirectives(o,E);f+=d.appliedCount;for(let b=0;b<d.errors.length;b++)l.push(d.errors[b]);if(d.aborted)return {success:d.success,aborted:true,abortedBy:d.abortedBy,appliedCount:f,skippedCount:_,errors:l,processedCount:T,totalCount:v,counters:u,data:d.data}}else l.push({directiveIndex:a,error:g.error??"handler failed"}),u.errors++;}if(i)try{if(x.afterDirective(y,g,E)==="abort")return M("afterDirective",f,_,l,T,v,u)}catch(o){l.push({directiveIndex:a,error:`Hook afterDirective: ${o}`}),u.errors++;}}let k={success:true,aborted:false,appliedCount:f,skippedCount:_,errors:l,processedCount:v,totalCount:v,counters:u};if(n)try{x.onDirectivesComplete(k);}catch{}return k}}function ne(t){let e=t.filledNames.has("beforeDirective"),i=t.filledNames.has("afterDirective"),n=t.filledNames.has("onDirectivesComplete");return async function(r,c,h,x,m,D,R){let v=Math.min(r.length,R),l=[],f=0,_=0,{counters:u,scope:C}=c,A=c.ctx;for(let a=0;a<v;a++){let p=r[a],$=p[m];if($==="const"||$==="let"){let o=p.name;if(typeof p.resolve=="function")try{C[o]=p.resolve(A,C).value;}catch(d){l.push({directiveIndex:a,error:`Binding resolve: ${d}`}),u.errors++;}else C[o]=p.value;continue}if($==="return"){let o=a+1;if(typeof p.resolve=="function")try{let d=p.resolve(A,C),b="value"in d?d.value:"return"in d?d.return:p.value;return {success:!0,aborted:!1,appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:b}}catch(d){l.push({directiveIndex:a,error:`Control resolve: ${d}`}),u.errors++;}else return {success:true,aborted:false,appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:p.value};continue}if($==="throw"){let o=a+1;if(typeof p.resolve=="function")try{let d=p.resolve(A,C),b="message"in d?d.message:"throw"in d?d.throw:p.message;return {success:!1,aborted:!0,abortedBy:"throw",appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:b}}catch(d){l.push({directiveIndex:a,error:`Control resolve: ${d}`}),u.errors++;}else return {success:false,aborted:true,abortedBy:"throw",appliedCount:f,skippedCount:_,errors:l,processedCount:o,totalCount:v,counters:u,data:p.message};continue}let y=p,E=c;if(e)try{let o=processIntercept(await x.beforeDirective(y,c),"beforeDirective");if(o.action===Intercept.SKIP){_++,u.directivesSkipped++;continue}if(o.action===Intercept.ABORT)return M(o.abortReason,f,_,l,a,v,u);o.ctx!==void 0&&(E=c.withCtx(o.ctx)),o.directive!==void 0&&(y=o.directive);}catch(o){l.push({directiveIndex:a,error:`Hook beforeDirective: ${o}`}),u.errors++;}if(typeof y.resolve=="function")try{let o=y.resolve(E.ctx,E.scope);y={...y,...o};}catch(o){l.push({directiveIndex:a,error:`Directive resolve: ${o}`}),u.errors++;continue}let w=y[m],I=w?h[w]:void 0;if(!I){l.push({directiveIndex:a,error:`No handler for directive type: ${w??"undefined"}`}),u.errors++;continue}let g;try{g=I(y,E,D);}catch(o){g={ok:false,error:String(o)};}let T=a+1;if(g.ok){if(f++,u.directivesApplied++,typeof y.as=="string"&&(C[y.as]=g.data),g.halt)return {success:true,aborted:true,abortedBy:"halt",appliedCount:f,skippedCount:_,errors:l,processedCount:T,totalCount:v,counters:u,data:g.data}}else {if(g.halt)return {success:false,aborted:true,abortedBy:"halt",appliedCount:f,skippedCount:_,errors:l,processedCount:T,totalCount:v,counters:u,data:g.data};let o=y.catch;if(Array.isArray(o)&&o.length>0){C.$exception=g.error??"handler failed";let d=await D.runDirectivesAsync(o,E);f+=d.appliedCount;for(let b=0;b<d.errors.length;b++)l.push(d.errors[b]);if(d.aborted)return {success:d.success,aborted:true,abortedBy:d.abortedBy,appliedCount:f,skippedCount:_,errors:l,processedCount:T,totalCount:v,counters:u,data:d.data}}else l.push({directiveIndex:a,error:g.error??"handler failed"}),u.errors++;}if(i)try{if(await x.afterDirective(y,g,E)==="abort")return M("afterDirective",f,_,l,T,v,u)}catch(o){l.push({directiveIndex:a,error:`Hook afterDirective: ${o}`}),u.errors++;}}let k={success:true,aborted:false,appliedCount:f,skippedCount:_,errors:l,processedCount:v,totalCount:v,counters:u};if(n)try{await x.onDirectivesComplete(k);}catch{}return k}}function B(t,e){return e?ne(t):ie(t)}function j(t){let{filledNames:e,hasAnyAsync:i}=t,n=m=>e.has(m),s=m=>t.asyncNames.has(m)?"await ":"",r=[];for(let m of e)r.push(`const ${m} = directiveHooks.${m};`);r.push("const len = Math.min(directives.length, maxDirectives);"),r.push("const errors = []; let appliedCount = 0; let skippedCount = 0;"),r.push("const counters = frame.counters;"),r.push("for (let i = 0; i < len; i++) {"),r.push(" let directive = directives[i];"),n("beforeDirective")?(r.push(" let _df = frame;"),r.push(" try {"),r.push(` const _bd = ${s("beforeDirective")}beforeDirective(directive, frame);`),r.push(' if (_bd === "skip") { skippedCount++; counters.directivesSkipped++; continue; }'),r.push(' if (_bd === "abort") return { success: false, aborted: true, abortedBy: "beforeDirective", appliedCount, skippedCount, errors, processedCount: i, totalCount: len, counters };'),r.push(' if (typeof _bd === "object" && _bd !== null) {'),r.push(' if ("abort" in _bd) return { success: false, aborted: true, abortedBy: _bd.abort, appliedCount, skippedCount, errors, processedCount: i, totalCount: len, counters };'),r.push(' if ("ctx" in _bd) _df = frame.withCtx(_bd.ctx);'),r.push(' if ("directive" in _bd) directive = _bd.directive;'),r.push(" }"),r.push(' } catch (_e) { errors.push({ directiveIndex: i, error: "Hook beforeDirective: " + _e }); counters.errors++; }')):r.push(" const _df = frame;"),r.push(' if (typeof directive.resolve === "function") {'),r.push(" try { const _r = directive.resolve(_df.ctx); directive = Object.assign({}, directive, _r); }"),r.push(' catch (_e) { errors.push({ directiveIndex: i, error: "Directive resolve: " + _e }); counters.errors++; continue; }'),r.push(" }"),r.push(" const _type = directive[typeField];"),r.push(" const _handler = _type ? handlers[_type] : undefined;"),r.push(' if (!_handler) { errors.push({ directiveIndex: i, error: "No handler for directive type: " + (_type || "undefined") }); counters.errors++; continue; }'),r.push(" let _result;"),r.push(" try { _result = _handler(directive, _df, engine); } catch (_e) { errors.push({ directiveIndex: i, error: String(_e) }); counters.errors++; continue; }"),r.push(" if (_result.ok) { appliedCount++; counters.directivesApplied++; }"),r.push(' else { errors.push({ directiveIndex: i, error: _result.error || "handler failed" }); counters.errors++; }'),n("afterDirective")&&(r.push(" try {"),r.push(` const _ad = ${s("afterDirective")}afterDirective(directive, _result, _df);`),r.push(' if (_ad === "abort") return { success: false, aborted: true, abortedBy: "afterDirective", appliedCount, skippedCount, errors, processedCount: i + 1, totalCount: len, counters };'),r.push(' } catch (_e) { errors.push({ directiveIndex: i, error: "Hook afterDirective: " + _e }); counters.errors++; }')),r.push("}"),r.push("const _finalResult = { success: true, aborted: false, appliedCount, skippedCount, errors, processedCount: len, totalCount: len, counters };"),n("onDirectivesComplete")&&r.push(`try { ${s("onDirectivesComplete")}onDirectivesComplete(_finalResult); } catch (_e) {}`),r.push("return _finalResult;");let c=r.join(`
2
+ `),h=i?"async ":"";return {fn:new Function("directives","frame","handlers","directiveHooks","typeField","engine","maxDirectives",`"use strict";
3
+ return (${h}() => {
4
+ ${c}
5
+ })();`),isAsync:i}}function N(t,e,i){return `return{success:false,aborted:true,abortedBy:${t},appliedCount,skippedCount,errors,processedCount:${e},totalCount:${i},counters};`}function se(t,e){return `return{success:true,aborted:true,abortedBy:"halt",appliedCount,skippedCount,errors,processedCount:${t},totalCount:${e},counters,data:_result.data};`}function oe(t,e){return `return{success:false,aborted:true,abortedBy:"halt",appliedCount,skippedCount,errors,processedCount:${t},totalCount:${e},counters,data:_result.data};`}function ce(t,e,i){let n=JSON.stringify(e.name);typeof e.resolve=="function"?(t.push("try{"),t.push(`scope[${n}]=$.d[${i}].resolve(ctx,scope).value;`),t.push(`}catch(_e){errors.push({directiveIndex:${i},error:"Binding resolve: "+_e});counters.errors++;}`)):t.push(`scope[${n}]=$.d[${i}].value;`);}function ae(t,e,i,n){let s=typeof e.resolve=="function",r=i+1;s?(t.push("try{"),t.push(`const _rv=$.d[${i}].resolve(ctx,scope);`),t.push(`return{success:true,aborted:false,appliedCount,skippedCount,errors,processedCount:${r},totalCount:${n},counters,data:"value" in _rv?_rv.value:"return" in _rv?_rv.return:$.d[${i}].value};`),t.push(`}catch(_e){errors.push({directiveIndex:${i},error:"Control resolve: "+_e});counters.errors++;}`)):t.push(`return{success:true,aborted:false,appliedCount,skippedCount,errors,processedCount:${r},totalCount:${n},counters,data:$.d[${i}].value};`);}function ue(t,e,i,n){let s=typeof e.resolve=="function",r=i+1;s?(t.push("try{"),t.push(`const _rv=$.d[${i}].resolve(ctx,scope);`),t.push(`return{success:false,aborted:true,abortedBy:"throw",appliedCount,skippedCount,errors,processedCount:${r},totalCount:${n},counters,data:"message" in _rv?_rv.message:"throw" in _rv?_rv.throw:$.d[${i}].message};`),t.push(`}catch(_e){errors.push({directiveIndex:${i},error:"Control resolve: "+_e});counters.errors++;}`)):t.push(`return{success:false,aborted:true,abortedBy:"throw",appliedCount,skippedCount,errors,processedCount:${r},totalCount:${n},counters,data:$.d[${i}].message};`);}function de(t,e,i,n,s,r,c,h,x,m){let D=e[s],R=r.get(D),v=typeof e.resolve=="function",l=typeof e.as=="string",f=Array.isArray(e.catch)&&e.catch.length>0,_=l?JSON.stringify(e.as):"",u=i+1;t.push(`_b${i}:{`);let C=c||v,A=c;C&&t.push(`let _dir=$.d[${i}];`),A&&t.push("let _df=frame;"),c&&(t.push("try{"),t.push(`const _bd=${x}_hookBefore($.d[${i}],frame);`),t.push(`if(_bd==="skip"){skippedCount++;counters.directivesSkipped++;break _b${i};}`),t.push(`if(_bd==="abort")${N('"beforeDirective"',i,n)}`),t.push('if(typeof _bd==="object"&&_bd!==null){'),t.push(`if("abort" in _bd)${N("_bd.abort",i,n)}`),t.push('if("ctx" in _bd)_df=frame.withCtx(_bd.ctx);'),t.push('if("directive" in _bd)_dir=_bd.directive;'),t.push("}"),t.push(`}catch(_e){errors.push({directiveIndex:${i},error:"Hook beforeDirective: "+_e});counters.errors++;}`)),c?(t.push('if(typeof _dir.resolve==="function"){'),t.push("try{const _r=_dir.resolve(_df.ctx,scope);_dir=Object.assign({},_dir,_r);}"),t.push(`catch(_e){errors.push({directiveIndex:${i},error:"Directive resolve: "+_e});counters.errors++;break _b${i};}}`)):v&&(t.push(`try{const _r=$.d[${i}].resolve(ctx,scope);_dir=Object.assign({},$.d[${i}],_r);}`),t.push(`catch(_e){errors.push({directiveIndex:${i},error:"Directive resolve: "+_e});counters.errors++;break _b${i};}`));let k=C?"_dir":`$.d[${i}]`,a=A?"_df":"frame";t.push("let _result;"),t.push(`try{_result=${R}(${k},${a},$.engine);}`),t.push("catch(_e){_result={ok:false,error:String(_e)};}"),t.push("if(_result.ok){"),t.push("appliedCount++;counters.directivesApplied++;"),l&&t.push(`scope[${_}]=_result.data;`),t.push(`if(_result.halt)${se(u,n)}`),t.push("}else{"),t.push(`if(_result.halt)${oe(u,n)}`),f?(t.push('scope.$exception=_result.error||"handler failed";'),t.push(`const _cr=$.runner($.d[${i}].catch,${a});`),t.push("appliedCount+=_cr.appliedCount;"),t.push("for(let _j=0;_j<_cr.errors.length;_j++)errors.push(_cr.errors[_j]);"),t.push(`if(_cr.aborted)return{success:_cr.success,aborted:true,abortedBy:_cr.abortedBy,appliedCount,skippedCount,errors,processedCount:${u},totalCount:${n},counters,data:_cr.data};`)):t.push(`errors.push({directiveIndex:${i},error:_result.error||"handler failed"});counters.errors++;`),t.push("}"),h&&(t.push("try{"),t.push(`const _ad=${m}_hookAfter(${k},_result,${a});`),t.push(`if(_ad==="abort")${N('"afterDirective"',u,n)}`),t.push(`}catch(_e){errors.push({directiveIndex:${i},error:"Hook afterDirective: "+_e});counters.errors++;}`)),t.push("}");}function O(t,e,i){let n=[],s=t.length,{filledNames:r,hasAnyAsync:c,asyncNames:h}=e,x=r.has("beforeDirective"),m=r.has("afterDirective"),D=r.has("onDirectivesComplete"),R=h.has("beforeDirective")?"await ":"",v=h.has("afterDirective")?"await ":"",l=h.has("onDirectivesComplete")?"await ":"",f=new Set;for(let a of t){let p=a[i];p&&!S.has(p)&&f.add(p);}let _=new Map,u=0;for(let a of f)_.set(a,`_h${u++}`);n.push("const counters=frame.counters;"),n.push("const ctx=frame.ctx;"),n.push("const errors=[];"),n.push("let appliedCount=0;"),n.push("let skippedCount=0;");for(let[a,p]of _)n.push(`const ${p}=$.h[${JSON.stringify(a)}];`);x&&n.push("const _hookBefore=$.hooks.beforeDirective;"),m&&n.push("const _hookAfter=$.hooks.afterDirective;");for(let a=0;a<t.length;a++){let p=t[a];switch(p[i]){case "const":case "let":ce(n,p,a);break;case "return":ae(n,p,a,s);break;case "throw":ue(n,p,a,s);break;default:de(n,p,a,s,i,_,x,m,R,v);break}}n.push(`const _finalResult={success:true,aborted:false,appliedCount,skippedCount,errors,processedCount:${s},totalCount:${s},counters};`),D&&n.push(`try{${l}$.hooks.onDirectivesComplete(_finalResult);}catch(_e){}`),n.push("return _finalResult;");let C=n.join(`
6
+ `),A=c?"async ":"";return {fn:new Function("frame","scope","$",`"use strict";
7
+ return(${A}()=>{
8
+ ${C}
9
+ })();`),isAsync:c}}function K(t,e,i){return {success:false,aborted:false,appliedCount:0,skippedCount:0,processedCount:0,totalCount:0,errors:[{directiveIndex:-1,error:e}],counters:t,...i}}function U(t,e){return K(e,`Action not found: "${t}"`)}function G(t,e,i){return K(i,`Max depth ${e} exceeded invoking "${t}"`,{aborted:true,abortedBy:"maxDepth"})}function Y(t,e){return K(e,`Action "${t}" is private (sub-action). Can only be invoked from within its parent scope.`)}function le(t){return typeof t=="object"&&t!==null&&"execute"in t}function Q(t){let e=Object.create(null),i=new Map;for(let n of Object.keys(t)){let s=t[n];le(s)?(e[n]=s.execute,i.set(n,s)):(e[n]=s,i.set(n,{execute:s}));}return {handlers:e,definitions:i}}function X(t,e){if(t==="*")return true;if(!t.includes("*"))return t===e;let i=t.replace(/[.+^${}()|[\]\\]/g,"\\$&");return new RegExp("^"+i.replace(/\*/g,".*")+"$").test(e)}function Z(t){return typeof t=="string"?{pattern:t}:t}function L(t,e,i){let n=new Map;if(!e&&!i){for(let s of t)n.set(s,{status:"available"});return n}if(e){let s=e.map(Z);for(let r of t){let c=s.some(h=>X(h.pattern,r));n.set(r,{status:c?"available":"denied"});}}else {let s=i.map(Z);for(let r of t){let c=s.find(h=>X(h.pattern,r));c?n.set(r,{status:"denied",reason:c.reason,source:c.source}):n.set(r,{status:"available"});}}return n}var ve=8,fe="type",z={maxDepth:10,maxRules:1e4,maxDirectives:1e5},V=class{_directiveExecutor;_mode;_ctx;_requestedMode;_threshold;_limits;_typeField;_handlers;_definitions;_directiveHooks;_directiveAnalysis;_isAsync;_directivePermissions;_registry=new Map;_emitter=new F;_batchDepth=0;_batchErrors=[];_batchWarnings=[];_batchActions=[];_batchRegistered=[];_registeredIds=new Set;_directiveRunner;_engineRef;constructor(e){this._requestedMode=e.mode??"auto",this._threshold=e.autoJitThreshold??ve,this._typeField=e.typeField??fe,this._limits={maxDepth:e.limits?.maxDepth??z.maxDepth,maxRules:e.limits?.maxRules??z.maxRules,maxDirectives:e.limits?.maxDirectives??z.maxDirectives};let{handlers:i,definitions:n}=Q(e.handlers);for(let s of Object.keys(e.handlers))if(S.has(s))throw new Error(`Handler type "${s}" is reserved for engine-internal directives`);if(e.allowedDirectives&&e.blockedDirectives)throw new Error("allowedDirectives and blockedDirectives are mutually exclusive. Provide one or neither.");this._handlers=i,this._definitions=n,this._directivePermissions=L(Object.keys(i),e.allowedDirectives,e.blockedDirectives),this._directiveHooks=e.directiveHooks??{},this._directiveAnalysis=analyzeSlots(this._directiveHooks,DIRECTIVE_SLOT_NAMES),this._isAsync=this._directiveAnalysis.hasAnyAsync,this._engineRef={runDirectives:(s,r)=>this._executeDirectives(s,r),runDirectivesAsync:(s,r)=>this._executeDirectivesAsync(s,r),invoke:(s,r,c)=>this._invokeInternal(s,r,c),invokeAsync:(s,r,c)=>this._invokeInternalAsync(s,r,c),evaluateRules:()=>{throw new Error("evaluateRules() not available in ActionEngine context. Use createRuleEngine().")},evaluateRulesAsync:()=>{throw new Error("evaluateRulesAsync() not available in ActionEngine context. Use createRuleEngine().")}},this._directiveRunner=(s,r)=>this._directiveExecutor(s,r,this._handlers,this._directiveHooks,this._typeField,this._engineRef,this._limits.maxDirectives),this._requestedMode==="jit"?(this._directiveExecutor=this._buildJitDirectiveExecutor(),this._mode="jit"):(this._directiveExecutor=B(this._directiveAnalysis,this._isAsync),this._mode="interpret");}register(e){let i=[],n=[],s=[],r=[];for(let h of e){if(!h.id){n.push({actionId:"",error:"Action must have an id"});continue}let x=W(h,this._handlers,this._definitions,this._typeField);if(x.length>0){for(let m of x)n.push({actionId:h.id,error:m});continue}r.push(h);}for(let h of r){let x=H(h.directives,this._typeField),m={definition:h,directives:x,compiled:null,invokeCount:0};this._requestedMode==="jit"&&(m.compiled=this._compileAction(x)),this._registry.set(h.id,m),this._registeredIds.add(h.id),i.push(h.id);}if(this._batchDepth>0){this._batchErrors.push(...n),this._batchWarnings.push(...s);for(let h of r)this._batchActions.push(h);return this._batchRegistered.push(...i),{registered:i,errors:n,warnings:s}}let c={registered:i,errors:n,warnings:s};return i.length>0&&this._emitter.emit("register",{actions:r,result:c,registered:i}),c}unregister(e){let i=this._registry.delete(e);i&&this._registeredIds.delete(e);let n=e+"/",s=[];for(let r of this._registry.keys())r.startsWith(n)&&(this._registry.delete(r),this._registeredIds.delete(r),s.push(r));return i&&this._emitter.emit("unregister",{id:e,cascaded:s}),i}invoke(e,i){if(this._isAsync)throw new Error("Cannot call invoke() with async hooks. Use invokeAsync() instead.");let n=this._requireCtx(),s=createRootFrame(n,this._limits);return this._invokeInternal(e,i,s)}async invokeAsync(e,i){let n=this._requireCtx(),s=createRootFrame(n,this._limits);return this._invokeInternalAsync(e,i,s)}setContext(e){this._ctx=e;}context(e,i){let n=this._ctx;this._ctx=e;try{return i()}finally{this._ctx=n;}}beginBatch(){this._batchDepth++,this._batchDepth===1&&(this._batchErrors=[],this._batchWarnings=[],this._batchActions=[],this._batchRegistered=[]);}endBatch(){if(this._batchDepth<=0)throw new Error("endBatch() called without matching beginBatch()");if(this._batchDepth--,this._batchDepth>0)return {registered:[],errors:[],warnings:[]};let e={registered:this._batchRegistered,errors:this._batchErrors,warnings:this._batchWarnings};return this._batchRegistered.length>0&&this._emitter.emit("register",{actions:this._batchActions,result:e,registered:this._batchRegistered}),e}on(e,i){return this._emitter.on(e,i)}get handlerDefinitions(){return this._definitions}get registeredIds(){return this._registeredIds}getActionDefinition(e){return this._registry.get(e)?.definition}get typeField(){return this._typeField}get directivePermissions(){return this._directivePermissions}get isAsync(){return this._isAsync}get compilationMode(){return this._mode}get directiveHookSlots(){return this._directiveAnalysis.filledNames}get asyncSlots(){return this._directiveAnalysis.asyncNames}compile(){if(this._requestedMode!=="interpret"){this._mode!=="jit"&&this._promote();for(let e of this._registry.values())e.compiled||(e.compiled=this._compileAction(e.directives));}}_invokeInternal(e,i,n){let s=this._prepareInvoke(e,i,n);if("success"in s)return s;let{stored:r,childFrame:c,childScope:h}=s;if(r.compiled)return r.compiled.fn(c,h,r.compiled.$);let x=this._directiveRunner(r.directives,c);return this._maybeAutoPromote(r),x}async _invokeInternalAsync(e,i,n){let s=this._prepareInvoke(e,i,n);if("success"in s)return s;let{stored:r,childFrame:c,childScope:h}=s;if(r.compiled)return r.compiled.fn(c,h,r.compiled.$);let x=this._directiveRunner(r.directives,c);return this._maybeAutoPromote(r),x}_prepareInvoke(e,i,n){let s=this._registry.get(e);if(!s)return U(e,n.counters);if(e.includes("/")&&!this._isAccessible(e,n))return Y(e,n.counters);if(n.depth>=n.limits.maxDepth)return G(e,n.limits.maxDepth,n.counters);let r=Object.create(n.scope);i&&Object.assign(r,i);let c=n.child("action:"+e,0,e).withScope(r);return {stored:s,childFrame:c,childScope:r}}_maybeAutoPromote(e){this._requestedMode==="auto"&&++e.invokeCount>=this._threshold&&(e.compiled=this._compileAction(e.directives),this._mode!=="jit"&&this._promote());}_executeDirectives(e,i){return this._directiveExecutor(e,i,this._handlers,this._directiveHooks,this._typeField,this._engineRef,this._limits.maxDirectives)}async _executeDirectivesAsync(e,i){return this._directiveExecutor(e,i,this._handlers,this._directiveHooks,this._typeField,this._engineRef,this._limits.maxDirectives)}_compileAction(e){let{fn:i}=O(e,this._directiveAnalysis,this._typeField),n={d:e,h:this._handlers,hooks:this._directiveHooks,engine:this._engineRef,runner:this._directiveRunner};return {fn:i,$:n}}_isAccessible(e,i){let s="action:"+e.slice(0,e.lastIndexOf("/"));return i.path.includes(s)}_requireCtx(){if(this._ctx===void 0)throw new Error("No context set. Call setContext(ctx) or use context(ctx, fn) before invoke.");return this._ctx}_promote(){this._directiveExecutor=this._buildJitDirectiveExecutor(),this._mode="jit";}_buildJitDirectiveExecutor(){let{fn:e}=j(this._directiveAnalysis);return e}};function _e(t){return new V(t)}export{S as RESERVED_TYPES,F as SimpleEmitter,O as buildActionExecutor,j as buildDirectiveExecutor,_e as createActionEngine,B as createDirectiveInterpreter,H as normalizeDirectives};
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@statedelta-actions/actions",
3
+ "version": "0.1.0",
4
+ "description": "Directive execution engine with JIT compilation and BailHook interception",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "dependencies": {
21
+ "@statedelta-actions/core": "0.1.0"
22
+ },
23
+ "author": "Anderson D. Rosa <andersondrosa@outlook.com>",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/andersondrosa/statedelta-actions.git",
28
+ "directory": "packages/actions"
29
+ },
30
+ "sideEffects": false,
31
+ "engines": {
32
+ "node": ">=18"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "build": "tsup",
39
+ "dev": "tsup --watch",
40
+ "test": "vitest run",
41
+ "test:watch": "vitest",
42
+ "test:coverage": "vitest run --coverage",
43
+ "lint": "eslint src/",
44
+ "typecheck": "tsc --noEmit",
45
+ "clean": "rm -rf dist"
46
+ }
47
+ }