Skip to content

Action Store: Preserve last error through running for stale-while-revalidate#1624

Open
mcintyre94 wants to merge 1 commit into
reactive-store/abort-signalfrom
reactive-store/preserve-error
Open

Action Store: Preserve last error through running for stale-while-revalidate#1624
mcintyre94 wants to merge 1 commit into
reactive-store/abort-signalfrom
reactive-store/preserve-error

Conversation

@mcintyre94
Copy link
Copy Markdown
Member

@mcintyre94 mcintyre94 commented May 12, 2026

Improving SWR for reactive-action-store: it now maintains the error as well as data on a subsequent dispatch. This means that apps can display the previous error on a retrying state if they'd like to.

Related to first note here: #1619 (comment) - this means we can track state correctly on a running -> error -> running retry scenario.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 12, 2026

🦋 Changeset detected

Latest commit: 84cd1f2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 47 packages
Name Type
@solana/subscribable Minor
@solana/react Minor
@solana/kit Minor
@solana/rpc-spec Minor
@solana/rpc-subscriptions-channel-websocket Minor
@solana/rpc-subscriptions-spec Minor
@solana/rpc-subscriptions Minor
@solana/accounts Minor
@solana/plugin-interfaces Minor
@solana/rpc-api Minor
@solana/rpc-transport-http Minor
@solana/rpc Minor
@solana/sysvars Minor
@solana/rpc-subscriptions-api Minor
@solana/transaction-confirmation Minor
@solana/program-client-core Minor
@solana/rpc-graphql Minor
@solana/addresses Minor
@solana/assertions Minor
@solana/codecs-core Minor
@solana/codecs-data-structures Minor
@solana/codecs-numbers Minor
@solana/codecs-strings Minor
@solana/codecs Minor
@solana/compat Minor
@solana/errors Minor
@solana/fast-stable-stringify Minor
@solana/fixed-points Minor
@solana/functional Minor
@solana/instruction-plans Minor
@solana/instructions Minor
@solana/keys Minor
@solana/nominal-types Minor
@solana/offchain-messages Minor
@solana/options Minor
@solana/plugin-core Minor
@solana/programs Minor
@solana/promises Minor
@solana/rpc-parsed-types Minor
@solana/rpc-spec-types Minor
@solana/rpc-transformers Minor
@solana/rpc-types Minor
@solana/signers Minor
@solana/transaction-messages Minor
@solana/transactions Minor
@solana/wallet-account-signer Minor
@solana/webcrypto-ed25519-polyfill Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@bundlemon
Copy link
Copy Markdown

bundlemon Bot commented May 12, 2026

BundleMon

