Skip to content

Commit 25c1925

Browse files
committed
Refactor session configuration to use store instead of provider
- Updated documentation and examples to reflect the change from `provider` to `store` in session configuration. - Modified session handling in various integrations and examples to accommodate the new `store` attribute. - Ensured backward compatibility by adjusting session data access patterns across all relevant files.
1 parent 7ad020d commit 25c1925

27 files changed

Lines changed: 587 additions & 2716 deletions

ERROR_HANDLING.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,14 @@ The Redis store now includes:
113113
4. **Health Monitoring**: Health check methods for monitoring
114114

115115
```crystal
116-
def [](key : String) : SessionId(T)
116+
def [](key : String) : T
117117
Retry.with_retry_if(
118118
->(ex : Exception) { Retry.retryable_connection_error?(ex) },
119119
Session.config.retry_config
120120
) do
121121
if data = @client.get(prefixed(key))
122122
begin
123-
SessionId(T).from_json(data)
123+
T.from_json(data)
124124
rescue ex : JSON::ParseException
125125
Log.error { "Failed to parse session data for key #{key}: #{ex.message}" }
126126
raise SessionCorruptionException.new("Invalid JSON in session data", ex)
@@ -153,7 +153,7 @@ The memory store now includes:
153153
4. **Cleanup Methods**: Manual cleanup of expired sessions
154154

155155
```crystal
156-
def [](key : String) : SessionId(T)
156+
def [](key : String) : T
157157
if session = sessions[key]?
158158
if session.valid?
159159
session
@@ -199,11 +199,11 @@ The cookie store now includes:
199199
4. **Graceful Fallbacks**: Fallback behavior when encryption fails
200200

201201
```crystal
202-
def [](key : String) : SessionId(T)
202+
def [](key : String) : T
203203
if data = cookies[data_key]?
204204
begin
205205
payload = String.new(verify_and_decrypt(data.value))
206-
SessionId(T).from_json payload
206+
T.from_json payload
207207
rescue ex : Session::SessionEncryptionException
208208
Log.error { "Failed to decrypt session data: #{ex.message}" }
209209
raise SessionCorruptionException.new("Session data corruption detected", ex)

IMPLEMENTATION_SUMMARY.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -190,19 +190,20 @@ Session::Retry.with_retry_if(
190190
end
191191
```
192192

193-
## 🔍 Monitoring and Health Checks
193+
## Monitoring and Health Checks
194194

195195
### Health Check Methods
196196

197197
```crystal
198198
# Check Redis store health
199-
if store = session.as?(Session::RedisStore(UserSession))
200-
store.healthy?
199+
store = Session.config.store.not_nil!
200+
if redis_store = store.as?(Session::RedisStore(UserSession))
201+
redis_store.healthy?
201202
end
202203
203204
# Get memory store statistics
204-
if store = session.as?(Session::MemoryStore(UserSession))
205-
stats = store.memory_stats
205+
if memory_store = store.as?(Session::MemoryStore(UserSession))
206+
stats = memory_store.memory_stats
206207
puts "Total sessions: #{stats[:total_sessions]}"
207208
puts "Valid sessions: #{stats[:valid_sessions]}"
208209
puts "Expired sessions: #{stats[:expired_sessions]}"
@@ -213,8 +214,9 @@ end
213214

214215
```crystal
215216
# Clean up expired sessions (memory store)
216-
if store = session.as?(Session::MemoryStore(UserSession))
217-
cleaned = store.cleanup_expired
217+
store = Session.config.store.not_nil!
218+
if memory_store = store.as?(Session::MemoryStore(UserSession))
219+
cleaned = memory_store.cleanup_expired
218220
puts "Cleaned up #{cleaned} expired sessions"
219221
end
220222
```

README.md

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212

1313
| | |
1414
|---|---|
15-
| **Type-Safe** | Define sessions as Crystal structs with compile-time guarantees |
15+
| **Type-Safe** | Define sessions as Crystal classes with compile-time guarantees |
1616
| **Multiple Backends** | Cookie, Memory, Redis, or Clustered Redis—pick what fits |
1717
| **Battle-Tested Security** | AES-256 encryption, HMAC-SHA256, PBKDF2, client binding |
1818
| **Production Resilience** | Circuit breakers, retry logic, graceful degradation |
19-
| **329+ Tests** | Comprehensive coverage you can rely on |
19+
| **346 Tests** | Comprehensive coverage you can rely on |
2020

2121
---
2222

@@ -36,22 +36,21 @@ dependencies:
3636
require "session"
3737

3838
# Define your session data
39-
struct UserSession
40-
include Session::SessionData
41-
property user_id : Int64?
42-
property username : String?
39+
class UserSession < Session::Base
40+
property? authenticated : Bool = false
41+
property username : String? = nil
4342
end
4443

4544
# Configure once
4645
Session.configure do |config|
4746
config.secret = ENV["SESSION_SECRET"]
48-
config.provider = Session::MemoryStore(UserSession).provider
47+
config.store = Session::MemoryStore(UserSession).new
4948
end
5049

5150
# Create and use sessions
52-
session = Session.provider.create
53-
session.data.user_id = 42
54-
session.data.username = "alice"
51+
store = Session.config.store.not_nil!
52+
session = store.create
53+
session.username = "alice"
5554
```
5655

5756
That's it. You're ready to build.
@@ -71,17 +70,17 @@ That's it. You're ready to build.
7170

