Skip to content

Commit 226cdd9

Browse files
mbrandonwp4checo
authored andcommitted
Fix 0.48.1 cherry pick
## Changes Previous 0.48.1 cherry pick somehow wasn't properly done (possibly due to `git rerere`) and some changes were missing. This commit contains all upstream changes from 0.47.2 ... 0.48.1 which were then reapplied on top of `master`. This should hopefully now include all changes. To avoid issues with `git rerere` I cleared its cache before doing this operation. ## Automatic git commit (cherry picked from commit 1c19319aed7ab85e10e07de570f6160e46140d2b) Apostrocide. (#1701) (cherry picked from commit 937a716d1af205f5e9b6f512c88012d7ad3e3f02) Typo (#1702) wow! (cherry picked from commit 1c50ffcf440de19e15e3a8b94e7347df0895a6ce) Base `OpenURL` dependency on SwiftUI (#1714) * Base `OpenURL` dependency on SwiftUI * indent (cherry picked from commit fbd70bf4d01284a9788d88cba4b6c70827f104e4) Fix ButtonRole and Button deprecations (#1715) Replaced AlertState<Action>.ButtonRole with ButtonState<Action>.Role Replaced AlertState<Action>.Button with ButtonState<Action> (cherry picked from commit 907eb1866a9de2c506a05edee9d277b856a7171c) # Conflicts: # Package.resolved Run swift-format (cherry picked from commit f56a0d1973d92fa82066ed3bd7f9ba7375fca5fe) add await (#1725) (cherry picked from commit 47465c3f265cf058447c32c58a6676216ed76590) # Conflicts: # Sources/Dependencies/Dependencies/MainQueue.swift Fix a possible typo (#1762) (cherry picked from commit d0b1444393d9e209307dcad066cb8d19a667eda9) Bump SwiftUINavigation and update examples (#1760) * bump navigation * bump swiftui-navigation * Add SearchView preview * make login sendable * use button state builder * format * bump swift and platform version * remove unused test clock * Add quotes to scheme (cherry picked from commit fe5603ec380e2a312cbf8ff45e12e81eea5c072b) Fix minor document error (#1764) (cherry picked from commit b555bfeac62c8c95cb54b002442bb8068aa99311) Fix code typo (#1773) Signed-off-by: Daeyoung Kim <[email protected]> Signed-off-by: Daeyoung Kim <[email protected]> (cherry picked from commit 315d935fcd2021828310294c2d85fc747f3de332) Update latest version documentation link. (#1776) (cherry picked from commit 43291b21dc24e1981d2bc8e1b715a5ce733c3e23) Add @_unsafeInheritExecutor to withTaskCancellation(id:) (#1779) * Add @_unsafeInheritExecutor to withTaskCancellation(id:) * wip (cherry picked from commit 48f0cc66000a23690ebbd7b65ea57fb7e7769825) # Conflicts: # Sources/ComposableArchitecture/Effects/Cancellation.swift resolve binding key path crash (#1784) (cherry picked from commit fbe68471a3cf4eef6f0501d07642ee70b5bc3e84) # Conflicts: # Sources/ComposableArchitecture/ViewStore.swift Run swift-format (cherry picked from commit 8f19bf88aeb67c33e41e14eefa30f9074ddca013) Simplify/fix #1784 (#1785) * Simplify/fix #1784 This PR works on top of #1784 and: * Reduces the number of moving parts * Restores implicit animations by directly producing the binding from the observable object * Strongly retains the store in the binding to avoid losing writes * Move (cherry picked from commit 626c35c7dea962bd3246e1f019d91cbfe419e695) Make TestStore.receive actually match the action predicate (#1780) * Assert that TestStore.receive(...) actually calls its predicate * Fix TestStore.receive to respect its action predicate * Update TestStore failure tests to use new description strings (cherry picked from commit 5f294b9dc9a047b1e6b6766752da2856a158750e) # Conflicts: # Tests/ComposableArchitectureTests/TestStoreTests.swift Run swift-format (cherry picked from commit 5a8df942237aa1ff59b7abccfe18bff74d1bbe4a) Fix TestStore docs (#1787) * Fix TestStore docs * fix * wip (cherry picked from commit ea9cc86779038a0e1d38aa080bdc636e236190b6) # Conflicts: # Sources/ComposableArchitecture/TestStore.swift Deprecate 'Effect' for 'EffectTask' (#1788) * Deprecate 'Effect' for 'EffectTask' This is to allow reclaiming 'Effect' at a later time without the 'Failure' generic in the near future. * wip (cherry picked from commit 32f967c0b84099e29dc5bce062aa9f45493d2688) # Conflicts: # Sources/ComposableArchitecture/Effect.swift Soft-deprecate EffectPublisher (#1791) * Soft-deprecate EffectPublisher in favor of EffectTask. * wip (cherry picked from commit 4266744f047734de8eb8bc73730d7f7d25cbd775) # Conflicts: # Sources/ComposableArchitecture/Documentation.docc/ComposableArchitecture.md # Sources/ComposableArchitecture/Documentation.docc/Extensions/Effect.md # Sources/ComposableArchitecture/Effect.swift Run swift-format (cherry picked from commit ce196d7c152172cc924dcc875338a6459fcd568a) Deprecate async version of withValue and introduce sync version. (#1792) (cherry picked from commit 5eedf980b72dd6fcd3a65c01dfd644a929d2223b) # Conflicts: # Sources/ComposableArchitecture/Effects/ConcurrencySupport.swift # Sources/ComposableArchitecture/Internal/Deprecations.swift Run swift-format (cherry picked from commit ad714bacb9dd1b3addfb27d5021ca8ad33b62009) Wrong cancel id on testNestedCancels (#1793) (cherry picked from commit 1a65878210b8bfccc7c73436718195582562c314) # Conflicts: # Tests/ComposableArchitectureTests/EffectCancellationTests.swift Allow `BindingReducer` to work with `ViewState` (#1790) * Simpler bindable view state * wip * wip * Remove `BindingStore` * wip * wip * wip * wip * wip * wip * wip * wip * wip * Make BindingState conditionally sendable. * Fixed tests * Update bindings article * Add some additional contextual information to the runtime warnings * update some docs * lots more docs * test clean up * Improve diagnostic * Put back `BindingReducer()` in the form study * clean up * Improve DocC references * Remove DocC references for `@`'d property wrappers. * wip Co-authored-by: Stephen Celis <[email protected]> Co-authored-by: Brandon Williams <[email protected]> (cherry picked from commit c719fa1d3921533f25a6aa6c41016ce5d41a250d) # Conflicts: # Sources/ComposableArchitecture/Internal/Deprecations.swift # Sources/ComposableArchitecture/SwiftUI/Binding.swift # Tests/ComposableArchitectureTests/BindingTests.swift # Tests/ComposableArchitectureTests/DebugTests.swift Run swift-format (cherry picked from commit d1c2e5b6d1c4e3b2f46c4fa1983b6ed4acab9173) Revert #1790 (#1795) It occurred to us that this solution unfortunately is incompatible with view actions. We have an alternate solution that works, so I'll PR that in the future if no others materialize! (cherry picked from commit 30015d13a3ca0988b4674a83eccebbea747fe1f8) # Conflicts: # Sources/ComposableArchitecture/Internal/Deprecations.swift # Sources/ComposableArchitecture/SwiftUI/Binding.swift Revert #1784: Resolve binding key path crash (#1799) * Revert "Simplify/fix #1784 (#1785)" This reverts commit 626c35c7dea962bd3246e1f019d91cbfe419e695. * Revert "resolve binding key path crash (#1784)" This reverts commit fbe68471a3cf4eef6f0501d07642ee70b5bc3e84. (cherry picked from commit cbf8a45fa97ca4afb858f6cd99730bb67952813a) # Conflicts: # Sources/ComposableArchitecture/ViewStore.swift
1 parent a95532b commit 226cdd9

