Skip to content

Commit 224eb46

Browse files
committed
refactor!: prepare for v1.0.0 - rename @Prefix to @action_prefix and unify dispatch API
BREAKING CHANGES: 1. Renamed @Prefix to @action_prefix in reducer system - All reducer modules must update from @Prefix to @action_prefix - @action_prefix can be nil or "" for catch-all reducers - Generated function renamed: __reducer_prefix__ → __reducer_action_prefix__ 2. Changed dispatch return values to :ok - dispatch/3 now returns :ok instead of {:ok, state} - dispatch_async/3 now returns :ok instead of {:ok, state} - All dispatches are now async (fire-and-forget) - Use get_state/1-2 to retrieve state after dispatch 3. Added dispatch_async/3 function - New explicit async dispatch function for clarity - Same behavior as dispatch/3 but clearer intent MIGRATION: For @Prefix rename: - Find: @Prefix - Replace: @action_prefix For dispatch return values: - Find: {:ok, state} = SessionProcess.dispatch(...) - Replace: :ok = SessionProcess.dispatch(...) - Add: state = SessionProcess.get_state(session_id) Files changed: - lib/phoenix/session_process.ex - lib/phoenix/session_process/redux/reducer_compiler.ex - test/phoenix/session_process/dispatch_test.exs - test/phoenix/session_process/reducer_integration_test.exs - README.md - CLAUDE.md - CHANGELOG.md New documentation: - V1_0_0_PREPARATION.md - Comprehensive v1.0.0 preparation guide - REDUCER_IMPROVEMENTS.md - Reducer system improvement tracking All 264 tests passing.
1 parent a987113 commit 224eb46

File tree

9 files changed

+983
-148
lines changed

9 files changed

+983
-148
lines changed

CHANGELOG.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,90 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased] - v1.0.0
9+
10+
### Breaking Changes
11+
12+
- **Renamed `@prefix` to `@action_prefix` in reducer modules**
13+
- All reducer modules must now use `@action_prefix` instead of `@prefix`
14+
- The `@action_prefix` can be `nil` or `""` to create catch-all reducers that handle all actions
15+
- Migration: Simply rename `@prefix` to `@action_prefix` in your reducer modules
16+
- Example:
17+
```elixir
18+
# Before (v0.x)
19+
defmodule MyReducer do
20+
use Phoenix.SessionProcess, :reducer
21+
@name :my_reducer
22+
@prefix "my" # Old name
23+
end
24+
25+
# After (v1.0.0)
26+
defmodule MyReducer do
27+
use Phoenix.SessionProcess, :reducer
28+
@name :my_reducer
29+
@action_prefix "my" # New name
30+
end
31+
```
32+
33+
- **Changed `dispatch/3` and `dispatch_async/3` return values**
34+
- Both functions now return `:ok` instead of `{:ok, new_state}`
35+
- All dispatches are now async (fire-and-forget) by default
36+
- Use `get_state/1-2` to retrieve state after dispatch
37+
- Migration:
38+
```elixir
39+
# Before (v0.x)
40+
{:ok, new_state} = SessionProcess.dispatch(session_id, :increment)
41+
IO.inspect(new_state)
42+
43+
# After (v1.0.0)
44+
:ok = SessionProcess.dispatch(session_id, :increment)
45+
new_state = SessionProcess.get_state(session_id)
46+
IO.inspect(new_state)
47+
```
48+
49+
- **Removed deprecated `Phoenix.SessionProcess.Redux` module**
50+
- The old struct-based Redux API has been removed
51+
- Use the Redux Store API (built into SessionProcess) instead
52+
- See migration guide: `REDUX_TO_SESSIONPROCESS_MIGRATION.md`
53+
54+
### Added
55+
56+
- **`dispatch_async/3` function for explicit async dispatch**
57+
- Same behavior as `dispatch/3` but with clearer naming for async operations
58+
- Makes code intent more explicit when dispatching async actions
59+
- Example: `:ok = SessionProcess.dispatch_async(session_id, :increment)`
60+
61+
### Changed
62+
63+
- **Improved action routing with `@action_prefix`**
64+
- More consistent naming aligns with action routing semantics
65+
- Catch-all reducers now explicitly use `nil` or `""` for `@action_prefix`
66+
- Better documentation and examples for action routing
67+
68+
### Migration Guide
69+
70+
1. **Rename `@prefix` to `@action_prefix` in all reducer modules**
71+
- Search your codebase for `@prefix` in reducer modules
72+
- Replace with `@action_prefix`
73+
- No logic changes required
74+
75+
2. **Update dispatch call sites to handle `:ok` return value**
76+
- Replace `{:ok, state} = dispatch(...)` with `:ok = dispatch(...)`
77+
- Add `get_state(session_id)` calls where you need the updated state
78+
- Consider: Do you actually need the state? Many dispatches are fire-and-forget
79+
80+
3. **Remove uses of deprecated Redux module**
81+
- If using `Phoenix.SessionProcess.Redux` struct-based API
82+
- Migrate to Redux Store API (SessionProcess IS the store)
83+
- See `REDUX_TO_SESSIONPROCESS_MIGRATION.md` for detailed migration
84+
85+
### Notes
86+
87+
- All changes are breaking but migrations are straightforward
88+
- Most codebases will only need to rename `@prefix` to `@action_prefix`
89+
- Dispatch return value change makes async nature more explicit
90+
- v0.9.x will be the last version supporting deprecated APIs
91+
892
## [0.6.0] - 2025-10-29
993

