Chaining actions
For one logical operation, put sequential steps in one runner. The flow then holds one busy lock and emits one final result.
const flow = useSubmitFlow({
createAndNotify: {
run: async (input: { email: string }, { signal, throwIfCancelled }) => {
const account = await createAccount(input, { signal });
throwIfCancelled();
await sendWelcomeEmail(account.id, { signal });
return account;
},
},
});
Use separate run() calls when the second action depends on inspecting the first result. Start the next call after the first promise settles; a same-flow call from inside its own runner is skipped as busy.
const created = await flow.run("create", values);
if (created.status === "success") {
await flow.run("notify", { accountId: created.data.id });
}
Failures do not undo side effects from earlier steps. Add application-owned compensation when the domain requires it. See the chaining example.