You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
DSL-configured shutdown_after and hibernate_after options were ignored at runtime — processes never shut down even when shutdown_after was set in the options block. The values were stored for introspection but never read during process startup. Server.init/1 and Server.start_link/1 now fall back to the module's DSL-configured values when options are not explicitly passed.
Added
Built-in state.id field on every object's State struct, automatically set to the object's ID at init time
Available in handlers, after_load, and handle_alarm callbacks
Not persisted to the database — it's runtime metadata, not domain state
Defaults to nil in test helpers like perform_handler/4 (set it yourself if your handler reads state.id)
Auto-generated DSL reference documentation via mix spark.cheat_sheets
mix docs alias now chains spark.cheat_sheets → docs → spark.replace_doc_links
CI check to verify DSL documentation is up-to-date (mix spark.cheat_sheets --check)
Changed
Breaking:field :id is now a reserved name and will raise a compile-time error. If you have an existing field :id in your state block, rename it (e.g., to :external_id or :resource_id) before upgrading.
State is now returned as a struct (%MyApp.Counter.State{count: 0}) instead of a plain atom-keyed map (%{count: 0})
The DSL automatically generates a nested State struct module from the declared fields and defaults
%{state | field: value} update syntax continues to work unchanged
State is persisted to the database as a plain JSON map (no __struct__ key)
Unknown keys in persisted state are silently dropped on load (forward-compatible with field removal)
get_persisted_state/3 in DurableObject.Testing now returns the module's State struct
Breaking:state[:field] bracket access no longer works — use state.field dot access instead