File tree

16 files changed

+389
-334
lines changed

16 files changed

+389
-334
lines changed

Examples/CaseStudies/SwiftUICaseStudies/01-GettingStarted-FocusState.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ struct FocusDemoView: View {
5757
VStack {
5858
TextField("Username", text: viewStore.binding(\.$username))
5959
.focused($focusedField, equals: .username)
60-
6160
SecureField("Password", text: viewStore.binding(\.$password))
6261
.focused($focusedField, equals: .password)
6362
Button("Sign In") {

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/ComposableArchitecture/Documentation.docc/ComposableArchitecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
### State management
1414

1515
- ``ReducerProtocol``
16-
- ``EffectProducer``
16+
- ``EffectTask``
1717
- ``Store``
1818
- ``ViewStore``
1919

Sources/ComposableArchitecture/Documentation.docc/Extensions/Deprecations/SwiftUIDeprecations.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,5 @@ Avoid using deprecated APIs in your app. Select a method to see the replacement
3333
- ``WithViewStore/Action``
3434
- ``WithViewStore/State``
3535

36-
### View state
37-
38-
- ``ActionSheetState``
39-
4036
<!--DocC: Can't currently document `View` extensions-->
4137
<!--### View Modifiers-->

Sources/ComposableArchitecture/Documentation.docc/Extensions/Effect.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,39 @@
1-
# ``ComposableArchitecture/EffectProducer``
1+
# ``ComposableArchitecture/EffectTask``
22

33
## Topics
44

55
### Creating an effect
66

7-
- ``none``
8-
- ``task(priority:operation:catch:file:fileID:line:)``
9-
- ``run(priority:operation:catch:file:fileID:line:)``
10-
- ``fireAndForget(priority:_:)``
7+
- ``EffectProducer/none``
8+
- ``EffectProducer/task(priority:operation:catch:file:fileID:line:)``
9+
- ``EffectProducer/run(priority:operation:catch:file:fileID:line:)``
10+
- ``EffectProducer/fireAndForget(priority:_:)``
1111
- ``TaskResult``
1212

1313
### Cancellation
1414

15-
- ``cancellable(id:cancelInFlight:)-29q60``
16-
- ``cancel(id:)-6hzsl``
17-
- ``cancel(ids:)-1cqqx``
15+
- ``EffectProducer/cancellable(id:cancelInFlight:)-29q60``
16+
- ``EffectProducer/cancel(id:)-6hzsl``
17+
- ``EffectProducer/cancel(ids:)-1cqqx``
1818
- ``withTaskCancellation(id:cancelInFlight:operation:)-4dtr6``
1919

2020
### Composition
2121

22-
- ``map(_:)-yn70``
23-
- ``merge(_:)-45guh``
24-
- ``merge(_:)-3d54p``
22+
- ``EffectProducer/map(_:)-yn70``
23+
- ``EffectProducer/merge(_:)-45guh``
24+
- ``EffectProducer/merge(_:)-3d54p``
2525

2626
### Concurrency
2727

2828
- ``UncheckedSendable``
2929

3030
### Testing
3131

32-
- ``unimplemented(_:)``
32+
- ``EffectProducer/unimplemented(_:)``
3333

3434
### SwiftUI integration
3535

36-
- ``animation(_:)``
36+
- ``EffectProducer/animation(_:)``
3737

3838
### Deprecations
3939

Sources/ComposableArchitecture/Documentation.docc/Extensions/TestStore.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
### Creating a test store
66

7-
- ``init(initialState:reducer:file:line:)``
7+
- ``init(initialState:reducer:prepareDependencies:file:line:)``
88

99
### Configuring a test store
1010

@@ -18,7 +18,7 @@
1818
- ``receive(_:timeout:assert:file:line:)-1rwdd``
1919
- ``receive(_:timeout:assert:file:line:)-4e4m0``
2020
- ``receive(_:timeout:assert:file:line:)-3myco``
21-
- ``finish(timeout:file:line:)``
21+
- ``finish(timeout:file:line:)-53gi5``
2222
- ``TestStoreTask``
2323

2424
### Methods for skipping actions and effects

Sources/ComposableArchitecture/Effect.swift

Lines changed: 85 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,55 @@ import XCTestDynamicOverlay
66
import SwiftUI
77
#endif
88

9-
/// A type that encapsulates a unit of work that can be run in the outside world, and can feed
10-
/// actions back to the ``Store``.
11-
///
12-
/// Effects are the perfect place to do side effects, such as network requests, saving/loading
13-
/// from disk, creating timers, interacting with dependencies, and more. They are returned from
14-
/// reducers so that the ``Store`` can perform the effects after the reducer is done running.
15-
///
16-
/// There are 2 distinct ways to create an `Effect`: one using Swift's native concurrency tools, and
17-
/// the other using ReactiveSwift framework:
18-
///
19-
/// * If using Swift's native structured concurrency tools then there are 3 main ways to create an
20-
/// effect, depending on if you want to emit one single action back into the system, or any number
21-
/// of actions, or just execute some work without emitting any actions:
22-
/// * ``EffectProducer/task(priority:operation:catch:file:fileID:line:)``
23-
/// * ``EffectProducer/run(priority:operation:catch:file:fileID:line:)``
24-
/// * ``EffectProducer/fireAndForget(priority:_:)``
25-
/// * If using ReactiveSwift in your application, in particular for the dependencies of your feature
26-
/// then you can create effects by making use of any of ReactiveSwift's operators, and then erasing the
27-
/// publisher type to ``EffectProducer`` with either `eraseToEffect` or `catchToEffect`. Note that
28-
/// the ReactiveSwift interface to ``EffectProducer`` is considered soft deprecated, and you should
29-
/// eventually port to Swift's native concurrency tools.
30-
///
31-
/// > Important: ``Store`` is not thread safe, and so all effects must receive values on the same
32-
/// thread. This is typically the main thread, **and** if the store is being used to drive UI then
33-
/// it must receive values on the main thread.
34-
/// >
35-
/// > This is only an issue if using the ReactiveSwift interface of ``EffectProducer`` as mentioned
36-
/// above. If you are using Swift's concurrency tools and the `.task`, `.run` and `.fireAndForget`
37-
/// functions on ``EffectTask``, then threading is automatically handled for you.
9+
/// This type is deprecated in favor of ``EffectTask``. See its documentation for more information.
10+
@available(
11+
iOS,
12+
deprecated: 9999.0,
13+
message:
14+
"""
15+
'EffectProducer' has been deprecated in favor of 'EffectTask'.
16+
17+
You are encouraged to use `EffectTask<Action>` to model the ouput of your reducers, and to use Swift concurrency to model asynchrony in dependencies.
18+
19+
See the migration roadmap for more information: https://github.com/pointfreeco/swift-composable-architecture/discussions/1477
20+
"""
21+
)
22+
@available(
23+
macOS,
24+
deprecated: 9999.0,
25+
message:
26+
"""
27+
'EffectProducer' has been deprecated in favor of 'EffectTask'.
28+
29+
You are encouraged to use `EffectTask<Action>` to model the ouput of your reducers, and to use Swift concurrency to model asynchrony in dependencies.
30+
31+
See the migration roadmap for more information: https://github.com/pointfreeco/swift-composable-architecture/discussions/1477
32+
"""
33+
)
34+
@available(
35+
tvOS,
36+
deprecated: 9999.0,
37+
message:
38+
"""
39+
'EffectProducer' has been deprecated in favor of 'EffectTask'.
40+
41+
You are encouraged to use `EffectTask<Action>` to model the ouput of your reducers, and to use Swift concurrency to model asynchrony in dependencies.
42+
43+
See the migration roadmap for more information: https://github.com/pointfreeco/swift-composable-architecture/discussions/1477
44+
"""
45+
)
46+
@available(
47+
watchOS,
48+
deprecated: 9999.0,
49+
message:
50+
"""
51+
'EffectProducer' has been deprecated in favor of 'EffectTask'.
52+
53+
You are encouraged to use `EffectTask<Action>` to model the ouput of your reducers, and to use Swift concurrency to model asynchrony in dependencies.
54+
55+
See the migration roadmap for more information: https://github.com/pointfreeco/swift-composable-architecture/discussions/1477
56+
"""
57+
)
3858
public struct EffectProducer<Action, Failure: Error> {
3959
@usableFromInline
4060
enum Operation {
@@ -63,20 +83,38 @@ extension EffectProducer {
6383
}
6484
}
6585

66-
/// A convenience type alias for referring to an effect that can never fail, like the kind of
67-
/// ``EffectProducer`` returned by a reducer after processing an action.
86+
/// A type that encapsulates a unit of work that can be run in the outside world, and can feed
87+
/// actions back to the ``Store``.
6888
///
69-
/// Instead of specifying `Never` as `Failure`:
89+
/// Effects are the perfect place to do side effects, such as network requests, saving/loading
90+
/// from disk, creating timers, interacting with dependencies, and more. They are returned from
91+
/// reducers so that the ``Store`` can perform the effects after the reducer is done running.
7092
///
71-
/// ```swift
72-
/// func reduce(into state: inout State, action: Action) -> EffectProducer<Action, Never> { … }
73-
/// ```
93+
/// There are 2 distinct ways to create an `Effect`: one using Swift's native concurrency tools, and
94+
/// the other using Apple's Combine framework:
7495
///
75-
/// You can specify a single generic:
96+
/// * If using Swift's native structured concurrency tools then there are 3 main ways to create an
97+
/// effect, depending on if you want to emit one single action back into the system, or any number
98+
/// of actions, or just execute some work without emitting any actions:
99+
/// * ``EffectProducer/task(priority:operation:catch:file:fileID:line:)``
100+
/// * ``EffectProducer/run(priority:operation:catch:file:fileID:line:)``
101+
/// * ``EffectProducer/fireAndForget(priority:_:)``
102+
/// * If using Combine in your application, in particular for the dependencies of your feature
103+
/// then you can create effects by making use of any of Combine's operators, and then erasing the
104+
/// publisher type to ``EffectProducer`` with either `eraseToEffect` or `catchToEffect`. Note that
105+
/// the Combine interface to ``EffectProducer`` is considered soft deprecated, and you should
106+
/// eventually port to Swift's native concurrency tools.
76107
///
77-
/// ```swift
78-
/// func reduce(into state: inout State, action: Action) -> EffectTask<Action> { … }
79-
/// ```
108+
/// > Important: The publisher interface to ``EffectTask`` is considered deperecated, and you should
109+
/// try converting any uses of that interface to Swift's native concurrency tools.
110+
/// >
111+
/// > Also, ``Store`` is not thread safe, and so all effects must receive values on the same
112+
/// thread. This is typically the main thread, **and** if the store is being used to drive UI then
113+
/// it must receive values on the main thread.
114+
/// >
115+
/// > This is only an issue if using the Combine interface of ``EffectProducer`` as mentioned
116+
/// above. If you are using Swift's concurrency tools and the `.task`, `.run` and `.fireAndForget`
117+
/// functions on ``EffectTask``, then threading is automatically handled for you.
80118
public typealias EffectTask<Action> = Effect<Action, Never>
81119

82120
extension EffectProducer where Failure == Never {
@@ -614,57 +652,20 @@ extension EffectProducer {
614652
}
615653

616654
@available(
617-
iOS,
618-
deprecated: 9999.0,
655+
*,
619656
message:
620657
"""
621-
'Effect' has been deprecated in favor of 'EffectTask' when `Failure == Never`, or
622-
`EffectProducer<Output, Failure>` in general.
658+
'Effect' has been deprecated in favor of 'EffectTask' when 'Failure == Never', or 'EffectProducer<Output, Failure>' in general.
623659
624-
You are encouraged to use `EffectTask<Action>` to model the ouput of your reducers, and to Swift
625-
concurrency to model failable streams of values.
660+
You are encouraged to use 'EffectTask<Action>' to model the output of your reducers, and to use Swift concurrency to model failable streams of values.
626661
627-
See the migration roadmap for more information: https://github.com/pointfreeco/swift-composable-architecture/discussions/1477
628-
"""
629-
)
630-
@available(
631-
macOS,
632-
deprecated: 9999.0,
633-
message:
634-
"""
635-
'Effect' has been deprecated in favor of 'EffectTask' when `Failure == Never`, or
636-
`EffectProducer<Output, Failure>` in general.
637-
638-
You are encouraged to use `EffectTask<Action>` to model the ouput of your reducers, and to Swift
639-
concurrency to model failable streams of values.
662+
To find and replace instances of 'Effect<Action, Never>' to 'EffectTask<Action, Never>' in your codebase, use the following regular expression:
640663
641-
See the migration roadmap for more information: https://github.com/pointfreeco/swift-composable-architecture/discussions/1477
642-
"""
643-
)
644-
@available(
645-
tvOS,
646-
deprecated: 9999.0,
647-
message:
648-
"""
649-
'Effect' has been deprecated in favor of 'EffectTask' when `Failure == Never`, or
650-
`EffectProducer<Output, Failure>` in general.
651-
652-
You are encouraged to use `EffectTask<Action>` to model the ouput of your reducers, and to Swift
653-
concurrency to model failable streams of values.
664+
Find:
665+
Effect<([^,]+), Never>
654666
655-
See the migration roadmap for more information: https://github.com/pointfreeco/swift-composable-architecture/discussions/1477
656-
"""
657-
)
658-
@available(
659-
watchOS,
660-
deprecated: 9999.0,
661-
message:
662-
"""
663-
'Effect' has been deprecated in favor of 'EffectTask' when `Failure == Never`, or
664-
`EffectProducer<Output, Failure>` in general.
665-
666-
You are encouraged to use `EffectTask<Action>` to model the ouput of your reducers, and to Swift
667-
concurrency to model failable streams of values.
667+
Replace:
668+
EffectTask<$1>
668669
669670
See the migration roadmap for more information: https://github.com/pointfreeco/swift-composable-architecture/discussions/1477
670671
"""

Sources/ComposableArchitecture/Effects/ConcurrencySupport.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,11 +326,11 @@
326326
/// - Parameters: operation: An operation to be performed on the actor with the underlying value.
327327
/// - Returns: The result of the operation.
328328
public func withValue<T: Sendable>(
329-
_ operation: @Sendable (inout Value) async throws -> T
330-
) async rethrows -> T {
329+
_ operation: @Sendable (inout Value) throws -> T
330+
) rethrows -> T {
331331
var value = self.value
332332
defer { self.value = value }
333-
return try await operation(&value)
333+
return try operation(&value)
334334
}
335335

336336
/// Overwrite the isolated value with a new value.

Sources/ComposableArchitecture/Internal/Deprecations.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ import XCTestDynamicOverlay
1010
import os
1111
#endif
1212

13+
// MARK: - Deprecated after 0.47.2
14+
15+
extension ActorIsolated {
16+
@available(
17+
*,
18+
deprecated,
19+
message: "Use the non-async version of 'withValue'."
20+
)
21+
public func withValue<T: Sendable>(
22+
_ operation: @Sendable (inout Value) async throws -> T
23+
) async rethrows -> T {
24+
var value = self.value
25+
defer { self.value = value }
26+
return try await operation(&value)
27+
}
28+
}
29+
1330
// MARK: - Deprecated after 0.45.0:
1431

1532
#if canImport(SwiftUI)

Sources/ComposableArchitecture/SwiftUI/Binding.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,11 @@ extension BindableState: CustomReflectable {
8282
}
8383
}
8484

85-
// Until we can use swift-custom-dump this has to be commented out
86-
// extension BindableState: CustomDumpRepresentable {
87-
// public var customDumpValue: Any {
88-
// self.wrappedValue
89-
// }
90-
// }
85+
extension BindableState: CustomDumpRepresentable {
86+
public var customDumpValue: Any {
87+
self.wrappedValue
88+
}
89+
}
9190

9291
extension BindableState: CustomDebugStringConvertible where Value: CustomDebugStringConvertible {
9392
public var debugDescription: String {
@@ -157,7 +156,6 @@ extension BindableAction {
157156
)
158157
}
159158
}
160-
161159
#endif
162160

163161
/// An action that describes simple mutations to some root state at a writable key path.

0 commit comments

Comments
 (0)