@statedelta-actions/actions 0.6.0 → 0.8.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/dist/index.d.cts CHANGED
@@ -12,6 +12,59 @@ interface ValidationResult {
12
12
  error?: string;
13
13
  warnings?: string[];
14
14
  }
15
+ /**
16
+ * Configuração de um campo da diretiva que contém sub-array de Directive[].
17
+ *
18
+ * Comportamento (afeta o engine):
19
+ * - `required`: campo precisa estar presente e ser array. Default: false.
20
+ * - `graph`: se false, ignorado por walks de grafo (mini-graph, analyzer).
21
+ * Default: true.
22
+ *
23
+ * Inspeção (metadata pura — não lida pelo engine, exposta via accessor):
24
+ * - `description`, `purpose`, `examples`, `tags`
25
+ */
26
+ interface SubDirectiveFieldConfig {
27
+ /**
28
+ * Se true, o campo precisa estar presente na diretiva e ser um array
29
+ * de Directive. Ausente ou não-array → throw em register-time.
30
+ * Default: false.
31
+ */
32
+ readonly required?: boolean;
33
+ /**
34
+ * Se false, o campo é ignorado por todos os walks de grafo
35
+ * (mini-graph, analyzer denied-scan, propagators). Útil pra campos
36
+ * de metadata/preview que não representam path de execução real.
37
+ * Default: true.
38
+ */
39
+ readonly graph?: boolean;
40
+ /**
41
+ * Descrição do campo. Hover docs em IDEs, descoberta de esquema
42
+ * por DSL JSON externo, documentação auto-gerada.
43
+ */
44
+ readonly description?: string;
45
+ /**
46
+ * Label semântico machine-readable. Tooling/analyzer pode dar
47
+ * tratamento diferente sem hardcode no engine.
48
+ *
49
+ * Valores comuns (não exaustivo, string livre):
50
+ * - "body" — caminho principal de execução
51
+ * - "catch" — caminho de fallback em erro
52
+ * - "branch" — caminho condicional
53
+ * - "finalizer" — caminho garantido (try/finally)
54
+ * - "metadata" — não é execução real (combine com graph: false)
55
+ */
56
+ readonly purpose?: string;
57
+ /**
58
+ * Exemplos de sub-arrays válidos. DSL/IDE pode usar pra autocomplete
59
+ * e docs auto-geradas.
60
+ */
61
+ readonly examples?: ReadonlyArray<ReadonlyArray<Directive>>;
62
+ /**
63
+ * Tags livres pra categorização cruzada em tooling/analyzer.
64
+ * Ex: ["transaction", "rollback-safe"].
65
+ */
66
+ readonly tags?: ReadonlyArray<string>;
67
+ }
15
68
  /**
16
69
  * Campos comuns a todo handler V2, independente do modo de execução.
17
70
  * `execute` fica nos subtipos — cada modo refina seu retorno. Não é genérico
@@ -24,6 +77,50 @@ interface HandlerBaseDefinition {
24
77
  validate?: (directive: Directive) => ValidationResult | void;
25
78
  /** JIT-time: contribui código inline per-action (Fase 2c). */
26
79
  compile?: (directive: Directive, compiler: unknown) => string | void;
80
+ /**
81
+ * Declara campos da diretiva que contêm sub-arrays de Directive[].
82
+ * O engine usa essa informação para:
83
+ * - Validação recursiva em register-time (com `required`)
84
+ * - Normalização recursiva (catch internos aninhados)
85
+ * - Walks do mini-graph (deps, async/interactive transitivo) — quando `graph !== false`
86
+ * - Walks do analyzer (denied-scan, capabilities, composition)
87
+ *
88
+ * NÃO afeta execução. Handler.execute é responsável por rodar
89
+ * as sub-directives via engine.runDirectives() ou runDirectivesAsync().
90
+ *
91
+ * Ver: docs/proposals/REFACTOR-SUBDIRECTIVES-DESCRIPTOR.md
92
+ */
93
+ readonly subDirectives?: {
94
+ readonly [fieldName: string]: SubDirectiveFieldConfig;
95
+ };
96
+ /**
97
+ * Descrição do handler. Hover docs, descoberta de esquema por DSL,
98
+ * documentação auto-gerada.
99
+ */
100
+ readonly description?: string;
101
+ /**
102
+ * Tags livres pra categorização cruzada (control-flow, transaction,
103
+ * io, query, etc.). Tooling pode agrupar/filtrar handlers por tag.
104
+ */
105
+ readonly tags?: ReadonlyArray<string>;
106
+ /**
107
+ * Marca o handler como obsoleto. boolean = deprecated sem motivo;
108
+ * string = mensagem de migração ("use 'try' since v0.5").
109
+ * Tooling/analyzer pode emitir warning quando handler é usado.
110
+ */
111
+ readonly deprecated?: boolean | string;
112
+ /**
113
+ * Versão em que o handler foi introduzido. SemVer ou string livre.
114
+ * Útil pra versionamento de DSL e compat checks no analyzer.
115
+ */
116
+ readonly since?: string;
117
+ /**
118
+ * Declara que esse handler é alias semântico de outro
119
+ * (mesma forma estrutural, mesma intenção). Tooling pode dedup
120
+ * referências e documentação. NÃO afeta dispatch — cada handler
121
+ * permanece independente em runtime.
122
+ */
123
+ readonly aliasOf?: string;
27
124
  }
