Skip to content

0.4.0

Latest

Choose a tag to compare

@pfriedrix pfriedrix released this 24 Apr 23:31

The big theme of 0.4.0 is collapsing the effect pipeline onto MainActor and tightening the concurrency contract. The store no longer owns a lock, an actor, or a driver task — isolation alone provides ordering. As a side effect, Send is now properly async.

Breaking changes

  • Send is now async. Inside .run effect bodies you must await send(.action). Callers no longer spawn a Task per dispatch; the await hops to MainActor and returns when the dispatch is complete.

    // before
    return .run { send in
        let data = await fetchData()
        send(.updateData(data))
    }
    
    // after
    return .run { send in
        let data = await fetchData()
        await send(.updateData(data))
    }
  • @Shared.wrappedValue is read-only. The setter was unused and only created the illusion that you could rebind a shared store. For test-time overrides, use StoreValues.withValues { ... } instead.

  • Effect pipeline is fully MainActor-isolated. .run register/cancel and .cancel(id:) now happen synchronously on MainActor, so a cancel dispatched in the same send chain as a .cancellable(id:) is guaranteed to observe its registration. The internal driver actor and lock are gone.

Fixed

  • .animation(nil) now actually clears any attached animation.
  • Persistence no longer wipes stored data on encode/decode failure — the blob is preserved so a future migration can read it.
  • Store.cancel(id:) logs on miss instead of silently no-oping.
  • Eliminated a register/cancel race in the effect lifecycle.

Concurrency & tooling

  • Single Package.swift with swiftLanguageModes: [.v6].
  • Swift 7 upcoming features enabled across all targets (ExistentialAny, InternalImportsByDefault, MemberImportVisibility, InferIsolatedConformances, NonisolatedNonsendingByDefault).
  • Bumped swift-syntax to 603.0.1 for Swift 6.2 toolchains.

Internal

  • Store.tasks is now private(set).
  • KeyPath resolution routes through StoreValues.current(_:).
  • Dropped redundant lock in StoreValues — MainActor isolation is enough.
  • Removed empty deinit and clarified willSave is internal Storable plumbing.

Docs

  • Full README rewrite against the 0.4.0 API.
  • @Inject docblock spells out the expansion contract and the __Store_<name> peer naming.
  • Binding capture policy (strong getter / weak setter) documented and pinned with regression tests.

CI

  • GitHub Actions workflow: swift build + swift test on macos-26 for every PR and push to master.

Tests

  • SwiftUI rendering baseline using real hosted views, plus negative-invariant coverage.
  • Coverage for previously untested public API surfaces.
  • Cleaned up flaky Task.sleep-based waits.

Full Changelog: 0.3.2...0.4.0