Files updated (16)
Status Path Size Limits
react/dist/index.native.mjs
3.89KB (+815B +25.73%) -
react/dist/index.browser.mjs
3.89KB (+814B +25.69%) -
react/dist/index.node.mjs
3.89KB (+814B +25.71%) -
errors/dist/index.browser.mjs
20.69KB (+170B +0.81%) -
errors/dist/index.native.mjs
20.69KB (+170B +0.81%) -
errors/dist/index.node.mjs
20.71KB (+170B +0.81%) -
wallet-account-signer/dist/index.native.mjs
17.53KB (+165B +0.93%) -
wallet-account-signer/dist/index.browser.mjs
17.53KB (+164B +0.92%) -
wallet-account-signer/dist/index.node.mjs
17.54KB (+164B +0.92%) -
subscribable/dist/index.node.mjs
2.79KB (+116B +4.23%) -
subscribable/dist/index.browser.mjs
2.72KB (+114B +4.27%) -
subscribable/dist/index.native.mjs
2.72KB (+114B +4.26%) -
@solana/kit production bundle
kit/dist/index.production.min.js
52.35KB (+80B +0.15%) -
rpc-spec/dist/index.browser.mjs
898B (-20B -2.18%) -
rpc-spec/dist/index.native.mjs
897B (-21B -2.29%) -
rpc-spec/dist/index.node.mjs
896B (-21B -2.29%) -
Unchanged files (131)
Status Path Size Limits
rpc-graphql/dist/index.browser.mjs
18.82KB -
rpc-graphql/dist/index.native.mjs
18.81KB -
rpc-graphql/dist/index.node.mjs
18.81KB -
transaction-messages/dist/index.browser.mjs
11.32KB -
transaction-messages/dist/index.native.mjs
11.32KB -
transaction-messages/dist/index.node.mjs
11.32KB -
instruction-plans/dist/index.browser.mjs
6.58KB -
instruction-plans/dist/index.native.mjs
6.58KB -
instruction-plans/dist/index.node.mjs
6.58KB -
fixed-points/dist/index.browser.mjs
5.08KB -
fixed-points/dist/index.native.mjs
5.07KB -
fixed-points/dist/index.node.mjs
5.07KB -
codecs-data-structures/dist/index.browser.mjs
5.04KB -
codecs-data-structures/dist/index.native.mjs
5.03KB -
codecs-data-structures/dist/index.node.mjs
5.03KB -
offchain-messages/dist/index.browser.mjs
4.89KB -
offchain-messages/dist/index.native.mjs
4.89KB -
offchain-messages/dist/index.node.mjs
4.89KB -
transactions/dist/index.browser.mjs
4.07KB -
transactions/dist/index.native.mjs
4.07KB -
transactions/dist/index.node.mjs
4.07KB -
kit/dist/index.browser.mjs
3.97KB -
kit/dist/index.native.mjs
3.97KB -
kit/dist/index.node.mjs
3.97KB -
codecs-core/dist/index.browser.mjs
3.62KB -
codecs-core/dist/index.native.mjs
3.62KB -
codecs-core/dist/index.node.mjs
3.62KB -
webcrypto-ed25519-polyfill/dist/index.node.mj
s
3.61KB -
webcrypto-ed25519-polyfill/dist/index.browser
.mjs
3.59KB -
webcrypto-ed25519-polyfill/dist/index.native.
mjs
3.57KB -
rpc-subscriptions/dist/index.browser.mjs
3.37KB -
rpc-subscriptions/dist/index.node.mjs
3.34KB -
rpc-subscriptions/dist/index.native.mjs
3.31KB -
signers/dist/index.browser.mjs
3.26KB -
signers/dist/index.native.mjs
3.26KB -
signers/dist/index.node.mjs
3.26KB -
rpc-transformers/dist/index.browser.mjs
3.16KB -
rpc-transformers/dist/index.native.mjs
3.16KB -
rpc-transformers/dist/index.node.mjs
3.16KB -
keys/dist/index.node.mjs
3.06KB -
addresses/dist/index.browser.mjs
2.93KB -
addresses/dist/index.native.mjs
2.92KB -
addresses/dist/index.node.mjs
2.92KB -
keys/dist/index.browser.mjs
2.85KB -
keys/dist/index.native.mjs
2.85KB -
codecs-strings/dist/index.browser.mjs
2.55KB -
codecs-strings/dist/index.node.mjs
2.51KB -
codecs-strings/dist/index.native.mjs
2.47KB -
transaction-confirmation/dist/index.node.mjs
2.42KB -
transaction-confirmation/dist/index.native.mj
s
2.37KB -
sysvars/dist/index.browser.mjs
2.37KB -
sysvars/dist/index.native.mjs
2.37KB -
transaction-confirmation/dist/index.browser.m
js
2.37KB -
sysvars/dist/index.node.mjs
2.37KB -
rpc-subscriptions-spec/dist/index.node.mjs
2.25KB -
rpc-subscriptions-spec/dist/index.native.mjs
2.2KB -
rpc-subscriptions-spec/dist/index.browser.mjs
2.2KB -
rpc/dist/index.node.mjs
1.95KB -
codecs-numbers/dist/index.browser.mjs
1.95KB -
codecs-numbers/dist/index.native.mjs
1.95KB -
codecs-numbers/dist/index.node.mjs
1.94KB -
rpc-transport-http/dist/index.browser.mjs
1.91KB -
rpc-transport-http/dist/index.native.mjs
1.9KB -
rpc/dist/index.native.mjs
1.81KB -
rpc-types/dist/index.browser.mjs
1.8KB -
rpc/dist/index.browser.mjs
1.8KB -
rpc-types/dist/index.native.mjs
1.8KB -
rpc-types/dist/index.node.mjs
1.8KB -
rpc-transport-http/dist/index.node.mjs
1.72KB -
rpc-subscriptions-channel-websocket/dist/inde
x.node.mjs
1.33KB -
rpc-subscriptions-channel-websocket/dist/inde
x.native.mjs
1.27KB -
rpc-subscriptions-channel-websocket/dist/inde
x.browser.mjs
1.26KB -
program-client-core/dist/index.browser.mjs
1.21KB -
program-client-core/dist/index.native.mjs
1.21KB -
program-client-core/dist/index.node.mjs
1.21KB -
options/dist/index.browser.mjs
1.18KB -
options/dist/index.native.mjs
1.18KB -
options/dist/index.node.mjs
1.17KB -
accounts/dist/index.browser.mjs
1.17KB -
accounts/dist/index.native.mjs
1.17KB -
accounts/dist/index.node.mjs
1.16KB -
rpc-api/dist/index.browser.mjs
998B -
rpc-api/dist/index.native.mjs
997B -
rpc-api/dist/index.node.mjs
995B -
compat/dist/index.browser.mjs
969B -
compat/dist/index.native.mjs
968B -
compat/dist/index.node.mjs
966B -
rpc-spec-types/dist/index.browser.mjs
962B -
rpc-spec-types/dist/index.native.mjs
961B -
rpc-spec-types/dist/index.node.mjs
959B -
rpc-subscriptions-api/dist/index.native.mjs
870B -
rpc-subscriptions-api/dist/index.node.mjs
869B -
rpc-subscriptions-api/dist/index.browser.mjs
868B -
promises/dist/index.native.mjs
841B -
promises/dist/index.node.mjs
840B -
promises/dist/index.browser.mjs
839B -
plugin-core/dist/index.browser.mjs
820B -
plugin-core/dist/index.native.mjs
819B -
plugin-core/dist/index.node.mjs
817B -
assertions/dist/index.browser.mjs
783B -
instructions/dist/index.browser.mjs
771B -
instructions/dist/index.native.mjs
770B -
instructions/dist/index.node.mjs
768B -
fast-stable-stringify/dist/index.browser.mjs
726B -
fast-stable-stringify/dist/index.native.mjs
725B -
assertions/dist/index.native.mjs
724B -
fast-stable-stringify/dist/index.node.mjs
724B -
assertions/dist/index.node.mjs
723B -
programs/dist/index.browser.mjs
329B -
programs/dist/index.native.mjs
327B -
programs/dist/index.node.mjs
325B -
fs-impl/dist/index.browser.mjs
245B -
event-target-impl/dist/index.node.mjs
230B -
functional/dist/index.browser.mjs
154B -
functional/dist/index.native.mjs
152B -
text-encoding-impl/dist/index.native.mjs
152B -
functional/dist/index.node.mjs
151B -
codecs/dist/index.browser.mjs
145B -
codecs/dist/index.native.mjs
144B -
codecs/dist/index.node.mjs
142B -
event-target-impl/dist/index.browser.mjs
133B -
ws-impl/dist/index.node.mjs
131B -
text-encoding-impl/dist/index.browser.mjs
122B -
fs-impl/dist/index.node.mjs
120B -
text-encoding-impl/dist/index.node.mjs
119B -
ws-impl/dist/index.browser.mjs
113B -
crypto-impl/dist/index.node.mjs
111B -
crypto-impl/dist/index.browser.mjs
109B -
rpc-parsed-types/dist/index.browser.mjs
66B -
rpc-parsed-types/dist/index.native.mjs
65B -
rpc-parsed-types/dist/index.node.mjs
63B -

