Skip to content

Add withCleanup function to @solana/plugin-core#1480

Merged
mcintyre94 merged 2 commits intomainfrom
with-cleanup
Mar 27, 2026
Merged

Add withCleanup function to @solana/plugin-core#1480
mcintyre94 merged 2 commits intomainfrom
with-cleanup

Conversation

@mcintyre94
Copy link
Copy Markdown
Member

@mcintyre94 mcintyre94 commented Mar 17, 2026

Adds a withCleanup function that extends any client with a synchronous Symbol.dispose method, enabling the TC39 using declaration pattern. Note that only synchronous cleanup is supported for now — async teardown (Symbol.asyncDispose) is not yet handled. If the client already has a Symbol.dispose, the new cleanup is chained so both run when the client is disposed. Includes unit tests and a type test.

function myPlugin() {
    return <T extends object>(client: T) => {
        const socket = new WebSocket('wss://api.example.com');
        return withCleanup(
            extendClient(client, { socket }),
            () => socket.close(),
        );
    };
}

// `socket.close()` is called automatically when `client` goes out of scope:
using client = createClient(myPlugin());

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 17, 2026

🦋 Changeset detected

Latest commit: 20b3992

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

This PR includes changesets to release 46 packages
Name Type
@solana/plugin-core Minor
@solana/kit Minor
@solana/accounts 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/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-interfaces Minor
@solana/program-client-core Minor
@solana/programs Minor
@solana/promises Minor
@solana/react Minor
@solana/rpc-api Minor
@solana/rpc-graphql Minor
@solana/rpc-parsed-types Minor
@solana/rpc-spec-types Minor
@solana/rpc-spec Minor
@solana/rpc-subscriptions-api Minor
@solana/rpc-subscriptions-channel-websocket Minor
@solana/rpc-subscriptions-spec Minor
@solana/rpc-subscriptions Minor
@solana/rpc-transformers Minor
@solana/rpc-transport-http Minor
@solana/rpc-types Minor
@solana/rpc Minor
@solana/signers Minor
@solana/subscribable Minor
@solana/sysvars Minor
@solana/transaction-confirmation 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

@mcintyre94 mcintyre94 requested a review from lorisleiva March 17, 2026 17:45
@bundlemon
Copy link
Copy Markdown

bundlemon bot commented Mar 17, 2026

BundleMon

Files updated (4)
Status Path Size Limits
plugin-core/dist/index.native.mjs
730B (+258B +54.66%) -
plugin-core/dist/index.node.mjs
728B (+258B +54.89%) -
plugin-core/dist/index.browser.mjs
730B (+257B +54.33%) -
@solana/kit production bundle
kit/dist/index.production.min.js
45.83KB (+156B +0.33%) -
Unchanged files (138)
Status Path Size Limits
errors/dist/index.node.mjs
19.18KB -
errors/dist/index.browser.mjs
19.16KB -
errors/dist/index.native.mjs
19.16KB -
rpc-graphql/dist/index.browser.mjs
18.82KB -
rpc-graphql/dist/index.native.mjs
18.81KB -
rpc-graphql/dist/index.node.mjs
18.81KB -
wallet-account-signer/dist/index.node.mjs
16.26KB -
wallet-account-signer/dist/index.native.mjs
16.24KB -
wallet-account-signer/dist/index.browser.mjs
16.24KB -
transaction-messages/dist/index.browser.mjs
11.08KB -
transaction-messages/dist/index.native.mjs
11.08KB -
transaction-messages/dist/index.node.mjs
11.08KB -
instruction-plans/dist/index.browser.mjs
6.47KB -
instruction-plans/dist/index.native.mjs
6.47KB -
instruction-plans/dist/index.node.mjs
6.46KB -
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
3.94KB -
transactions/dist/index.native.mjs
3.93KB -
transactions/dist/index.node.mjs
3.93KB -
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 -
rpc-transformers/dist/index.browser.mjs
3.16KB -
rpc-transformers/dist/index.native.mjs
3.16KB -
rpc-transformers/dist/index.node.mjs
3.16KB -
signers/dist/index.browser.mjs
3.14KB -
signers/dist/index.native.mjs
3.14KB -
signers/dist/index.node.mjs
3.14KB -
react/dist/index.browser.mjs
3.09KB -
react/dist/index.native.mjs
3.09KB -
react/dist/index.node.mjs
3.09KB -
addresses/dist/index.browser.mjs
2.93KB -
addresses/dist/index.native.mjs
2.92KB -
addresses/dist/index.node.mjs
2.92KB -
kit/dist/index.browser.mjs
2.78KB -
kit/dist/index.native.mjs
2.78KB -
kit/dist/index.node.mjs
2.78KB -
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.41KB -
sysvars/dist/index.browser.mjs
2.37KB -
sysvars/dist/index.native.mjs
2.37KB -
sysvars/dist/index.node.mjs
2.37KB -
transaction-confirmation/dist/index.native.mj
s
2.36KB -
transaction-confirmation/dist/index.browser.m
js
2.35KB -
rpc-subscriptions-spec/dist/index.node.mjs
2.18KB -
rpc-subscriptions-spec/dist/index.native.mjs
2.13KB -
rpc-subscriptions-spec/dist/index.browser.mjs
2.13KB -
keys/dist/index.browser.mjs
2.1KB -
keys/dist/index.native.mjs
2.1KB -
keys/dist/index.node.mjs
2.1KB -
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/dist/index.browser.mjs
1.8KB -
subscribable/dist/index.node.mjs
1.8KB -
subscribable/dist/index.native.mjs
1.75KB -
subscribable/dist/index.browser.mjs
1.74KB -
rpc-transport-http/dist/index.node.mjs
1.72KB -
rpc-types/dist/index.browser.mjs
1.53KB -
rpc-types/dist/index.native.mjs
1.53KB -
rpc-types/dist/index.node.mjs
1.53KB -
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
976B -
rpc-api/dist/index.native.mjs
975B -
rpc-api/dist/index.node.mjs
973B -
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 -
rpc-spec/dist/index.browser.mjs
852B -
rpc-spec/dist/index.native.mjs
851B -
rpc-spec/dist/index.node.mjs
850B -
promises/dist/index.browser.mjs
799B -
promises/dist/index.native.mjs
798B -
promises/dist/index.node.mjs
797B -
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 -
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
137B -
codecs/dist/index.native.mjs
136B -
codecs/dist/index.node.mjs
134B -
event-target-impl/dist/index.browser.mjs
133B -
ws-impl/dist/index.node.mjs
131B -
text-encoding-impl/dist/index.browser.mjs
122B -
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 +929B +0.19%

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 17, 2026

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

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.

Very nice! Just a couple of nits. Is the idea that we only support sync dispose for now and if we need async support we can add withAsyncCleanup in the future?

Copy link
Copy Markdown
Member Author

mcintyre94 commented Mar 17, 2026

@mcintyre94 mcintyre94 force-pushed the with-cleanup branch 3 times, most recently from a152bf6 to 8676a63 Compare March 17, 2026 18:41
@mcintyre94 mcintyre94 marked this pull request as draft March 17, 2026 23:41
Adds a `withCleanup` function that wraps any client with a synchronous `Symbol.dispose` method, enabling the TC39 `using` declaration pattern. Note that only synchronous cleanup is supported for now — async teardown (`Symbol.asyncDispose`) is not yet handled. If the client already has a `Symbol.dispose`, the new cleanup is chained so both run when the client is disposed. Includes unit tests and a type test.
@mcintyre94 mcintyre94 marked this pull request as ready for review March 26, 2026 09:31
@mcintyre94
Copy link
Copy Markdown
Member Author

mcintyre94 commented Mar 26, 2026

We discussed offline, and decided to keep broadly this design.

I've refactored this PR to use a DisposableStack, which is part of the same spec. This replaces our code to manually call a parent dispose function to create a LIFO stack. The primary difference is that this provides robust error handling, if one dispose function fails then others will still be attempted.

This does add some state to the client object, which is maintained in a non-enumerable __PRIVATE__DISPOSABLE_STACK field. The first time we use withCleanup we add this stack to the client, and subsequent calls add their cleanup function to it. We also add a [Symbol.dispose] method which calls stack[Symbol.dispose](), ie calls the cleanup functions added to the stack. If there is an existing Symbol.dispose on the client before the first call to withCleanup then this is preserved by being added to the stack first.

@mcintyre94 mcintyre94 requested a review from lorisleiva March 26, 2026 09:45
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.

Nice! The disposable stack API is great!

@mcintyre94 mcintyre94 added this pull request to the merge queue Mar 27, 2026
Merged via the queue into main with commit 9c4fd6e Mar 27, 2026
13 checks passed
@mcintyre94 mcintyre94 deleted the with-cleanup branch March 27, 2026 17:45
@github-actions
Copy link
Copy Markdown
Contributor

🔎💬 Inkeep AI search and chat service is syncing content for source 'Solana Kit Docs'

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.

2 participants