1094
### Added

CLAUDE.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,8 @@ session_id = conn.assigns.session_id
277277
# Start session
278278
Phoenix.SessionProcess.start(session_id, MyApp.SessionProcess)
279279

280-
# Register reducer
281-
reducer = fn state, action ->
280+
# Register reducer (note: first parameter is action, second is state)
281+
reducer = fn action, state ->
282282
case action do
283283
:increment -> %{state | count: state.count + 1}
284284
{:set_user, user} -> %{state | user: user}
@@ -288,8 +288,11 @@ end
288288

289289
Phoenix.SessionProcess.register_reducer(session_id, :main, reducer)
290290

291-
# Dispatch actions
292-
{:ok, new_state} = Phoenix.SessionProcess.dispatch(session_id, :increment)
291+
# Dispatch actions (returns :ok, all dispatches are async)
292+
:ok = Phoenix.SessionProcess.dispatch(session_id, :increment)
293+
294+
# Get state after dispatch
295+
state = Phoenix.SessionProcess.get_state(session_id)
293296
```
294297

295298
**LiveView (NEW API):**
@@ -366,16 +369,19 @@ SessionProcess itself is a Redux store with built-in infrastructure:
366369
# Define initial state
367370
def user_init(_), do: %{count: 0}
368371
369-
# Register reducer
370-
SessionProcess.register_reducer(session_id, :counter, fn state, action ->
372+
# Register reducer (note: first parameter is action, second is state)
373+
SessionProcess.register_reducer(session_id, :counter, fn action, state ->
371374
case action do
372375
:increment -> %{state | count: state.count + 1}
373376
_ -> state
374377
end
375378
end)
376379
377-
# Dispatch actions
378-
{:ok, new_state} = SessionProcess.dispatch(session_id, :increment)
380+
# Dispatch actions (returns :ok)
381+
:ok = SessionProcess.dispatch(session_id, :increment)
382+
383+
# Get state after dispatch
384+
state = SessionProcess.get_state(session_id)
379385
380386
# Subscribe with selector
381387
{:ok, sub_id} = SessionProcess.subscribe(

README.md

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ end
147147

148148
Phoenix.SessionProcess now includes built-in Redux functionality - **SessionProcess IS the Redux store**. No need to manage separate Redux structs or manual state updates.
149149

150+
> **Note**: v1.0.0 is coming soon with enhanced reducer routing and action normalization. See CHANGELOG.md for details.
151+
150152
#### Session Process as Redux Store
151153

152154
```elixir
@@ -163,7 +165,7 @@ end
163165
{:ok, _pid} = Phoenix.SessionProcess.start(session_id, MyApp.SessionProcess)
164166

165167
# Register a reducer
166-
reducer = fn state, action ->
168+
reducer = fn action, state ->
167169
case action do
168170
{:set_user, user} -> %{state | user: user}
169171
:increment -> %{state | count: state.count + 1}
@@ -173,11 +175,14 @@ end
173175

174176
Phoenix.SessionProcess.register_reducer(session_id, :main, reducer)
175177

176-
# Dispatch actions (synchronous)
177-
{:ok, new_state} = Phoenix.SessionProcess.dispatch(session_id, {:set_user, %{id: 123, name: "Alice"}})
178+
# Dispatch actions (all dispatches are async and return :ok)
179+
:ok = Phoenix.SessionProcess.dispatch(session_id, {:set_user, %{id: 123, name: "Alice"}})
180+
181+
# Or use dispatch_async for clarity (same behavior)
182+
:ok = Phoenix.SessionProcess.dispatch_async(session_id, :increment)
178183

179-
# Dispatch actions (asynchronous)
180-
:ok = Phoenix.SessionProcess.dispatch(session_id, :increment, async: true)
184+
# Get state after dispatch
185+
state = Phoenix.SessionProcess.get_state(session_id)
181186

182187
# Subscribe to state changes
183188
Phoenix.SessionProcess.subscribe(
@@ -405,8 +410,8 @@ end
405410
The built-in Redux Store API provides state management with actions, reducers, and subscriptions:
406411

407412
```elixir
408-
# Register a reducer
409-
reducer = fn state, action ->
413+
# Register a reducer (note: first parameter is action, second is state)
414+
reducer = fn action, state ->
410415
case action do
411416
{:set_user, user} -> %{state | user: user}
412417
:increment -> %{state | count: state.count + 1}
@@ -416,17 +421,17 @@ end
416421

417422
Phoenix.SessionProcess.register_reducer(session_id, :main_reducer, reducer)
418423

419-
# Dispatch actions (synchronous - returns new state)
420-
{:ok, new_state} = Phoenix.SessionProcess.dispatch(session_id, {:set_user, %{id: 123}})
424+
# Dispatch actions (all dispatches return :ok and are async)
425+
:ok = Phoenix.SessionProcess.dispatch(session_id, {:set_user, %{id: 123}})
421426

422-
# Dispatch actions (asynchronous - fire and forget)
423-
:ok = Phoenix.SessionProcess.dispatch(session_id, :increment, async: true)
427+
# Or use dispatch_async for clarity (same behavior)
428+
:ok = Phoenix.SessionProcess.dispatch_async(session_id, :increment)
424429

425-
# Get current state
426-
{:ok, state} = Phoenix.SessionProcess.get_state(session_id)
430+
# Get current state after dispatch
431+
state = Phoenix.SessionProcess.get_state(session_id)
427432

428433
# Get state with selector
429-
{:ok, user} = Phoenix.SessionProcess.get_state(session_id, fn state -> state.user end)
434+
user = Phoenix.SessionProcess.get_state(session_id, fn state -> state.user end)
430435

431436
# Subscribe to state changes (with selector)
432437
{:ok, sub_id} = Phoenix.SessionProcess.subscribe(
@@ -449,7 +454,7 @@ user_name_selector = fn state -> state.user && state.user.name end
449454
:ok = Phoenix.SessionProcess.register_selector(session_id, :user_name, user_name_selector)
450455

451456
# Use registered selector
452-
{:ok, name} = Phoenix.SessionProcess.select(session_id, :user_name)
457+
name = Phoenix.SessionProcess.select(session_id, :user_name)
453458
```
454459

455460
**Key Features:**

0 commit comments

Comments
 (0)