From f05624e14ecc8ea0a0fd2f72981511cd16b0fc65 Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Tue, 14 Apr 2026 13:35:17 -0400 Subject: [PATCH 1/2] fix(types): prevent invalid dispatch metadata from bypassing Dialyzer Signed-off-by: Yordis Prieto --- lib/application.ex | 2 +- lib/commanded/commands/composite_router.ex | 2 +- lib/commanded/commands/router.ex | 23 +++++++++++++++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/application.ex b/lib/application.ex index 2f62f41f..76a64110 100644 --- a/lib/application.ex +++ b/lib/application.ex @@ -366,7 +366,7 @@ defmodule Commanded.Application do """ @callback dispatch( command :: struct(), - timeout_or_opts :: non_neg_integer() | :infinity | Keyword.t() + timeout_or_opts :: non_neg_integer() | :infinity | Router.dispatch_options() ) :: Router.dispatch_resp() @doc false diff --git a/lib/commanded/commands/composite_router.ex b/lib/commanded/commands/composite_router.ex index 34ba8854..b612b3aa 100644 --- a/lib/commanded/commands/composite_router.ex +++ b/lib/commanded/commands/composite_router.ex @@ -98,7 +98,7 @@ defmodule Commanded.Commands.CompositeRouter do """ @spec dispatch( command :: struct(), - timeout_or_opts :: non_neg_integer() | :infinity | Keyword.t() + timeout_or_opts :: non_neg_integer() | :infinity | Router.dispatch_options() ) :: Router.dispatch_resp() def dispatch(command, opts \\ []) diff --git a/lib/commanded/commands/router.ex b/lib/commanded/commands/router.ex index 36916321..86edefb7 100644 --- a/lib/commanded/commands/router.ex +++ b/lib/commanded/commands/router.ex @@ -388,6 +388,27 @@ defmodule Commanded.Commands.Router do | {:error, :consistency_timeout} | {:error, reason :: term()} + @type dispatch_consistency :: + :eventual | :strong | [module() | String.t()] + + @type dispatch_return :: + :aggregate_state | :aggregate_version | :events | :execution_result | false + + @type dispatch_option :: + {:application, Commanded.Application.t()} + | {:causation_id, String.t() | nil} + | {:command_uuid, String.t()} + | {:consistency, dispatch_consistency()} + | {:correlation_id, String.t() | nil} + | {:include_aggregate_version, boolean()} + | {:include_execution_result, boolean()} + | {:metadata, map()} + | {:returning, dispatch_return()} + | {:retry_attempts, non_neg_integer() | nil} + | {:timeout, non_neg_integer() | :infinity} + + @type dispatch_options :: [dispatch_option()] + @doc """ Dispatch the given command to the registered handler. @@ -475,7 +496,7 @@ defmodule Commanded.Commands.Router do """ @callback dispatch( command :: struct(), - timeout_or_opts :: non_neg_integer() | :infinity | Keyword.t() + timeout_or_opts :: non_neg_integer() | :infinity | dispatch_options() ) :: dispatch_resp() defmacro __before_compile__(_env) do From 5ce0842db05b8cf47e9a8a03f173983fe161ebc8 Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Tue, 14 Apr 2026 14:36:55 -0400 Subject: [PATCH 2/2] fix(types): include event returns in dispatch response contract Signed-off-by: Yordis Prieto --- lib/commanded/commands/router.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/commanded/commands/router.ex b/lib/commanded/commands/router.ex index 86edefb7..961c474f 100644 --- a/lib/commanded/commands/router.ex +++ b/lib/commanded/commands/router.ex @@ -383,6 +383,7 @@ defmodule Commanded.Commands.Router do :ok | {:ok, aggregate_state :: struct()} | {:ok, aggregate_version :: non_neg_integer()} + | {:ok, events :: [struct()]} | {:ok, execution_result :: ExecutionResult.t()} | {:error, :unregistered_command} | {:error, :consistency_timeout}