Total files change +3.72KB +0.71%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

@mcintyre94 mcintyre94 force-pushed the reactive-store/preserve-error branch from 419b944 to 2f9688e Compare May 12, 2026 18:14
@mcintyre94
Copy link
Copy Markdown
Member Author

@trevor-cortex

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 12, 2026

Documentation Preview: https://kit-docs-ja1r475c4-anza-tech.vercel.app

Copy link
Copy Markdown

@trevor-cortex trevor-cortex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (commenting rather than approving — no write access).

Clean, well-scoped extension of the existing SWR behavior to error. The change is symmetric with the prior data handling: previousError is now threaded through into the running snapshot the same way previousData already was, and success clears it (so a successful retry doesn't keep showing the old failure) while reset() clears both. The type, docs, README, changeset, and tests are all consistent with each other.

Things to watch out for:

  • The running variant's error widens from undefined to unknown. Downstream consumers that narrowed on status === 'running' and relied on error being undefined there will need to adjust — the changeset's minor bump is correct given pre-1.0 conventions where minor may be treated as breaking.
  • success clears error but only reset() clears data — an intentional asymmetry that's now called out in both the package docstring and the README. Worth keeping in mind for anyone building on this.
  • The setState short-circuit in createReactiveActionStore still fires the listener on an error → running transition because status differs, so subscribers correctly observe the status flip even when data and error are unchanged.

Notes for subsequent reviewers:

  • Test coverage is solid: the new subscribable-layer tests cover both error → running (preserves error) and success → error → running (preserves both stale data and stale error), and the React test confirms error clears on the subsequent success. No need to ask for more.
  • The variant reordering in ReactiveActionState is cosmetic — running and error are now structurally identical except for the discriminant, which is the whole point of this PR.

@mcintyre94 mcintyre94 marked this pull request as ready for review May 12, 2026 18:56
@mcintyre94 mcintyre94 requested a review from lorisleiva May 12, 2026 18:56
@mcintyre94 mcintyre94 changed the title Preserve last error through running for stale-while-revalidate Action Store: Preserve last error through running for stale-while-revalidate May 13, 2026
@mcintyre94 mcintyre94 changed the base branch from reactive-store/abort-signal to graphite-base/1624 May 13, 2026 10:32
@mcintyre94 mcintyre94 force-pushed the graphite-base/1624 branch from 1c2b3e9 to 3471172 Compare May 13, 2026 10:38
@mcintyre94 mcintyre94 force-pushed the reactive-store/preserve-error branch from 2f9688e to 3c31014 Compare May 13, 2026 10:38
@mcintyre94 mcintyre94 changed the base branch from graphite-base/1624 to reactive-store/abort-signal May 13, 2026 10:38
@mcintyre94 mcintyre94 changed the base branch from reactive-store/abort-signal to graphite-base/1624 May 13, 2026 10:43
@mcintyre94 mcintyre94 force-pushed the graphite-base/1624 branch from 3471172 to f22b562 Compare May 13, 2026 10:44
@mcintyre94 mcintyre94 force-pushed the reactive-store/preserve-error branch from 3c31014 to 475b052 Compare May 13, 2026 10:44
@mcintyre94 mcintyre94 changed the base branch from graphite-base/1624 to reactive-store/abort-signal May 13, 2026 10:44
@mcintyre94 mcintyre94 force-pushed the reactive-store/abort-signal branch from f22b562 to 674c112 Compare May 13, 2026 14:30
@mcintyre94 mcintyre94 force-pushed the reactive-store/preserve-error branch from 475b052 to a1625b6 Compare May 13, 2026 14:30
@mcintyre94 mcintyre94 force-pushed the reactive-store/abort-signal branch from 674c112 to f2bb5d1 Compare May 18, 2026 14:42
@mcintyre94 mcintyre94 force-pushed the reactive-store/preserve-error branch from a1625b6 to a09827d Compare May 18, 2026 14:42
Errors from a `ReactiveActionStore` now persist through a subsequent `running` state, matching the existing behavior for `data`. A re-dispatch after a failure keeps the previous error in `state.error` until the new attempt resolves — `success` clears it, a new failure replaces it. This mirrors how SWR and TanStack Query handle revalidation: stale-while-revalidate applies symmetrically to data and errors, so consumers don't have to choose between flickering and losing context on retry.

The `running` variant of `ReactiveActionState<T>` widens from `error: undefined` to `error: unknown`, which surfaces through `useAction` as a behavior change: the `error` field now persists across a new `send(...)` call until that call resolves, instead of clearing immediately. The README, JSDoc, and tests are updated to match. `useRequest` will pick this up via a follow-up commit on the next branch in the stack.
Copy link
Copy Markdown
Member

@lorisleiva lorisleiva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants