Add reactiveStore to PendingRpcRequest#1555
Conversation
🦋 Changeset detectedLatest commit: f48797d The changes in this PR will be included in the next version bump. This PR includes changesets to release 47 packages
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 |
This stack of pull requests is managed by Graphite. Learn more about stacking. |
BundleMonFiles updated (4)
Unchanged files (143)
Total files change +522B +0.1% Final result: ✅ View report in BundleMon website ➡️ |
|
Documentation Preview: https://kit-docs-1hqmgirgi-anza-tech.vercel.app |
06c7974 to
eb8b21a
Compare
trevor-cortex
left a comment
There was a problem hiding this comment.
Nice, clean addition. The reactiveStore() method mirrors the existing PendingRpcSubscriptionRequest.reactiveStore() pattern, and the implementation is a tiny, easy-to-reason-about wrapper: createReactiveActionStore + immediate auto-dispatch. Docblock + README + changeset + tests are all in place. LGTM modulo the comments below.
Summary
- New
reactiveStore(): ReactiveActionStore<[], TResponse>method onPendingRpcRequest, auto-fires on construction and returns a store with the standard{ subscribe, getState, dispatch, dispatchAsync, reset }contract. @solana/subscribableadded as a runtime dep of@solana/rpc-spec.ES2024.Promiseadded to therpc-spectsconfiglib(needed forPromise.withResolvers()in the new tests).- Mock
PendingRpcRequestshapes updated across several packages (accounts,kit,rpc-graphql,transaction-confirmation) to satisfy the expanded type. - New CLAUDE.md guidance about preferring
jest.useFakeTimers()+runAllTimersAsync()over hand-rolled microtask flushers, which the new tests themselves follow.
Things to watch / notes for subsequent reviewers
- No external
abortSignaloption onreactiveStore()— unlikesend({ abortSignal }). Consumers tie cancellation tostore.reset()or letdispatch()supersede in-flight calls. The PR description mentions the escape hatch (createActionStore((signal) => rpc.getAccountInfo(address).send({ abortSignal: signal }))), which is fine, but worth confirming this is the intended ergonomic — a follow-up that accepts an external signal wouldn't be a breaking change, so deferring is reasonable. - Auto-dispatch semantics: the
ReactiveActionStorereturned here can re-enteridleviareset()but not re-enterrunningwithout an explicitdispatch(). Documented in the changeset/README; flagging because it's the main behavioural subtlety. @solana/subscribablein@solana/rpc-spec's runtime deps pulls theevent-target-impl/promiseschain into the spec package. Consistent with the subscription-side precedent, but it does slightly expand the spec package's surface — worth a sanity-check.- Test hygiene: the new
describeinstalls fake timers inbeforeEachwith no matchingafterEachto restore real timers — see inline comment. - Bundle-size impact on
@solana/kitvia the new transitive dep — BundleMon will tell us, but worth eyeballing.
| plan: RpcPlan<TResponse>, | ||
| ): PendingRpcRequest<TResponse> { | ||
| return { | ||
| reactiveStore(): ReactiveActionStore<[], TResponse> { | ||
| const store = createReactiveActionStore<[], TResponse>(signal => plan.execute({ signal, transport })); |
There was a problem hiding this comment.
Question (non-blocking): would it be worth accepting an optional { abortSignal } here, mirroring send(options)? Use cases: binding the store's lifetime to a parent controller (e.g. Svelte onDestroy, Vue onScopeDispose, or a composed cancellation tree) without having to manually wire reset(). The escape-hatch pattern in the PR description (createActionStore(signal => ...send({ abortSignal: signal }))) works but loses the one-liner ergonomics. Happy to defer — this is purely additive and can be layered on later.
There was a problem hiding this comment.
Considered this but I don't think it's needed. There's nothing that can leak here - the http request is abortable and doesn't leave anything behind. In contrast to subscriptions where we have a subscription to clean up.
Having both signals requires fiddly wiring in subscriptions, which is worth it there but would just be complexity for no value here IMO.
eb8b21a to
d404b62
Compare
0e977ea to
1a53c39
Compare
d404b62 to
0c6eab5
Compare
lorisleiva
left a comment
There was a problem hiding this comment.
Sorry for the late review, looks good to me! 👌
Merge activity
|
|
🔎💬 Inkeep AI search and chat service is syncing content for source 'Solana Kit Docs' |

Summary of Changes
This PR adds
.reactiveStore()toPendingRpcRequest, similar to how we use it forPendingRpcSubscriptionRequest. This sends the request and synchronously returns aReactiveActionStore.As with our other reactive store features, this is intended to provide a better API for reactive consumers:
Note that this has auto-dispatch semantics, meaning calling it has the same sort of behaviour as calling
send()or the similarreactiveStore()on subscriptions.Consumers that want to control sending precisely can use
createActionStore((signal) => rpc.getAccountInfo(address).send({abortSignal: signal})- this is just a thin wrapper that adds auto-dispatch and therefore skips theidlestate.