11import Foundation
22
3+ /// Action execution closure that mutates state and returns a task.
4+ ///
5+ /// This typealias defines the signature for action processing logic used in ``ActionHandler``.
6+ /// The closure receives an action and state, performs any necessary state mutations,
7+ /// and returns an ``ActionTask`` for asynchronous side effects.
8+ ///
9+ /// All execution occurs on the **MainActor**, ensuring thread-safe state mutations.
10+ ///
11+ /// ## Example
12+ /// ```swift
13+ /// let execution: ActionExecution<MyAction, MyState, Void> = { action, state in
14+ /// switch action {
15+ /// case .increment:
16+ /// state.count += 1
17+ /// return .none
18+ /// }
19+ /// }
20+ /// ```
21+ ///
22+ /// ## Type Parameters
23+ /// - `Action`: The action type to process (must be Sendable)
24+ /// - `State`: The state type to mutate (must be AnyObject/reference type)
25+ /// - `ActionResult`: The result type returned from action processing (must be Sendable)
26+ ///
27+ /// ## See Also
28+ /// - ``ActionHandler/init(_:)``
29+ ///
30+ /// - Note: Type constraints match Feature protocol requirements to ensure consistency.
31+ public typealias ActionExecution < Action: Sendable , State: AnyObject , ActionResult: Sendable > =
32+ @MainActor ( Action, State) async -> ActionTask < Action , State , ActionResult >
33+
334/// A facade for action processing with fluent method chaining capabilities that can return typed results.
435///
536/// `ActionHandler` provides a clean, composable API for defining how your feature
@@ -195,8 +226,25 @@ public final class ActionHandler<Action: Sendable, State: AnyObject, ActionResul
195226extension ActionHandler {
196227 /// Adds error handling to the action processing pipeline.
197228 ///
229+ /// The error handler receives any errors thrown during action processing
230+ /// and can update state accordingly (e.g., setting error messages, resetting loading flags).
231+ ///
198232 /// - Parameter errorHandler: A closure that handles errors
199233 /// - Returns: A new ActionHandler with error handling
234+ ///
235+ /// - Note: If you call `onError` multiple times, only the **last** handler will be used.
236+ /// Each call replaces the previous error handler.
237+ ///
238+ /// ## Example
239+ /// ```swift
240+ /// ActionHandler { action, state in
241+ /// // action processing
242+ /// }
243+ /// .onError { error, state in
244+ /// state.errorMessage = error.localizedDescription
245+ /// state.isLoading = false
246+ /// }
247+ /// ```
200248 public func onError( _ errorHandler: @escaping ( Error , State ) -> Void ) -> ActionHandler <
201249 Action , State , ActionResult
202250 > {
@@ -205,8 +253,34 @@ extension ActionHandler {
205253
206254 /// Transforms the task returned by action processing.
207255 ///
256+ /// Use this to add cross-cutting concerns like logging, analytics, or monitoring
257+ /// to all tasks without modifying individual action handlers.
258+ ///
208259 /// - Parameter taskTransform: A closure that transforms the task
209260 /// - Returns: A new ActionHandler with task transformation
261+ ///
262+ /// ## Example: Add Logging to All Tasks
263+ /// ```swift
264+ /// ActionHandler { action, state in
265+ /// // action processing
266+ /// }
267+ /// .transform { task in
268+ /// switch task.operation {
269+ /// case .run(let id, let name, let operation, let onError, let cancelInFlight, let priority):
270+ /// return .run(id: id, name: name, priority: priority) { state in
271+ /// print("Task '\(name ?? id)' starting")
272+ /// let result = try await operation(state)
273+ /// print("Task '\(name ?? id)' completed")
274+ /// return result
275+ /// } onError: { error, state in
276+ /// print("Task '\(name ?? id)' failed: \(error)")
277+ /// onError?(error, state)
278+ /// }
279+ /// default:
280+ /// return task
281+ /// }
282+ /// }
283+ /// ```
210284 public func transform(
211285 _ taskTransform: @escaping ( ActionTask < Action , State , ActionResult > )
212286 -> ActionTask < Action , State , ActionResult >
@@ -216,8 +290,26 @@ extension ActionHandler {
216290
217291 /// Adds custom middleware to the action processing pipeline.
218292 ///
293+ /// Middleware is executed in the order it's added. Call `use` multiple times
294+ /// to add multiple middlewares, and they will execute sequentially.
295+ ///
219296 /// - Parameter middleware: The middleware to add
220297 /// - Returns: A new ActionHandler with the middleware added
298+ ///
299+ /// ## Example: Add Multiple Middlewares
300+ /// ```swift
301+ /// ActionHandler { action, state in
302+ /// // action processing
303+ /// }
304+ /// .use(LoggingMiddleware()) // Executes first
305+ /// .use(AnalyticsMiddleware()) // Executes second
306+ /// .use(TimingMiddleware()) // Executes third
307+ /// ```
308+ ///
309+ /// - Note: Middleware executes in **registration order**:
310+ /// - `beforeAction` hooks run in order (first → last)
311+ /// - Action logic executes
312+ /// - `afterAction` hooks run in order (first → last)
221313 public func use( _ middleware: some BaseActionMiddleware ) -> ActionHandler <
222314 Action , State , ActionResult
223315 > {
0 commit comments