Merges next → master (12 commits, 22 files) for the effect-view 0.3.0 release: offline support (networkMode) for Query/Mutation, an operation-based rework that fixes Query/Mutation race conditions, and Stream-based request APIs. Full entry: packages/effect-view/CHANGELOG.md.
Offline support (networkMode)
Query.networkMode (new Operation.NetworkMode). "online" (default): a request made offline waits for a connection before running — its state has paused: true meanwhile, with result.waiting still true. "offlineFirst" runs right away and, if it fails while offline, pauses until the connection returns, then runs again. "always" ignores the connection.
refreshOnReconnect (defaults true, except in "always" mode): refreshes the current key when the connection returns, subject to staleTime.
refreshOnFocus / refreshOnReconnect accept "always" to refresh even a fresh result (Query.RefreshOn).
Focus/reconnect refreshes no longer restart a request that is already running, and paused requests resume by themselves.
New AppConnectivity and AppFocus services, each providing layerBrowser (navigator.onLine + online/offline events; page visibility), layerDummy (e.g. for tests) and make(view) (from any View<boolean>, e.g. on React Native).
Mutation.networkMode (defaults to the client's new defaultMutationNetworkMode, "online"): mutations called offline are paused until the connection returns.
Query.withScheduledRefresh now skips refreshes while the app is not focused; a skipped refresh still counts toward the schedule. Pass refreshInBackground: true to keep the previous behavior.
QueryClient gains defaultNetworkMode, defaultRefreshOnReconnect and defaultMutationNetworkMode.
Query/Mutation race fixes (new Operation module)
Each run of a Query or Mutation is now an Operation, and only the current one updates state / latestFinalState. Fixes, most visible on React Native:
a request's final state could be lost, leaving state stuck on waiting: true and the result out of the cache;
a superseded request could overwrite the state of a newer one, or be recorded in latestFinalState while still waiting;
concurrent fetch/refresh calls superseding a running request could leave an extra request running that was never interrupted.
Also: serving a fresh result from the cache no longer resets that cache entry's staleness timer.
Breaking changes
fetchView / refreshView / mutateView → fetchStream / refreshStream / mutateStream: same request, but returns a Stream of that request's states. It emits the current state first, so subscribing late still yields the final state, then ends once the request settles or is interrupted. Consume with Stream.use.
A fetch/refresh superseded by a newer request is now interrupted instead of returning its unfinished state typed as final; its state goes back to the previous result.
fiber removed from Query / Mutation; use the new operation View (key, state, stream, fiber, interrupt, await).
Overlapping mutations: mutation.state / latestFinalState follow only the most recently started call — earlier calls still run to completion but no longer update them. Use mutateStream to follow each call separately.
QueryClient.layer is no longer a function: it's now a plain Layer with the default options, and QueryClient.layerWithOptions takes options. Both now require the AppConnectivity and AppFocus services; in a browser use QueryClient.layerBrowser / layerBrowserWithOptions (which provide both), elsewhere provide the services (e.g. the layerDummys).
Mutation.make and MutationForm.make now require a QueryClient.
refreshOnWindowFocus → refreshOnFocus, defaultRefreshOnWindowFocus → defaultRefreshOnFocus (focus now comes from the AppFocus service).
Docs & tests
New CHANGELOG.md; docs (query.md, mutation.md, getting-started.md), ai-docs and the example app updated.
New Query.network.test.ts (network modes); Query.test.ts and Mutation.test.ts expanded.
## Summary
Merges `next` → `master` (12 commits, 22 files) for the effect-view **0.3.0** release: offline support (`networkMode`) for `Query`/`Mutation`, an operation-based rework that fixes `Query`/`Mutation` race conditions, and Stream-based request APIs. Full entry: `packages/effect-view/CHANGELOG.md`.
### Offline support (`networkMode`)
- `Query.networkMode` (new `Operation.NetworkMode`). `"online"` (default): a request made offline waits for a connection before running — its state has `paused: true` meanwhile, with `result.waiting` still `true`. `"offlineFirst"` runs right away and, if it fails while offline, pauses until the connection returns, then runs again. `"always"` ignores the connection.
- `refreshOnReconnect` (defaults `true`, except in `"always"` mode): refreshes the current key when the connection returns, subject to `staleTime`.
- `refreshOnFocus` / `refreshOnReconnect` accept `"always"` to refresh even a fresh result (`Query.RefreshOn`).
- Focus/reconnect refreshes no longer restart a request that is already running, and paused requests resume by themselves.
- New `AppConnectivity` and `AppFocus` services, each providing `layerBrowser` (`navigator.onLine` + `online`/`offline` events; page visibility), `layerDummy` (e.g. for tests) and `make(view)` (from any `View<boolean>`, e.g. on React Native).
- `Mutation.networkMode` (defaults to the client's new `defaultMutationNetworkMode`, `"online"`): mutations called offline are paused until the connection returns.
- `Query.withScheduledRefresh` now skips refreshes while the app is not focused; a skipped refresh still counts toward the schedule. Pass `refreshInBackground: true` to keep the previous behavior.
- `QueryClient` gains `defaultNetworkMode`, `defaultRefreshOnReconnect` and `defaultMutationNetworkMode`.
### Query/Mutation race fixes (new `Operation` module)
Each run of a Query or Mutation is now an `Operation`, and only the current one updates `state` / `latestFinalState`. Fixes, most visible on React Native:
- a request's final state could be lost, leaving `state` stuck on `waiting: true` and the result out of the cache;
- a superseded request could overwrite the state of a newer one, or be recorded in `latestFinalState` while still waiting;
- concurrent `fetch`/`refresh` calls superseding a running request could leave an extra request running that was never interrupted.
Also: serving a fresh result from the cache no longer resets that cache entry's staleness timer.
### Breaking changes
- `fetchView` / `refreshView` / `mutateView` → `fetchStream` / `refreshStream` / `mutateStream`: same request, but returns a `Stream` of that request's states. It emits the current state first, so subscribing late still yields the final state, then ends once the request settles or is interrupted. Consume with `Stream.use`.
- A `fetch`/`refresh` superseded by a newer request is now interrupted instead of returning its unfinished state typed as final; its state goes back to the previous result.
- `fiber` removed from `Query` / `Mutation`; use the new `operation` View (`key`, `state`, `stream`, `fiber`, `interrupt`, `await`).
- Overlapping mutations: `mutation.state` / `latestFinalState` follow only the most recently started call — earlier calls still run to completion but no longer update them. Use `mutateStream` to follow each call separately.
- Renames: `FinalQueryState` → `QueryFinalState`, `FinalMutationState` → `MutationFinalState`, `LatestMutationState` → `MutationLatestState`; removed `QueryStateLens`, `makeQueryStateLens`, `MutationStateLens` and `makeMutationStateLens`.
- `QueryClient.layer` is no longer a function: it's now a plain `Layer` with the default options, and `QueryClient.layerWithOptions` takes options. Both now require the `AppConnectivity` and `AppFocus` services; in a browser use `QueryClient.layerBrowser` / `layerBrowserWithOptions` (which provide both), elsewhere provide the services (e.g. the `layerDummy`s).
- `Mutation.make` and `MutationForm.make` now require a `QueryClient`.
- `refreshOnWindowFocus` → `refreshOnFocus`, `defaultRefreshOnWindowFocus` → `defaultRefreshOnFocus` (focus now comes from the `AppFocus` service).
### Docs & tests
- New `CHANGELOG.md`; docs (`query.md`, `mutation.md`, `getting-started.md`), ai-docs and the example app updated.
- New `Query.network.test.ts` (network modes); `Query.test.ts` and `Mutation.test.ts` expanded.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Merges
next→master(12 commits, 22 files) for the effect-view 0.3.0 release: offline support (networkMode) forQuery/Mutation, an operation-based rework that fixesQuery/Mutationrace conditions, and Stream-based request APIs. Full entry:packages/effect-view/CHANGELOG.md.Offline support (
networkMode)Query.networkMode(newOperation.NetworkMode)."online"(default): a request made offline waits for a connection before running — its state haspaused: truemeanwhile, withresult.waitingstilltrue."offlineFirst"runs right away and, if it fails while offline, pauses until the connection returns, then runs again."always"ignores the connection.refreshOnReconnect(defaultstrue, except in"always"mode): refreshes the current key when the connection returns, subject tostaleTime.refreshOnFocus/refreshOnReconnectaccept"always"to refresh even a fresh result (Query.RefreshOn).AppConnectivityandAppFocusservices, each providinglayerBrowser(navigator.onLine+online/offlineevents; page visibility),layerDummy(e.g. for tests) andmake(view)(from anyView<boolean>, e.g. on React Native).Mutation.networkMode(defaults to the client's newdefaultMutationNetworkMode,"online"): mutations called offline are paused until the connection returns.Query.withScheduledRefreshnow skips refreshes while the app is not focused; a skipped refresh still counts toward the schedule. PassrefreshInBackground: trueto keep the previous behavior.QueryClientgainsdefaultNetworkMode,defaultRefreshOnReconnectanddefaultMutationNetworkMode.Query/Mutation race fixes (new
Operationmodule)Each run of a Query or Mutation is now an
Operation, and only the current one updatesstate/latestFinalState. Fixes, most visible on React Native:statestuck onwaiting: trueand the result out of the cache;latestFinalStatewhile still waiting;fetch/refreshcalls superseding a running request could leave an extra request running that was never interrupted.Also: serving a fresh result from the cache no longer resets that cache entry's staleness timer.
Breaking changes
fetchView/refreshView/mutateView→fetchStream/refreshStream/mutateStream: same request, but returns aStreamof that request's states. It emits the current state first, so subscribing late still yields the final state, then ends once the request settles or is interrupted. Consume withStream.use.fetch/refreshsuperseded by a newer request is now interrupted instead of returning its unfinished state typed as final; its state goes back to the previous result.fiberremoved fromQuery/Mutation; use the newoperationView (key,state,stream,fiber,interrupt,await).mutation.state/latestFinalStatefollow only the most recently started call — earlier calls still run to completion but no longer update them. UsemutateStreamto follow each call separately.FinalQueryState→QueryFinalState,FinalMutationState→MutationFinalState,LatestMutationState→MutationLatestState; removedQueryStateLens,makeQueryStateLens,MutationStateLensandmakeMutationStateLens.QueryClient.layeris no longer a function: it's now a plainLayerwith the default options, andQueryClient.layerWithOptionstakes options. Both now require theAppConnectivityandAppFocusservices; in a browser useQueryClient.layerBrowser/layerBrowserWithOptions(which provide both), elsewhere provide the services (e.g. thelayerDummys).Mutation.makeandMutationForm.makenow require aQueryClient.refreshOnWindowFocus→refreshOnFocus,defaultRefreshOnWindowFocus→defaultRefreshOnFocus(focus now comes from theAppFocusservice).Docs & tests
CHANGELOG.md; docs (query.md,mutation.md,getting-started.md), ai-docs and the example app updated.Query.network.test.ts(network modes);Query.test.tsandMutation.test.tsexpanded.Release 0.3.0: Query/Mutation refactor + connectivity supportto Release 0.3.0: Query/Mutation race fixes + offline support