7271
```crystal
7372
# Cookie (stateless, client-side)
74-
config.provider = Session::CookieStore(UserSession).provider
73+
config.store = Session::CookieStore(UserSession).new
7574
7675
# Memory (development)
77-
config.provider = Session::MemoryStore(UserSession).provider
76+
config.store = Session::MemoryStore(UserSession).new
7877
7978
# Redis (production)
80-
config.provider = Session::RedisStore(UserSession).provider(client: Redis.new)
79+
config.store = Session::RedisStore(UserSession).new(client: Redis.new)
8180
8281
# Clustered Redis (high-scale production)
8382
config.cluster.enabled = true
84-
config.provider = Session::ClusteredRedisStore(UserSession).new(client: Redis.new)
83+
config.store = Session::ClusteredRedisStore(UserSession).new(client: Redis.new)
8584
```
8685

8786
### Security
@@ -152,7 +151,7 @@ Session.configure do |config|
152151
config.cluster.local_cache_ttl = 30.seconds
153152
config.cluster.local_cache_max_size = 10_000
154153
155-
config.provider = Session::ClusteredRedisStore(UserSession).new(
154+
config.store = Session::ClusteredRedisStore(UserSession).new(
156155
client: Redis.new(url: ENV["REDIS_URL"])
157156
)
158157
end
@@ -162,26 +161,26 @@ end
162161

163162
## API Essentials
164163

165-
### Provider Operations
164+
### Store Operations
166165

167166
```crystal
168-
provider = Session.provider
169-
170-
provider.create # New session
171-
provider.delete # Destroy session
172-
provider.regenerate_id # New ID, keep data (post-login security)
173-
provider.valid? # Check validity
174-
provider.data # Access your typed session data
175-
provider.flash # One-request flash messages
167+
store = Session.config.store.not_nil!
168+
169+
store.create # New session
170+
store.delete # Destroy session
171+
store.regenerate_id # New ID, keep data (post-login security)
172+
store.valid? # Check validity
173+
store.current_session # Access your typed session data
174+
store.flash # One-request flash messages
176175
```
177176

178177
### Session Object
179178

180179
```crystal
181-
session = provider.current_session
180+
session = store.current_session
182181
183182
session.session_id # Unique ID
184-
session.data # Your SessionData struct
183+
session.username # Your session properties directly
185184
session.valid? # Not expired?
186185
session.expired? # Past expiration?
187186
session.time_until_expiry # Remaining lifetime
@@ -192,11 +191,11 @@ session.touch # Extend expiration
192191

193192
```crystal
194193
# Set (available next request)
195-
provider.flash["notice"] = "Saved successfully"
196-
provider.flash["error"] = "Something went wrong"
194+
store.flash["notice"] = "Saved successfully"
195+
store.flash["error"] = "Something went wrong"
197196
198197
# Read (clears after access)
199-
provider.flash.now["notice"] # => "Saved successfully"
198+
store.flash.now["notice"] # => "Saved successfully"
200199
```
201200

202201
### Query & Bulk Operations
@@ -205,13 +204,13 @@ provider.flash.now["notice"] # => "Saved successfully"
205204
store = Session::MemoryStore(UserSession).new
206205
207206
# Iterate sessions
208-
store.each_session { |s| puts s.data.username }
207+
store.each_session { |s| puts s.username }
209208
210209
# Find by criteria
211-
admins = store.find_by { |s| s.data.roles.includes?("admin") }
210+
admins = store.find_by { |s| s.roles.includes?("admin") }
212211
213212
# Bulk delete (e.g., revoke compromised user)
214-
store.bulk_delete { |s| s.data.user_id == compromised_id }
213+
store.bulk_delete { |s| s.user_id == compromised_id }
215214
```
216215

217216
---
@@ -223,11 +222,13 @@ require "http/server"
223222
224223
Session.configure do |config|
225224
config.secret = ENV["SESSION_SECRET"]
226-
config.provider = Session::MemoryStore(UserSession).provider
225+
config.store = Session::MemoryStore(UserSession).new
227226
end
228227
228+
store = Session.config.store.not_nil!
229+
229230
server = HTTP::Server.new([
230-
Session::SessionHandler.new(Session.provider),
231+
Session::SessionHandler.new(store),
231232
YourAppHandler.new,
232233
])
233234
@@ -269,8 +270,8 @@ Session.configure do |config|
269270
config.cluster.local_cache_max_size = 10_000
270271
271272
# Callbacks
272-
config.on_started = ->(id, data) { Log.info { "Session #{id} created" } }
273-
config.on_deleted = ->(id, data) { Log.info { "Session #{id} destroyed" } }
273+
config.on_started = ->(id : String, session : Session::Base) { Log.info { "Session #{id} created" } }
274+
config.on_deleted = ->(id : String, session : Session::Base) { Log.info { "Session #{id} destroyed" } }
274275
275276
# Metrics
276277
config.metrics_backend = Session::Metrics::LogBackend.new
@@ -290,6 +291,7 @@ Full documentation available at [GitBook](https://azutoolkit.gitbook.io/session)
290291
- [Security Best Practices](docs/configuration/security.md)
291292
- [AZU Framework Integration](docs/integrations/azu-framework.md)
292293
- [HTTP::Server Integration](docs/integrations/http-server.md)
294+
- [Upgrade Guide](UPGRADE.md)
293295

294296
---
295297

0 commit comments

Comments
 (0)