28
125
  /** Função `execute` de um handler sync — retorna `ApplyResult` direto. */
29
126
  type SyncHandlerExecute<TCtx> = (directive: Directive, frame: ExecutionFrame<TCtx>, engine: ActionEngineRef<TCtx>) => ApplyResult;
@@ -37,57 +134,69 @@ type AsyncHandlerExecute<TCtx> = (directive: Directive, frame: ExecutionFrame<TC
37
134
  */
38
135
  type InteractiveHandlerExecute<TCtx> = (directive: Directive, frame: ExecutionFrame<TCtx>, engine: ActionEngineRef<TCtx>) => Generator<unknown, ApplyResult, unknown> | AsyncGenerator<unknown, ApplyResult, unknown>;
39
136
  /**
40
- * Handler sync `execute` retorna `ApplyResult` direto. É o modo default:
41
- * sem flag e sem `async function`/`function*`, o handler é tratado como sync.
42
- */
43
- interface SyncHandlerDefinition<TCtx> extends HandlerBaseDefinition {
44
- async?: false;
45
- interactive?: false;
46
- execute: SyncHandlerExecute<TCtx>;
47
- }
48
- /**
49
- * Handler async — `execute` retorna `Promise<ApplyResult>`. Marcado com
50
- * `async: true` ou detectado via `isAsyncFunction(execute)` (cobre
51
- * `async function`). Use a flag pra wrappers que retornam Promise sem serem
52
- * `async function` (ex: factory que delega via `.then`).
137
+ * Handler V2 (objeto com fases). Multi-variant: o handler declara `execute`
138
+ * como floor (sync, async ou generator) e opcionalmente `executeAsync` e
139
+ * `executeInteractive` como variantes especializadas pra quando a action
140
+ * que o usa é transitivamente async/interactive.
53
141
  *
54
- * Quando o engine um handler async: inclui no async handler set, força
55
- * `isAsync = true` no engine inteiro, e emite `await` ao invocá-lo no
56
- * interpreter async e nos JITs.
57
- */
58
- interface AsyncHandlerDefinition<TCtx> extends HandlerBaseDefinition {
59
- async: true;
60
- interactive?: false;
61
- execute: AsyncHandlerExecute<TCtx>;
62
- }
63
- /**
64
- * Handler interactive — `execute` é generator (sync ou async). Marcado com
65
- * `interactive: true` ou detectado via `isGeneratorFunction(execute)` (cobre
66
- * `function*` e `async function*`). Use a flag pra wrappers que retornam
67
- * iterator sem serem generator function. Pode também ser `async` (generator
68
- * async) — daí `async: true` junto.
142
+ * Seleção da variante (compile-time da action, via mini-graph):
143
+ * - Action transitivamente interactive `executeInteractive` (se presente),
144
+ * senão `execute` (deve ser generator function ou flag `interactive: true`,
145
+ * validado em register-time)
146
+ * - Action transitivamente async → `executeAsync` (se presente), senão
147
+ * `execute` (engine awaita — `await` em valor sync é no-op)
148
+ * - Action sync → `execute`
69
149
  *
70
- * Quando o engine um handler interactive: inclui no interactive handler set,
71
- * propaga `_interactiveActions` transitivamente no mini-graph, emite
72
- * `yield* handler(...)` ao invocá-lo nas actions interactive, e exige
73
- * `engine.invokeInteractive()` em actions cuja sub-árvore o use. Handler
74
- * `interactive: true` em engine sem `interactive` config → erro no constructor
75
- * (fail-fast).
150
+ * Auto-detect de modo do handler:
151
+ * - `executeAsync` presente OU `async: true` OU `isAsyncFunction(execute)`
152
+ * handler é async (adicionado ao `asyncHandlerSet`)
153
+ * - `executeInteractive` presente OU `interactive: true` OU
154
+ * `isGeneratorFunction(execute)` handler é interactive (adicionado ao
155
+ * `interactiveHandlerSet`)
156
+ *
157
+ * Custo runtime: zero. A seleção de variante acontece 1x em register/compile
158
+ * time da action — `$.h[type]` no JIT já vem pré-resolvido pra função certa.
159
+ *
160
+ * Backwards compat: handlers single-mode (só `execute`) continuam funcionando
161
+ * idênticos. As variantes opcionais são pra wrapper handlers (simulate, try_,
162
+ * transaction) que precisam adaptar à mode do sub-bloco.
76
163
  */
77
- interface InteractiveHandlerDefinition<TCtx> extends HandlerBaseDefinition {
78
- interactive: true;
164
+ interface HandlerDefinition<TCtx> extends HandlerBaseDefinition {
165
+ /**
166
+ * Floor execute. Pode ser sync, async, ou generator. O modo é
167
+ * auto-detectado via `isAsyncFunction`/`isGeneratorFunction`, ou
168
+ * declarado explícito via `async`/`interactive` flags.
169
+ */
170
+ execute: SyncHandlerExecute<TCtx> | AsyncHandlerExecute<TCtx> | InteractiveHandlerExecute<TCtx>;
171
+ /**
172
+ * Variante async opcional. Quando presente, engine usa esta no lugar de
173
+ * `execute` em actions transitivamente async. Sua presença marca o
174
+ * handler como async (entra no `asyncHandlerSet`).
175
+ */
176
+ executeAsync?: AsyncHandlerExecute<TCtx>;
177
+ /**
178
+ * Variante interactive opcional. Quando presente, engine usa esta no
179
+ * lugar de `execute` em actions transitivamente interactive. Sua
180
+ * presença marca o handler como interactive (entra no
181
+ * `interactiveHandlerSet`). Convenção: `async function*` (cobre tanto
182
+ * sync+interactive quanto async+interactive — o `await` interno em
183
+ * valor sync é no-op, V8 otimiza).
184
+ */
185
+ executeInteractive?: InteractiveHandlerExecute<TCtx>;
186
+ /**
187
+ * Flag explícita — handler é async (mesmo que `execute` não seja
188
+ * `async function`). Use pra wrappers que retornam Promise sem serem
189
+ * `async function`.
190
+ */
79
191
  async?: boolean;
80
- execute: InteractiveHandlerExecute<TCtx>;
192
+ /**
193
+ * Flag explícita — handler é interactive (mesmo que `execute` não seja
194
+ * generator). Use pra wrappers que retornam iterator sem serem
195
+ * generator function. Em engine sem `interactive` config → erro no
196
+ * constructor (fail-fast).
197
+ */
198
+ interactive?: boolean;
81
199
  }
82
- /**
83
- * Handler V2 (objeto com fases). Discriminated union pelo modo de execução —
84
- * `async` e `interactive` discriminam, `execute` refina seu retorno conforme
85
- * o modo. Tipar como `HandlerDefinition<TCtx>` continua válido (é o agregado);
86
- * narrowing pelos flags refina pro subtipo. Quem sabe o modo do seu handler
87
- * pode tipar diretamente como `SyncHandlerDefinition` etc. e chamar
88
- * `handler.execute(...)` sem `await`/narrowing.
89
- */
90
- type HandlerDefinition<TCtx> = SyncHandlerDefinition<TCtx> | AsyncHandlerDefinition<TCtx> | InteractiveHandlerDefinition<TCtx>;
91
200
  /**
92
201
  * Aceita handler V1 (função) ou V2 (objeto com fases).
93
202
  * Backwards compat: função simples é tratada como { execute: fn }.
@@ -221,6 +330,7 @@ type DirectivePermissionEntry = string | DirectivePermissionConfig;
221
330
  * - diretiva `type: "pause"` → erro no register
222
331
  */
223
332
  interface InteractiveConfig {
333
+ readonly [key: string]: unknown;
224
334
  }
225
335
  /**
226
336
  * Evento yieldado durante execução de uma action interactive.
@@ -391,6 +501,13 @@ interface IActionEngine<TCtx> {
391
501
  getActionDefinition(id: string): ActionDefinition<TCtx> | undefined;
392
502
  /** Campo de tipo pra dispatch de diretivas (default: "type"). */
393
503
  readonly typeField: string;
504
+ /**
505
+ * Mapa `type → readonly fieldNames[]` dos campos declarados pelo
506
+ * `subDirectives` dos handlers que entram no grafo (graph !== false).
507
+ * Pré-computado no construct-time. Consumido pelo mini-graph interno
508
+ * e por walks externos (analyzer denied-scan, capabilities, composition).
509
+ */
510
+ readonly subDirectiveFieldsForGraph: ReadonlyMap<string, readonly string[]>;
394
511
  /**
395
512
  * Mapa de permissões de diretivas, computado no boot (imutável).
396
513
  * Contém apenas handlers registrados (available ou denied).
@@ -535,7 +652,7 @@ declare class SimpleEmitter<TEvents = Record<string, unknown>> {
535
652
  }
536
653
 
537
654
  declare const RESERVED_TYPES: Set<string>;
538
- declare function normalizeDirectives<TCtx>(directives: readonly Directive<TCtx>[], typeField: string): Directive<TCtx>[];
655
+ declare function normalizeDirectives<TCtx>(directives: readonly Directive<TCtx>[], typeField: string, subDirectiveFieldsAll?: ReadonlyMap<string, readonly string[]>): Directive<TCtx>[];
539
656
 
540
657
  declare function createDirectiveInterpreter<TCtx>(analysis: SlotAnalysis, isAsync: boolean): DirectiveExecutorFn<TCtx>;
541
658
 
@@ -557,9 +674,22 @@ interface GeneratedDirectiveExecutor {
557
674
  */
558
675
  declare function buildDirectiveExecutor(analysis: SlotAnalysis, isAsync?: boolean): GeneratedDirectiveExecutor;
559
676
 
560
- type RuntimeActionExecutorFn = (frame: unknown, scope: unknown, $: unknown) => unknown;
677
+ /**
678
+ * Assinatura da função compilada pelo JIT per-action.
679
+ *
680
+ * Os parâmetros são tipados como `unknown` propositalmente: a função é
681
+ * criada via `new Function(...)` e recebe `frame`/`scope`/`$` que o
682
+ * caller (engine) já tem em tipos concretos. O retorno é `unknown`
683
+ * porque o JIT compila 4 shapes possíveis (sync/async/generator/
684
+ * async-generator) e o caller faz narrowing baseado em
685
+ * `GeneratedActionExecutor.{isAsync,isInteractive}`.
686
+ *
687
+ * Exportada pra que o engine possa tipar `CompiledAction.fn` sem
688
+ * cair em `Function` (que perde toda checagem de assinatura).
689
+ */
690
+ type GeneratedActionExecutorFn = (frame: unknown, scope: unknown, $: unknown) => unknown;
561
691
  interface GeneratedActionExecutor {
562
- fn: RuntimeActionExecutorFn;
692
+ fn: GeneratedActionExecutorFn;
563
693
  /** Wrapper async (`async function`/`async function*`)? */
564
694
  isAsync: boolean;
565
695
  /** Wrapper generator (`function*`/`async function*`)? Quando true, `fn(...)` retorna Generator/AsyncGenerator. */
@@ -595,4 +725,4 @@ interface GeneratedActionExecutor {
595
725
  */
596
726
  declare function buildActionExecutor(directives: readonly Directive[], analysis: SlotAnalysis, typeField: string, asyncHandlerSet?: ReadonlySet<string>, actionUsesAsyncOverride?: boolean, actionIsInteractive?: boolean, interactiveHandlerSet?: ReadonlySet<string>): GeneratedActionExecutor;
597
727
 
598
- export { type ActionDefinition, type ActionHooks, type ActionInterceptResult, type AsyncHandlerDefinition, type AsyncHandlerExecute, type AsyncInteractiveSession, 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 HandlerBaseDefinition, type HandlerDefinition, type HandlerInput, type HandlerInputMap, type IActionEngine, type IActionEngineConfig, type InteractiveApplyResult, type InteractiveConfig, type InteractiveHandlerDefinition, type InteractiveHandlerExecute, type InteractiveSession, type Listener, type PauseEvent, RESERVED_TYPES, type RegisterError, type RegisterEvent, type RegisterResult, type Responder, SimpleEmitter, type SyncHandlerDefinition, type SyncHandlerExecute, type UnregisterEvent, type ValidationResult, buildActionExecutor, buildDirectiveExecutor, createActionEngine, createDirectiveInterpreter, drainAsync, drainSync, normalizeDirectives, replayResponder };
728
+ export { type ActionDefinition, type ActionHooks, type ActionInterceptResult, type AsyncHandlerExecute, type AsyncInteractiveSession, 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 GeneratedActionExecutorFn, type GeneratedDirectiveExecutor, type HandlerAnalysis, type HandlerBaseDefinition, type HandlerDefinition, type HandlerInput, type HandlerInputMap, type IActionEngine, type IActionEngineConfig, type InteractiveApplyResult, type InteractiveConfig, type InteractiveHandlerExecute, type InteractiveSession, type Listener, type PauseEvent, RESERVED_TYPES, type RegisterError, type RegisterEvent, type RegisterResult, type Responder, SimpleEmitter, type SubDirectiveFieldConfig, type SyncHandlerExecute, type UnregisterEvent, type ValidationResult, buildActionExecutor, buildDirectiveExecutor, createActionEngine, createDirectiveInterpreter, drainAsync, drainSync, normalizeDirectives, replayResponder };
package/dist/index.d.ts CHANGED
@@ -12,6 +12,59 @@ interface ValidationResult {
12
12
  error?: string;
13
13
  warnings?: string[];
14
14
  }
15
+ /**
16
+ * Configuração de um campo da diretiva que contém sub-array de Directive[].
17
+ *
18
+ * Comportamento (afeta o engine):
19
+ * - `required`: campo precisa estar presente e ser array. Default: false.
20
+ * - `graph`: se false, ignorado por walks de grafo (mini-graph, analyzer).
21
+ * Default: true.
22
+ *
23
+ * Inspeção (metadata pura — não lida pelo engine, exposta via accessor):
24
+ * - `description`, `purpose`, `examples`, `tags`
25
+ */
26
+ interface SubDirectiveFieldConfig {
27
+ /**
28
+ * Se true, o campo precisa estar presente na diretiva e ser um array
29
+ * de Directive. Ausente ou não-array → throw em register-time.
30
+ * Default: false.
31
+ */
32
+ readonly required?: boolean;
33
+ /**
34
+ * Se false, o campo é ignorado por todos os walks de grafo
35
+ * (mini-graph, analyzer denied-scan, propagators). Útil pra campos
36
+ * de metadata/preview que não representam path de execução real.
37
+ * Default: true.
38
+ */
39
+ readonly graph?: boolean;
40
+ /**
41
+ * Descrição do campo. Hover docs em IDEs, descoberta de esquema
42
+ * por DSL JSON externo, documentação auto-gerada.
43
+ */
44
+ readonly description?: string;
45
+ /**
46
+ * Label semântico machine-readable. Tooling/analyzer pode dar
47
+ * tratamento diferente sem hardcode no engine.
48
+ *
49
+ * Valores comuns (não exaustivo, string livre):
50
+ * - "body" — caminho principal de execução
51
+ * - "catch" — caminho de fallback em erro
52
+ * - "branch" — caminho condicional
53
+ * - "finalizer" — caminho garantido (try/finally)
54
+ * - "metadata" — não é execução real (combine com graph: false)
55
+ */
56
+ readonly purpose?: string;
57
+ /**
58
+ * Exemplos de sub-arrays válidos. DSL/IDE pode usar pra autocomplete
59
+ * e docs auto-geradas.
60
+ */
61
+ readonly examples?: ReadonlyArray<ReadonlyArray<Directive>>;
62
+ /**
63
+ * Tags livres pra categorização cruzada em tooling/analyzer.
64
+ * Ex: ["transaction", "rollback-safe"].
65
+ */
66
+ readonly tags?: ReadonlyArray<string>;
67
+ }
15
68
  /**
16
69
  * Campos comuns a todo handler V2, independente do modo de execução.
17
70
  * `execute` fica nos subtipos — cada modo refina seu retorno. Não é genérico
@@ -24,6 +77,50 @@ interface HandlerBaseDefinition {
24
77
  validate?: (directive: Directive) => ValidationResult | void;
25
78
  /** JIT-time: contribui código inline per-action (Fase 2c). */
26
79
  compile?: (directive: Directive, compiler: unknown) => string | void;
80
+ /**
81
+ * Declara campos da diretiva que contêm sub-arrays de Directive[].
82
+ * O engine usa essa informação para:
83
+ * - Validação recursiva em register-time (com `required`)
84
+ * - Normalização recursiva (catch internos aninhados)
85
+ * - Walks do mini-graph (deps, async/interactive transitivo) — quando `graph !== false`
86
+ * - Walks do analyzer (denied-scan, capabilities, composition)
87
+ *
88
+ * NÃO afeta execução. Handler.execute é responsável por rodar
89
+ * as sub-directives via engine.runDirectives() ou runDirectivesAsync().
90
+ *
91
+ * Ver: docs/proposals/REFACTOR-SUBDIRECTIVES-DESCRIPTOR.md
92
+ */
93
+ readonly subDirectives?: {
94
+ readonly [fieldName: string]: SubDirectiveFieldConfig;
95
+ };
96
+ /**
97
+ * Descrição do handler. Hover docs, descoberta de esquema por DSL,
98
+ * documentação auto-gerada.
99
+ */
100
+ readonly description?: string;
101
+ /**
102
+ * Tags livres pra categorização cruzada (control-flow, transaction,
103
+ * io, query, etc.). Tooling pode agrupar/filtrar handlers por tag.
104
+ */
105
+ readonly tags?: ReadonlyArray<string>;
106
+ /**
107
+ * Marca o handler como obsoleto. boolean = deprecated sem motivo;
108
+ * string = mensagem de migração ("use 'try' since v0.5").
109
+ * Tooling/analyzer pode emitir warning quando handler é usado.
110
+ */
111
+ readonly deprecated?: boolean | string;
112
+ /**
113
+ * Versão em que o handler foi introduzido. SemVer ou string livre.
114
+ * Útil pra versionamento de DSL e compat checks no analyzer.
115
+ */
116
+ readonly since?: string;
117
+ /**
118
+ * Declara que esse handler é alias semântico de outro
119
+ * (mesma forma estrutural, mesma intenção). Tooling pode dedup
120
+ * referências e documentação. NÃO afeta dispatch — cada handler
121
+ * permanece independente em runtime.
122
+ */
123
+ readonly aliasOf?: string;
27
124
  }
28
125
  /** Função `execute` de um handler sync — retorna `ApplyResult` direto. */
29
126
  type SyncHandlerExecute<TCtx> = (directive: Directive, frame: ExecutionFrame<TCtx>, engine: ActionEngineRef<TCtx>) => ApplyResult;
@@ -37,57 +134,69 @@ type AsyncHandlerExecute<TCtx> = (directive: Directive, frame: ExecutionFrame<TC
37
134
  */
38
135
  type InteractiveHandlerExecute<TCtx> = (directive: Directive, frame: ExecutionFrame<TCtx>, engine: ActionEngineRef<TCtx>) => Generator<unknown, ApplyResult, unknown> | AsyncGenerator<unknown, ApplyResult, unknown>;
39
136
  /**
40
- * Handler sync `execute` retorna `ApplyResult` direto. É o modo default:
41
- * sem flag e sem `async function`/`function*`, o handler é tratado como sync.
42
- */
43
- interface SyncHandlerDefinition<TCtx> extends HandlerBaseDefinition {
44
- async?: false;
45
- interactive?: false;
46
- execute: SyncHandlerExecute<TCtx>;
47
- }
48
- /**
49
- * Handler async — `execute` retorna `Promise<ApplyResult>`. Marcado com
50
- * `async: true` ou detectado via `isAsyncFunction(execute)` (cobre
51
- * `async function`). Use a flag pra wrappers que retornam Promise sem serem
52
- * `async function` (ex: factory que delega via `.then`).
137
+ * Handler V2 (objeto com fases). Multi-variant: o handler declara `execute`
138
+ * como floor (sync, async ou generator) e opcionalmente `executeAsync` e
139
+ * `executeInteractive` como variantes especializadas pra quando a action
140
+ * que o usa é transitivamente async/interactive.
53
141
  *
54
- * Quando o engine um handler async: inclui no async handler set, força
55
- * `isAsync = true` no engine inteiro, e emite `await` ao invocá-lo no
56
- * interpreter async e nos JITs.
57
- */
58
- interface AsyncHandlerDefinition<TCtx> extends HandlerBaseDefinition {
59
- async: true;
60
- interactive?: false;
61
- execute: AsyncHandlerExecute<TCtx>;
62
- }
63
- /**
64
- * Handler interactive — `execute` é generator (sync ou async). Marcado com
65
- * `interactive: true` ou detectado via `isGeneratorFunction(execute)` (cobre
66
- * `function*` e `async function*`). Use a flag pra wrappers que retornam
67
- * iterator sem serem generator function. Pode também ser `async` (generator
68
- * async) — daí `async: true` junto.
142
+ * Seleção da variante (compile-time da action, via mini-graph):
143
+ * - Action transitivamente interactive `executeInteractive` (se presente),
144
+ * senão `execute` (deve ser generator function ou flag `interactive: true`,
145
+ * validado em register-time)
146
+ * - Action transitivamente async → `executeAsync` (se presente), senão
147
+ * `execute` (engine awaita — `await` em valor sync é no-op)
148
+ * - Action sync → `execute`
69
149
  *
70
- * Quando o engine um handler interactive: inclui no interactive handler set,
71
- * propaga `_interactiveActions` transitivamente no mini-graph, emite
72
- * `yield* handler(...)` ao invocá-lo nas actions interactive, e exige
73
- * `engine.invokeInteractive()` em actions cuja sub-árvore o use. Handler
74
- * `interactive: true` em engine sem `interactive` config → erro no constructor
75
- * (fail-fast).
150
+ * Auto-detect de modo do handler:
151
+ * - `executeAsync` presente OU `async: true` OU `isAsyncFunction(execute)`
152
+ * handler é async (adicionado ao `asyncHandlerSet`)
153
+ * - `executeInteractive` presente OU `interactive: true` OU
154
+ * `isGeneratorFunction(execute)` handler é interactive (adicionado ao
155
+ * `interactiveHandlerSet`)
156
+ *
157
+ * Custo runtime: zero. A seleção de variante acontece 1x em register/compile
158
+ * time da action — `$.h[type]` no JIT já vem pré-resolvido pra função certa.
159
+ *
160
+ * Backwards compat: handlers single-mode (só `execute`) continuam funcionando
161
+ * idênticos. As variantes opcionais são pra wrapper handlers (simulate, try_,
162
+ * transaction) que precisam adaptar à mode do sub-bloco.
76
163
  */
77
- interface InteractiveHandlerDefinition<TCtx> extends HandlerBaseDefinition {
78
- interactive: true;
164
+ interface HandlerDefinition<TCtx> extends HandlerBaseDefinition {
165
+ /**
166
+ * Floor execute. Pode ser sync, async, ou generator. O modo é
167
+ * auto-detectado via `isAsyncFunction`/`isGeneratorFunction`, ou
168
+ * declarado explícito via `async`/`interactive` flags.
169
+ */
170
+ execute: SyncHandlerExecute<TCtx> | AsyncHandlerExecute<TCtx> | InteractiveHandlerExecute<TCtx>;
171
+ /**
172
+ * Variante async opcional. Quando presente, engine usa esta no lugar de
173
+ * `execute` em actions transitivamente async. Sua presença marca o
174
+ * handler como async (entra no `asyncHandlerSet`).
175
+ */
176
+ executeAsync?: AsyncHandlerExecute<TCtx>;
177
+ /**
178
+ * Variante interactive opcional. Quando presente, engine usa esta no
179
+ * lugar de `execute` em actions transitivamente interactive. Sua
180
+ * presença marca o handler como interactive (entra no
181
+ * `interactiveHandlerSet`). Convenção: `async function*` (cobre tanto
182
+ * sync+interactive quanto async+interactive — o `await` interno em
183
+ * valor sync é no-op, V8 otimiza).
184
+ */
185
+ executeInteractive?: InteractiveHandlerExecute<TCtx>;
186
+ /**
187
+ * Flag explícita — handler é async (mesmo que `execute` não seja
188
+ * `async function`). Use pra wrappers que retornam Promise sem serem
189
+ * `async function`.
190
+ */
79
191
  async?: boolean;
80
- execute: InteractiveHandlerExecute<TCtx>;
192
+ /**
193
+ * Flag explícita — handler é interactive (mesmo que `execute` não seja
194
+ * generator). Use pra wrappers que retornam iterator sem serem
195
+ * generator function. Em engine sem `interactive` config → erro no
196
+ * constructor (fail-fast).
197
+ */
198
+ interactive?: boolean;
81
199
  }
82
- /**
83
- * Handler V2 (objeto com fases). Discriminated union pelo modo de execução —
84
- * `async` e `interactive` discriminam, `execute` refina seu retorno conforme
85
- * o modo. Tipar como `HandlerDefinition<TCtx>` continua válido (é o agregado);
86
- * narrowing pelos flags refina pro subtipo. Quem sabe o modo do seu handler
87
- * pode tipar diretamente como `SyncHandlerDefinition` etc. e chamar
88
- * `handler.execute(...)` sem `await`/narrowing.
89
- */
90
- type HandlerDefinition<TCtx> = SyncHandlerDefinition<TCtx> | AsyncHandlerDefinition<TCtx> | InteractiveHandlerDefinition<TCtx>;
91
200
  /**
92
201
  * Aceita handler V1 (função) ou V2 (objeto com fases).
93
202
  * Backwards compat: função simples é tratada como { execute: fn }.
@@ -221,6 +330,7 @@ type DirectivePermissionEntry = string | DirectivePermissionConfig;
221
330
  * - diretiva `type: "pause"` → erro no register
222
331
  */
223
332
  interface InteractiveConfig {
333
+ readonly [key: string]: unknown;
224
334
  }
225
335
  /**
226
336
  * Evento yieldado durante execução de uma action interactive.
@@ -391,6 +501,13 @@ interface IActionEngine<TCtx> {
391
501
  getActionDefinition(id: string): ActionDefinition<TCtx> | undefined;
392
502
  /** Campo de tipo pra dispatch de diretivas (default: "type"). */
393
503
  readonly typeField: string;
504
+ /**
505
+ * Mapa `type → readonly fieldNames[]` dos campos declarados pelo
506
+ * `subDirectives` dos handlers que entram no grafo (graph !== false).
507
+ * Pré-computado no construct-time. Consumido pelo mini-graph interno
508
+ * e por walks externos (analyzer denied-scan, capabilities, composition).
509
+ */
510
+ readonly subDirectiveFieldsForGraph: ReadonlyMap<string, readonly string[]>;
394
511
  /**
395
512
  * Mapa de permissões de diretivas, computado no boot (imutável).
396
513
  * Contém apenas handlers registrados (available ou denied).
@@ -535,7 +652,7 @@ declare class SimpleEmitter<TEvents = Record<string, unknown>> {
535
652
  }
536
653
 
537
654
  declare const RESERVED_TYPES: Set<string>;
538
- declare function normalizeDirectives<TCtx>(directives: readonly Directive<TCtx>[], typeField: string): Directive<TCtx>[];
655
+ declare function normalizeDirectives<TCtx>(directives: readonly Directive<TCtx>[], typeField: string, subDirectiveFieldsAll?: ReadonlyMap<string, readonly string[]>): Directive<TCtx>[];
539
656
 
540
657
  declare function createDirectiveInterpreter<TCtx>(analysis: SlotAnalysis, isAsync: boolean): DirectiveExecutorFn<TCtx>;
541
658
 
@@ -557,9 +674,22 @@ interface GeneratedDirectiveExecutor {
557
674
  */
558
675
  declare function buildDirectiveExecutor(analysis: SlotAnalysis, isAsync?: boolean): GeneratedDirectiveExecutor;
559
676
 
560
- type RuntimeActionExecutorFn = (frame: unknown, scope: unknown, $: unknown) => unknown;
677
+ /**
678
+ * Assinatura da função compilada pelo JIT per-action.
679
+ *
680
+ * Os parâmetros são tipados como `unknown` propositalmente: a função é
681
+ * criada via `new Function(...)` e recebe `frame`/`scope`/`$` que o
682
+ * caller (engine) já tem em tipos concretos. O retorno é `unknown`
683
+ * porque o JIT compila 4 shapes possíveis (sync/async/generator/
684
+ * async-generator) e o caller faz narrowing baseado em
685
+ * `GeneratedActionExecutor.{isAsync,isInteractive}`.
686
+ *
687
+ * Exportada pra que o engine possa tipar `CompiledAction.fn` sem
688
+ * cair em `Function` (que perde toda checagem de assinatura).
689
+ */
690
+ type GeneratedActionExecutorFn = (frame: unknown, scope: unknown, $: unknown) => unknown;
561
691
  interface GeneratedActionExecutor {
562
- fn: RuntimeActionExecutorFn;
692
+ fn: GeneratedActionExecutorFn;
563
693
  /** Wrapper async (`async function`/`async function*`)? */
564
694
  isAsync: boolean;
565
695
  /** Wrapper generator (`function*`/`async function*`)? Quando true, `fn(...)` retorna Generator/AsyncGenerator. */
@@ -595,4 +725,4 @@ interface GeneratedActionExecutor {
595
725
  */
596
726
  declare function buildActionExecutor(directives: readonly Directive[], analysis: SlotAnalysis, typeField: string, asyncHandlerSet?: ReadonlySet<string>, actionUsesAsyncOverride?: boolean, actionIsInteractive?: boolean, interactiveHandlerSet?: ReadonlySet<string>): GeneratedActionExecutor;
597
727
 
598
- export { type ActionDefinition, type ActionHooks, type ActionInterceptResult, type AsyncHandlerDefinition, type AsyncHandlerExecute, type AsyncInteractiveSession, 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 HandlerBaseDefinition, type HandlerDefinition, type HandlerInput, type HandlerInputMap, type IActionEngine, type IActionEngineConfig, type InteractiveApplyResult, type InteractiveConfig, type InteractiveHandlerDefinition, type InteractiveHandlerExecute, type InteractiveSession, type Listener, type PauseEvent, RESERVED_TYPES, type RegisterError, type RegisterEvent, type RegisterResult, type Responder, SimpleEmitter, type SyncHandlerDefinition, type SyncHandlerExecute, type UnregisterEvent, type ValidationResult, buildActionExecutor, buildDirectiveExecutor, createActionEngine, createDirectiveInterpreter, drainAsync, drainSync, normalizeDirectives, replayResponder };
728
+ export { type ActionDefinition, type ActionHooks, type ActionInterceptResult, type AsyncHandlerExecute, type AsyncInteractiveSession, 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 GeneratedActionExecutorFn, type GeneratedDirectiveExecutor, type HandlerAnalysis, type HandlerBaseDefinition, type HandlerDefinition, type HandlerInput, type HandlerInputMap, type IActionEngine, type IActionEngineConfig, type InteractiveApplyResult, type InteractiveConfig, type InteractiveHandlerExecute, type InteractiveSession, type Listener, type PauseEvent, RESERVED_TYPES, type RegisterError, type RegisterEvent, type RegisterResult, type Responder, SimpleEmitter, type SubDirectiveFieldConfig, type SyncHandlerExecute, type UnregisterEvent, type ValidationResult, buildActionExecutor, buildDirectiveExecutor, createActionEngine, createDirectiveInterpreter, drainAsync, drainSync, normalizeDirectives, replayResponder };