Skip to content

Conversation

@torres-engineer
Copy link

@torres-engineer torres-engineer commented May 3, 2025

Closes #

🎯 Changes

As said in the title, I created the package tanstack-solid-query based on the package tanstack-react-query.

I had some problems with skipToken and not everything in @tanstack/react-query is in @tanstack/solid-query it seems.

✅ Checklist

  • I have followed the steps listed in the Contributing guide.
  • If necessary, I have added documentation related to the changes made.
  • I have added or updated the tests related to the changes made (or at least tried).

Summary by CodeRabbit

  • New Features

    • Introduced the @trpc/tanstack-solid-query package integrating tRPC with TanStack Solid Query for Solid.js, enabling type-safe queries, mutations, infinite queries, and subscriptions.
    • Added context providers and hooks for seamless access to tRPC client and query utilities in Solid.js applications.
    • Implemented advanced generation of query keys, filters, and mutation keys for improved cache management.
    • Provided comprehensive TypeScript typings and utilities supporting queries, mutations, infinite queries, and subscriptions.
    • Developed reactive subscription management with lifecycle callbacks and connection state tracking tailored for Solid.js.
    • Included helper utilities to facilitate testing of Solid.js components using tRPC and Solid Query.
  • Documentation

    • Added a detailed README with installation instructions, usage guidance, and links to full documentation.
  • Tests

    • Delivered extensive test suites covering query options, infinite queries, mutations, subscriptions, polymorphic router interfaces, query key generation, and utility functions to ensure correctness and type safety.
  • Chores

    • Added configuration files for TypeScript builds, Rollup bundling, Vitest testing, and repository management.

Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
@torres-engineer torres-engineer requested a review from a team as a code owner May 3, 2025 22:32
@vercel
Copy link

vercel bot commented May 3, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
www ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 16, 2025 3:34am

@vercel
Copy link

vercel bot commented May 3, 2025

@torres-engineer is attempting to deploy a commit to the trpc Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 3, 2025

Walkthrough

This change introduces a new package, @trpc/tanstack-solid-query, which integrates tRPC with TanStack Solid Query, providing type-safe query, mutation, and subscription utilities for Solid.js applications. The package includes comprehensive internal modules for context setup, proxy generation, query/mutation/subscription options, and utility types. It features a standardized Rollup build configuration, TypeScript setup, and documentation. Extensive test suites validate query keys, infinite queries, mutations, polymorphic router interfaces, subscriptions, and utility functions, ensuring robust type safety and runtime correctness. Supporting files for testing, configuration, and package management are also included.

Changes

File(s) Change Summary
README.md, package.json, rollup.config.ts, entrypoints.script.ts, tsconfig*.json, turbo.json, vitest.config.ts Added new package metadata, documentation, build scripts, TypeScript configurations, and Turborepo/Vitest setup for @trpc/tanstack-solid-query.
src/index.ts Introduced main entry point re-exporting context, proxy, query, mutation, subscription utilities, and types for public API surface.
src/internals/Context.tsx Added Solid.js context provider and hooks for tRPC and TanStack Query integration.
src/internals/createOptionsProxy.ts Implemented recursive proxy for generating type-safe query, mutation, and subscription options and keys for tRPC routers.
src/internals/queryOptions.ts, src/internals/infiniteQueryOptions.ts, src/internals/mutationOptions.ts, src/internals/subscriptionOptions.ts Added strongly-typed option generators for queries, infinite queries, mutations, and subscriptions, including handling for async iterables, abort signals, and lifecycle callbacks.
src/internals/types.ts Defined shared and public types for resolver definitions, query/mutation keys, infinite data, and request options.
src/internals/utils.ts Provided internal utility functions for key generation, argument extraction, async iterable handling, and lazy value unwrapping.
test/__helpers.tsx Introduced test helper for setting up Solid.js, tRPC, and QueryClient context for integration tests.
test/client.test.tsx, test/infiniteQueryOptions.test.tsx, test/mutationOptions.test.tsx, test/polymorphism.common.tsx, test/polymorphism.factory.tsx, test/polymorphism.test.tsx, test/queryKeyable.test.tsx, test/queryOptions.test.tsx, test/skipToken.test.tsx, test/useSubscription.test.tsx, test/utils.test.ts Added comprehensive test suites covering client usage, infinite queries, mutations, polymorphic routers, query/mutation keys and filters, query options, skip tokens, subscriptions, and utility functions.

Sequence Diagram(s)

sequenceDiagram
    participant App as Solid.js App
    participant TRPCProvider as TRPCProvider (Context)
    participant QueryClient as TanStack QueryClient
    participant TRPCClient as tRPC Client
    participant Proxy as TRPCOptionsProxy

    App->>TRPCProvider: Wrap application with provider
    TRPCProvider->>TRPCClient: Provide tRPC client instance
    TRPCProvider->>QueryClient: Provide QueryClient instance
    TRPCProvider->>Proxy: Create TRPCOptionsProxy with clients

    App->>Proxy: useTRPC() / useTRPCClient()
    Proxy->>TRPCClient: Call query/mutation/subscription as needed
    Proxy->>QueryClient: Use for cache, options, etc.

    App->>Proxy: Generate query/mutation/subscription options
    Proxy->>TRPCClient: Execute RPC call
    Proxy->>QueryClient: Manage query/mutation state
Loading

Suggested labels

♻️ autoupdate

Suggested reviewers

  • KATT

Poem

In the warren where queries hop and scurry,
A new Solid-tRPC bridge leaps in a hurry!
With proxies and keys, and types oh so neat,
Every mutation and subscription skips a beat.
Rabbits rejoice—tests run, all is bright—
End-to-end typesafe, from burrow to byte!
🐇✨

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c4d58c and f3f3b8f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • packages/tanstack-solid-query/package.json (1 hunks)
  • packages/tests/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/tanstack-solid-query/package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/tests/package.json
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: test
  • GitHub Check: build
  • GitHub Check: Lint and auto-fix
  • GitHub Check: Analyze (typescript)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 17

🔭 Outside diff range comments (1)
packages/tanstack-solid-query/test/skipToken.test.tsx (1)

1-67: 💡 Verification agent

❓ Verification inconclusive

Address commented-out skipToken tests

Almost the entire test file is commented out, which aligns with your PR description mentioning "some issues with the skipToken feature". Consider either:

  1. Implementing functioning tests if the feature is ready
  2. Adding a TODO comment explaining why tests are disabled
  3. Removing the file if the feature isn't planned for this release

This will help maintain a clean codebase and clear expectations about feature status.


Clean up disabled skipToken tests

The file packages/tanstack-solid-query/test/skipToken.test.tsx is fully commented out. To keep the codebase clear, please choose one of the following:

  • Add a clear TODO at the top of the file explaining why these tests are disabled (e.g. linking an issue or noting planned follow-up).
  • Re-enable and implement these tests if the skipToken API is ready for verification.
  • Remove the file entirely if testing for this feature isn’t planned in the current release.
🧹 Nitpick comments (18)
packages/tanstack-solid-query/README.md (2)

15-19: Nitpick: Fix blockquote formatting and grammar

Remove the blank line inside the warning blockquote and adjust the verb for better English usage.

Suggested diff:

- > [!WARNING]
- >
- > 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧
- > This package is currently in beta as we stabilize the API. We might do breaking changes without respecting semver.
+ > [!WARNING]
+ > 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧
+ > This package is currently in beta as we stabilize the API. We might make breaking changes without respecting semver.
🧰 Tools
🪛 LanguageTool

[grammar] ~18-~18: Collocation: With the noun “changes”, you should use the verb “make”.
Context: ... beta as we stabilize the API. We might do breaking changes without respecting sem...

(MAKE_A_CHANGE)


22-22: Nitpick: Replace bare URL and correct link path

Use a proper Markdown link and update the path to Solid Query documentation to avoid MD034 and align with the new package.

- Full documentation can be found at https://trpc.io/docs/client/tanstack-react-query/setup.
+ Full documentation can be found at [Solid Query docs](https://trpc.io/docs/client/tanstack-solid-query/setup).
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

22-22: Bare URL used
null

(MD034, no-bare-urls)

packages/tanstack-solid-query/tsconfig.build.json (1)

4-7: Refactor unnecessary type definitions in build config
The build config should focus on production declarations; ambient types like "vite/client" and "@testing-library/jest-dom" aren’t needed here. Consider removing the "types" array or limiting it to only what’s required during build.

packages/tanstack-solid-query/src/internals/Context.tsx (2)

5-5: Convert Component and JSX imports to type imports.

Both Component and JSX are only used as types and should be updated to use import type syntax.

-import { Component, createContext, JSX, useContext } from 'solid-js';
+import { createContext, useContext } from 'solid-js';
+import type { Component, JSX } from 'solid-js';
🧰 Tools
🪛 ESLint

[error] 5-5: Imports "Component" and "JSX" are only used as type.

(@typescript-eslint/consistent-type-imports)


21-21: Update documentation link to reference Solid Query.

The JSDoc link currently points to React Query documentation, but this is a Solid Query package.

- * @see https://trpc.io/docs/client/tanstack-react-query/setup#3a-setup-the-trpc-context-provider
+ * @see https://trpc.io/docs/client/tanstack-solid-query/setup#3a-setup-the-trpc-context-provider

If the documentation doesn't exist yet, consider updating the documentation as part of this PR.

packages/tanstack-solid-query/test/mutationOptions.test.tsx (1)

78-84: Prefer onMount over createEffect for one-shot side-effects

createEffect re–runs whenever any reactive value referenced inside the callback changes.
Although the current callback references no reactive sources, future edits (e.g. reading a signal) may turn this into an accidental loop that fires mutation.mutate repeatedly.

Using Solid’s onMount communicates the intent (“run exactly once after mount”) and prevents such hazards.

-import { createEffect } from 'solid-js';
+import { onMount } from 'solid-js';
 ...
-      const mutation = useMutation(() => options);
-
-      createEffect(() => {
-        mutation.mutate({
-          text: 'hello',
-        });
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-      });
+      const mutation = useMutation(() => options);
+
+      onMount(() => {
+        mutation.mutate({ text: 'hello' });
+      });
packages/tanstack-solid-query/test/infiniteQueryOptions.test.tsx (1)

226-228: Remove no-op statement

infiniteQueryOptions; is evaluated for its type only and produces no runtime side-effects.
Keeping it reads as leftover debugging code and may confuse readers.

-      infiniteQueryOptions;
packages/tanstack-solid-query/test/polymorphism.factory.tsx (1)

48-53: Global mutable counter can bleed across parallel tests

COUNTER is file-level state and will keep incrementing across multiple invocations of createExportRoute.
When the test runner executes suites in parallel this may lead to surprising IDs. Consider:

  • Reseting COUNTER in a beforeEach.
  • Moving the counter into the supplied dataProvider.
  • Using crypto.randomUUID() for uniqueness.
packages/tanstack-solid-query/test/queryKeyable.test.tsx (2)

9-9: Use import type to satisfy ESLint’s consistent-type-imports.

TRPCQueryKey is only used for compile-time assertions, so it should be imported with import type to avoid the runtime dependency and silence the linter error.

-import { TRPCQueryKey } from '../src';
+import type { TRPCQueryKey } from '../src';
🧰 Tools
🪛 ESLint

[error] 9-9: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)


11-34: Reduce duplication between testContext variants.

testContext and testContextWithErrorShape differ only by the errorFormatter details yet duplicate ~40 lines. A small factory that receives the errorFormatter (or the whole initTRPC.create options) will keep the tests DRY and easier to maintain.

Example sketch:

function createCtx(errorFormatter?: Parameters<typeof initTRPC.create>[0]['errorFormatter']) {
  const t = initTRPC.create({ errorFormatter });
  const appRouter = t.router({});
  return testSolidResource(appRouter);
}

Also applies to: 36-60

packages/tanstack-solid-query/src/internals/queryOptions.ts (2)

141-149: queryClient is unwrapped but never used

const queryClient = unwrapLazyArg(args.queryClient); introduces an unused variable, which
will trigger noUnusedLocals/noUnusedVariables in many TS configs.

If queryClient is only needed when the result is an AsyncIterable, move the unwrap
inside that branch to silence the warning and avoid unnecessary work:

-  const queryClient = unwrapLazyArg(args.queryClient);
...
-    if (isAsyncIterable(result)) {
-      return buildQueryFromAsyncIterable(result, queryClient, queryKey);
+    if (isAsyncIterable(result)) {
+      const qc = unwrapLazyArg(args.queryClient);
+      return buildQueryFromAsyncIterable(result, qc, queryKey);
     }

175-182: Generic information lost via double cast

queryFn as unknown as QueryFunction<any, any> erases the rich generics you worked
hard to preserve above, defeating type-safety for consumers. Consider keeping the
QueryFunction<coerceAsyncIterableToArray<…>, TRPCQueryKey, …> signature and use a
// @ts-expect-error annotation only where TS cannot infer correctly.

packages/tanstack-solid-query/src/internals/types.ts (1)

46-57: Name leaks implementation detail (React) in a Solid-specific package

TRPCReactRequestOptions is exported from a package named tanstack-solid-query.
Renaming to something neutral like TRPCQueryRequestOptions (or
TRPCSolidRequestOptions) avoids confusion for downstream users.

Refactor suggestion (public API change; verify before merge):

-export interface TRPCReactRequestOptions
+export interface TRPCQueryRequestOptions

and update all references.

packages/tanstack-solid-query/test/polymorphism.test.tsx (2)

17-17: Import types with import type to silence eslint & reduce bundle size

ESLint hints that this import is type-only. Switching to import type removes the run-time reference and keeps tree-shaking clean.

-import { JSX } from 'solid-js/jsx-runtime';
+import type { JSX } from 'solid-js/jsx-runtime';
🧰 Tools
🪛 ESLint

[error] 17-17: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)


227-235: Return the promise from onSuccess to keep the mutation’s lifecycle consistent

mutationOptions passes an async onSuccess that invalidates queries, but the promise is swallowed:

await client.invalidateQueries(...)

React/Solid Query waits for the returned promise to settle before firing onSettled.
Add a return so callers can chain off it in tests and UI logic.

-async onSuccess(data) {
-  props.onExportStarted(data.id);
-  await client.invalidateQueries(props.route.pathFilter());
-},
+onSuccess: async (data) => {
+  props.onExportStarted(data.id);
+  return client.invalidateQueries(props.route.pathFilter());
+},
packages/tanstack-solid-query/src/internals/createOptionsProxy.ts (1)

350-365: Minor type/logic mismatch in pathFilter helper

pathFilter accepts one argument (filters) per its declaration, yet the
proxy implementation spreads arg1 and ignores arg2. Accidental two-arg
calls will silently drop the second parameter.

Consider validating arity or forwarding both args for consistency with
queryFilter / infiniteQueryFilter.

packages/tanstack-solid-query/src/internals/subscriptionOptions.ts (1)

155-159: Use const for the tracked-property set

The trackedProps reference is never reassigned; favour const to communicate
intent and satisfy the ESLint prefer-const rule.

-let trackedProps = new Set<keyof $Result>([]);
+const trackedProps = new Set<keyof $Result>();
🧰 Tools
🪛 ESLint

[error] 155-155: 'trackedProps' is never reassigned. Use 'const' instead.

(prefer-const)

packages/tanstack-solid-query/test/__helpers.tsx (1)

10-10: Use import type for the JSX import

Since the JSX import is only used as a type and not as a value, you should use import type to avoid including it in the runtime bundle.

-import { JSX } from 'solid-js/jsx-runtime';
+import type { JSX } from 'solid-js/jsx-runtime';
🧰 Tools
🪛 ESLint

[error] 10-10: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 93403aa and a2793ee.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (29)
  • packages/tanstack-solid-query/README.md (1 hunks)
  • packages/tanstack-solid-query/entrypoints.script.ts (1 hunks)
  • packages/tanstack-solid-query/package.json (1 hunks)
  • packages/tanstack-solid-query/rollup.config.ts (1 hunks)
  • packages/tanstack-solid-query/src/index.ts (1 hunks)
  • packages/tanstack-solid-query/src/internals/Context.tsx (1 hunks)
  • packages/tanstack-solid-query/src/internals/createOptionsProxy.ts (1 hunks)
  • packages/tanstack-solid-query/src/internals/infiniteQueryOptions.ts (1 hunks)
  • packages/tanstack-solid-query/src/internals/mutationOptions.ts (1 hunks)
  • packages/tanstack-solid-query/src/internals/queryOptions.ts (1 hunks)
  • packages/tanstack-solid-query/src/internals/subscriptionOptions.ts (1 hunks)
  • packages/tanstack-solid-query/src/internals/types.ts (1 hunks)
  • packages/tanstack-solid-query/src/internals/utils.ts (1 hunks)
  • packages/tanstack-solid-query/test/__helpers.tsx (1 hunks)
  • packages/tanstack-solid-query/test/client.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/infiniteQueryOptions.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/mutationOptions.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/polymorphism.common.tsx (1 hunks)
  • packages/tanstack-solid-query/test/polymorphism.factory.tsx (1 hunks)
  • packages/tanstack-solid-query/test/polymorphism.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/queryKeyable.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/queryOptions.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/skipToken.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/useSubscription.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/utils.test.ts (1 hunks)
  • packages/tanstack-solid-query/tsconfig.build.json (1 hunks)
  • packages/tanstack-solid-query/tsconfig.json (1 hunks)
  • packages/tanstack-solid-query/turbo.json (1 hunks)
  • packages/tanstack-solid-query/vitest.config.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
packages/tanstack-solid-query/entrypoints.script.ts (2)
scripts/entrypoints.ts (1)
  • generateEntrypoints (30-143)
packages/tanstack-solid-query/rollup.config.ts (1)
  • input (5-5)
packages/tanstack-solid-query/rollup.config.ts (1)
scripts/getRollupConfig.ts (1)
  • buildConfig (19-27)
packages/tanstack-solid-query/test/utils.test.ts (1)
packages/tanstack-solid-query/src/internals/utils.ts (1)
  • getQueryKeyInternal (85-132)
packages/tanstack-solid-query/test/queryKeyable.test.tsx (3)
packages/tanstack-solid-query/test/__helpers.tsx (1)
  • testSolidResource (13-56)
packages/tanstack-solid-query/src/internals/types.ts (1)
  • TRPCQueryKey (86-89)
packages/client/src/TRPCClientError.ts (1)
  • TRPCClientErrorLike (19-20)
packages/tanstack-solid-query/src/internals/infiniteQueryOptions.ts (4)
packages/tanstack-solid-query/src/internals/types.ts (6)
  • ExtractCursorType (31-33)
  • TRPCInfiniteData (38-41)
  • TRPCQueryKey (86-89)
  • TRPCQueryBaseOptions (62-67)
  • TRPCQueryOptionsResult (72-76)
  • ResolverDef (15-20)
packages/server/src/unstable-core-do-not-import/types.ts (1)
  • DistributiveOmit (71-73)
packages/client/src/TRPCClientError.ts (1)
  • TRPCClientErrorLike (19-20)
packages/tanstack-solid-query/src/internals/utils.ts (2)
  • getClientArgs (26-46)
  • createTRPCOptionsResult (13-21)
packages/tanstack-solid-query/src/internals/utils.ts (2)
packages/tanstack-solid-query/src/internals/types.ts (4)
  • TRPCQueryOptionsResult (72-76)
  • TRPCQueryKey (86-89)
  • QueryType (81-81)
  • TRPCMutationKey (94-94)
packages/server/src/unstable-core-do-not-import/utils.ts (2)
  • isObject (30-32)
  • isFunction (35-37)
🪛 LanguageTool
packages/tanstack-solid-query/README.md

[grammar] ~18-~18: Collocation: With the noun “changes”, you should use the verb “make”.
Context: ... beta as we stabilize the API. We might do breaking changes without respecting sem...

(MAKE_A_CHANGE)

🪛 markdownlint-cli2 (0.17.2)
packages/tanstack-solid-query/README.md

14-14: Blank line inside blockquote
null

(MD028, no-blanks-blockquote)


22-22: Bare URL used
null

(MD034, no-bare-urls)

🪛 ESLint
packages/tanstack-solid-query/test/__helpers.tsx

[error] 10-10: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)

packages/tanstack-solid-query/src/internals/Context.tsx

[error] 5-5: Imports "Component" and "JSX" are only used as type.

(@typescript-eslint/consistent-type-imports)

packages/tanstack-solid-query/test/queryKeyable.test.tsx

[error] 9-9: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)

packages/tanstack-solid-query/src/internals/subscriptionOptions.ts

[error] 155-155: 'trackedProps' is never reassigned. Use 'const' instead.

(prefer-const)


[error] 254-254: Expected an assignment or function call and instead saw an expression.

(@typescript-eslint/no-unused-expressions)

packages/tanstack-solid-query/test/polymorphism.test.tsx

[error] 17-17: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)

🪛 Biome (1.9.4)
packages/tanstack-solid-query/test/useSubscription.test.tsx

[error] 15-31: Do not export from a test file.

(lint/suspicious/noExportsInTest)


[error] 35-40: Do not export from a test file.

(lint/suspicious/noExportsInTest)

packages/tanstack-solid-query/src/internals/types.ts

[error] 26-26: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: build
  • GitHub Check: test
  • GitHub Check: Analyze (typescript)
  • GitHub Check: Lint and auto-fix
🔇 Additional comments (20)
packages/tanstack-solid-query/turbo.json (2)

2-3: Verify extends path correctness
Ensure that the "extends": ["//"] directive correctly inherits from your root turbo.json (e.g., ../../turbo.json). If "//" is a custom alias, confirm it resolves as intended in both CI and local development.


4-4: Confirm task outputs for caching
The codegen-entrypoints task outputs (package.json and dist/**) align with your build outputs and export paths. This looks correct for Turborepo incremental caching.

packages/tanstack-solid-query/vitest.config.ts (1)

1-1: Re-export shared Vitest configuration
The proxy to ../../vitest.config ensures consistency across packages. Verify the relative path resolves correctly and your build supports .ts Vitest configs.

packages/tanstack-solid-query/tsconfig.json (2)

2-3: Confirm base TS configuration and include paths
Ensure "extends": "../../tsconfig.json" points to your monorepo’s root config and that "include": ["src", "test"] captures all source & test files for this package.


5-8: Add Vitest type definitions if needed
The compilerOptions "types": ["vite/client", "@testing-library/jest-dom"] enable Vite and DOM matcher types, but may omit Vitest globals (describe, it, expect). Ensure "vitest" or "vitest/globals" types are included either here or in your base config to avoid missing global types.

packages/tanstack-solid-query/tsconfig.build.json (1)

2-3: Confirm build TS configuration inheritance
Verify that "extends": "../../tsconfig.build.json" correctly references your root build config for consistent declaration settings.

packages/tanstack-solid-query/test/polymorphism.common.tsx (1)

1-6: LGTM: Good setup for tRPC polymorphism testing with Solid.js

The file correctly sets up the JSX pragma for Solid.js, initializes a tRPC instance, and exports both the instance and necessary type information for polymorphic router testing.

packages/tanstack-solid-query/rollup.config.ts (1)

1-12: LGTM: Standard Rollup configuration

The configuration follows the project's pattern of reusing the shared buildConfig function, correctly specifies the entry point, and properly resolves the package directory path.

packages/tanstack-solid-query/test/utils.test.ts (1)

1-47: LGTM: Comprehensive test coverage for query key generation

The tests effectively cover different use cases for the getQueryKeyInternal utility, validating correct behavior for query keys, router keys, and infinite query keys with appropriate snapshot assertions.

packages/tanstack-solid-query/src/internals/Context.tsx (1)

1-69: Well-designed context provider for tRPC with Solid.js.

The implementation provides a clean and type-safe way to integrate tRPC with Solid.js applications:

  • It properly creates separate contexts for the client and the options proxy
  • Both hooks include appropriate error handling if used outside the provider
  • The types are well-defined and ensure type safety throughout the application
  • The pattern aligns with Solid.js best practices for context creation and usage

This is a strong foundation for the Solid.js integration with tRPC.

🧰 Tools
🪛 ESLint

[error] 5-5: Imports "Component" and "JSX" are only used as type.

(@typescript-eslint/consistent-type-imports)

packages/tanstack-solid-query/test/polymorphism.factory.tsx (1)

88-95: Returned status object is stale after readiness update

downloadUri is added to dataProvider[index], but the function returns the pre-update exportInstance, so callers never receive the ready link on the second poll.

If the intended behaviour is “first poll => queued, second poll => ready”, the updated object should be returned:

-        dataProvider[index] = {
+        const updated = {
           ...exportInstance,
           downloadUri: `example.com/export-${exportInstance.name}.csv`,
         };
-
-        return exportInstance;
+        dataProvider[index] = updated;
+        return updated;

If withholding the link deliberately, please add a code comment explaining why the stale object is returned.

packages/tanstack-solid-query/test/useSubscription.test.tsx (1)

60-122: Graceful cleanup of EventEmitter listeners.

getCtx creates a shared EventEmitter but does not ee.removeAllListeners() after the tests finish, relying on garbage-collection. Consider returning a dispose() helper (or re-using testSolidResource’s resource manager) to explicitly clean up listeners to avoid cross-test interference, especially when running the suite in watch mode.

packages/tanstack-solid-query/src/index.ts (1)

26-26: Verify minimum TypeScript version for export type * syntax.

export type * from './internals/types'; is only supported in TypeScript ≥ 5.2.
If the package targets earlier versions, switch to explicit re-exports:

export type { TRPCQueryKey, /* … */ } from './internals/types';

Otherwise, state the minimum TS requirement in package.json ("typescript": ">=5.2").

packages/tanstack-solid-query/src/internals/infiniteQueryOptions.ts (1)

177-184: initialPageParam derivation may mis-handle undefined cursor

opts?.initialCursor ?? (input as any)?.cursor will fall back to
(input as any)?.cursor even when initialCursor is explicitly null,
which might be a valid first page marker. Consider a stricter “defined”
check:

-      initialPageParam: opts?.initialCursor ?? (input as any)?.cursor,
+      initialPageParam:
+        opts.initialCursor !== undefined
+          ? opts.initialCursor
+          : (input as any)?.cursor,
packages/tanstack-solid-query/src/internals/mutationOptions.ts (2)

114-131: Nice use of spread order to make library overrides authoritative

Spreading opts first and then redefining mutationKey, mutationFn, and onSuccess ensures reserved fields cannot be overwritten by the caller – great job!


108-112:

❌ Incorrect review comment

Pass only TRPC-specific options into the client call

getClientArgs([path, { input }], opts) forwards the full opts object (which contains Solid-Query–specific settings such as onSuccess, retry, etc.) to the tRPC client.
Those keys are not recognised by client.mutation() and will be sent over the wire as part of the JSON payload if getClientArgs does not strip them internally, potentially blowing up the request size or causing server-side validation errors.

Please double-check what getClientArgs keeps. If it does not already sanitise the object, pass only the sub-object that is actually meant for the tRPC client (e.g. opts.trpc).


🏁 Script executed:

#!/bin/bash
# Locate the implementation of getClientArgs to verify option sanitization
rg "getClientArgs" -n packages/tanstack-solid-query/src -A5 -B5

Length of output: 6865


🏁 Script executed:

#!/usr/bin/env bash
# Print the first 500 lines of utils.ts to inspect getClientArgs implementation
sed -n '1,500p' packages/tanstack-solid-query/src/internals/utils.ts

Length of output: 3594


getClientArgs already strips non-TRPC options

The helper implemented in packages/tanstack-solid-query/src/internals/utils.ts only returns the trpc sub-object of opts, so Solid-Query–specific settings (e.g. onSuccess, retry) are never forwarded:

export function getClientArgs<TOptions>(
  queryKey: TRPCQueryKey,
  opts: TOptions,
  
) {
  // …
  return [
    path.join('.'),
    input,
    (opts as any)?.trpc  // only opts.trpc is passed through
  ] as const;
}

– No further sanitization is needed in mutationOptions.ts
– You can safely continue using getClientArgs([path, { input }], opts)

Likely an incorrect or invalid review comment.

packages/tanstack-solid-query/test/queryOptions.test.tsx (1)

56-58: using declarations are still Stage-3 – confirm test runner support

The test uses await using ctx = testContext();.
using (disposable resources proposal) is not yet part of ES2024 and is disabled in many TS/JS runtimes. Make sure:

  1. tsconfig has "useDefineForClassFields": false and an appropriate "lib" entry enabling the feature.
  2. The Vitest/Babel pipeline is configured to down-transpile or the Node version in CI understands it.

Otherwise the suite will fail to start outside your local environment.

packages/tanstack-solid-query/test/__helpers.tsx (1)

13-56: LGTM! Well-structured test helper for Solid.js integration

The testSolidResource function provides a clean and comprehensive testing utility for Solid.js components that use tRPC. It correctly sets up the necessary providers and returns all the required resources for testing.

packages/tanstack-solid-query/test/client.test.tsx (1)

37-69: LGTM! Comprehensive test for the useTRPCClient hook

The test is well-structured and effectively validates both runtime behavior and type correctness of the useTRPCClient hook in a Solid.js context. Good use of modern JavaScript features like using declarations for resource management.

packages/tanstack-solid-query/package.json (1)

1-83: LGTM! Package configuration is well-structured

The package configuration is comprehensive and properly sets up the build, dependencies, and exports for the Solid.js integration.

Comment on lines +4 to +5
// eslint-disable-next-line no-console
generateEntrypoints(input).catch(console.error);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ensure script failures propagate exit code
Currently the .catch(console.error) logs errors but exits with code 0, masking failures. Propagate a non-zero exit on error:

- generateEntrypoints(input).catch(console.error);
+ generateEntrypoints(input).catch((error) => {
+   console.error(error);
+   process.exit(1);
+ });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// eslint-disable-next-line no-console
generateEntrypoints(input).catch(console.error);
// eslint-disable-next-line no-console
generateEntrypoints(input).catch((error) => {
console.error(error);
process.exit(1);
});
🤖 Prompt for AI Agents (early access)
In packages/tanstack-solid-query/entrypoints.script.ts at lines 4 to 5, the script catches errors and logs them using console.error but does not propagate a non-zero exit code, causing the process to exit with code 0 even on failure. Modify the catch block to log the error and then call process.exit(1) to ensure the script exits with a failure code when an error occurs.

Comment on lines +40 to +44
items: fixtureData.slice(input.cursor, input.cursor + 1),
next:
input.cursor + 1 > fixtureData.length
? undefined
: input.cursor + 1,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Off-by-one in next cursor calculation

When input.cursor points at the last element (fixtureData.length - 1), the current expression returns next = fixtureData.length, triggering an extra request that yields an empty page.
Replacing > with >= avoids this unnecessary request.

-            next:
-              input.cursor + 1 > fixtureData.length
-                ? undefined
-                : input.cursor + 1,
+            next:
+              input.cursor + 1 >= fixtureData.length
+                ? undefined
+                : input.cursor + 1,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
items: fixtureData.slice(input.cursor, input.cursor + 1),
next:
input.cursor + 1 > fixtureData.length
? undefined
: input.cursor + 1,
items: fixtureData.slice(input.cursor, input.cursor + 1),
next:
input.cursor + 1 >= fixtureData.length
? undefined
: input.cursor + 1,
🤖 Prompt for AI Agents (early access)
In packages/tanstack-solid-query/test/infiniteQueryOptions.test.tsx around lines 40 to 44, the calculation of the `next` cursor uses `input.cursor + 1 > fixtureData.length`, which causes an off-by-one error by allowing `next` to equal `fixtureData.length` and triggering an extra empty request. Fix this by changing the comparison operator from `>` to `>=` to prevent `next` from exceeding the last valid index and avoid unnecessary requests.

Comment on lines 15 to 40
/* eslint-disable no-console */
export const suppressLogs = () => {
const log = console.log;
const error = console.error;
const noop = () => {
// ignore
};
console.log = noop;
console.error = noop;

function cleanup() {
console.log = log;
console.error = error;
}

return makeResource(cleanup, cleanup);
};

/**
* Pause logging until the promise resolves or throws
*/
export const suppressLogsUntil = async (fn: () => Promise<void>) => {
using _ = suppressLogs();

await fn();
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid exporting helpers from a test file.

Biome flags these exports (suppressLogs, suppressLogsUntil) because test files should not leak public API.
Either:

  1. Remove export (they’re only consumed inside this file), or
  2. Move them to a dedicated helper (test/__helpers/subscription.ts) and import from there.
-export const suppressLogs = () => {
+const suppressLogs = () => {-export const suppressLogsUntil = async (fn: () => Promise<void>) => {
+const suppressLogsUntil = async (fn: () => Promise<void>) => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/* eslint-disable no-console */
export const suppressLogs = () => {
const log = console.log;
const error = console.error;
const noop = () => {
// ignore
};
console.log = noop;
console.error = noop;
function cleanup() {
console.log = log;
console.error = error;
}
return makeResource(cleanup, cleanup);
};
/**
* Pause logging until the promise resolves or throws
*/
export const suppressLogsUntil = async (fn: () => Promise<void>) => {
using _ = suppressLogs();
await fn();
};
/* eslint-disable no-console */
const suppressLogs = () => {
const log = console.log;
const error = console.error;
const noop = () => {
// ignore
};
console.log = noop;
console.error = noop;
function cleanup() {
console.log = log;
console.error = error;
}
return makeResource(cleanup, cleanup);
};
/**
* Pause logging until the promise resolves or throws
*/
const suppressLogsUntil = async (fn: () => Promise<void>) => {
using _ = suppressLogs();
await fn();
};
🧰 Tools
🪛 Biome (1.9.4)

[error] 15-31: Do not export from a test file.

(lint/suspicious/noExportsInTest)


[error] 35-40: Do not export from a test file.

(lint/suspicious/noExportsInTest)

🤖 Prompt for AI Agents (early access)
In packages/tanstack-solid-query/test/useSubscription.test.tsx between lines 15 and 40, the helper functions suppressLogs and suppressLogsUntil are exported, which exposes them as part of the public API from a test file. To fix this, remove the export keyword from both functions if they are only used within this test file, or alternatively move these helper functions to a dedicated helper file such as test/__helpers/subscription.ts and import them into this test file.

Comment on lines +325 to +347
const callIt = (type: TRPCProcedureType): any => {
return (path: string, input: unknown, trpcOpts: TRPCRequestOptions) => {
if ('router' in opts) {
return Promise.resolve(unwrapLazyArg(opts.ctx)).then((ctx) =>
callTRPCProcedure({
router: opts.router,
path: path,
getRawInput: async () => input,
ctx: ctx,
type: type,
signal: undefined,
}),
);
}

const untypedClient =
opts.client instanceof TRPCUntypedClient
? opts.client
: getUntypedClient(opts.client);

return untypedClient[type](path, input, trpcOpts);
};
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Forward user-supplied request options to callTRPCProcedure

callIt swallows the trpcOpts parameter when executing through a router
instance, meaning headers, abort signals, or transformers passed by the caller
are lost on server-side paths.

-          callTRPCProcedure({
+          callTRPCProcedure({
             router: opts.router,
             path: path,
             getRawInput: async () => input,
             ctx: ctx,
             type: type,
-            signal: undefined,
+            signal: trpcOpts?.signal,
+            headers: (typeof trpcOpts?.headers === 'function'
+              ? await trpcOpts.headers()
+              : trpcOpts?.headers) as any,
           }),

This keeps client- and server-side behaviour aligned.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents (early access)
In packages/tanstack-solid-query/src/internals/createOptionsProxy.ts between lines 325 and 347, the function callIt does not forward the user-supplied trpcOpts when calling callTRPCProcedure for router instances, causing loss of headers, abort signals, or transformers. Modify the callTRPCProcedure invocation to include the trpcOpts parameter so that all user request options are preserved and client-server behavior remains consistent.

Comment on lines +283 to +292
createEffect(() => {
if (!opts.enabled) {
return;
}
reset();

return () => {
currentSubscription?.();
};
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Duplicate reset logic can spawn multiple subscriptions

reset() is executed both in the initial effect (line 231) and the cleanup
effect (line 283) when opts.enabled is true. If opts.queryKey is stable
but some other reactive source triggers both effects, you may end up
unsubscribing and resubscribing twice in quick succession.

Consider centralising the subscription lifecycle in a single effect to prevent
race-conditions and wasted network traffic.

🤖 Prompt for AI Agents (early access)
In packages/tanstack-solid-query/src/internals/subscriptionOptions.ts around lines 283 to 292, the reset() function is called both in the initial effect and the cleanup effect when opts.enabled is true, causing duplicate subscription logic and potential multiple rapid unsubscribe/resubscribe cycles. To fix this, consolidate the subscription lifecycle management into a single createEffect block that handles both setup and cleanup, ensuring reset() is called only once per subscription cycle to avoid race conditions and redundant network requests.

"main": "dist/index.js",
"module": "dist/index.mjs",
"typings": "dist/index.d.ts",
"homepage": "https://trpc.io/docs/client/tanstack-react-query/setup",
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Update homepage URL to point to Solid.js documentation

The homepage URL currently points to the React Query documentation. It should be updated to point to documentation specifically for the Solid.js integration.

-  "homepage": "https://trpc.io/docs/client/tanstack-react-query/setup",
+  "homepage": "https://trpc.io/docs/client/tanstack-solid-query/setup",

Note: If the documentation doesn't exist yet, you might need to create it or update this URL once the documentation is available.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"homepage": "https://trpc.io/docs/client/tanstack-react-query/setup",
"homepage": "https://trpc.io/docs/client/tanstack-solid-query/setup",
🤖 Prompt for AI Agents (early access)
In packages/tanstack-solid-query/package.json at line 10, the homepage URL currently points to the React Query documentation. Update this URL to point to the Solid.js integration documentation for accuracy. If the Solid.js documentation does not exist yet, either create it or update this URL later when it becomes available.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
packages/tanstack-solid-query/src/internals/subscriptionOptions.ts (2)

251-255: Ineffective effect with no side-effects

The createEffect block references reset without calling it and calls getInitialState() without using the result, producing no actual side effects. This will trigger the ESLint error for unused expressions.

-createEffect(() => {
-  reset;
-
-  getInitialState();
-});
🧰 Tools
🪛 ESLint

[error] 252-252: Expected an assignment or function call and instead saw an expression.

(@typescript-eslint/no-unused-expressions)


281-290: Duplicate reset logic can cause multiple rapid subscriptions

The reset() function is called both in the initial effect (line 232) and again in this effect (line 285) when opts.enabled is true. This duplication can lead to unnecessary subscription cycles if the dependency tracking causes both effects to run in quick succession.

Consider consolidating the subscription lifecycle management into a single effect:

-createEffect(() => {
-  hashKey(opts.queryKey);
-
-  reset();
-});

// ...

-createEffect(() => {
-  if (!opts.enabled) {
-    return;
-  }
-  reset();
-
-  return () => {
-    currentSubscription?.();
-  };
-});

+createEffect(() => {
+  // Force the effect to track the queryKey
+  hashKey(opts.queryKey);
+  
+  if (!opts.enabled) {
+    // Clean up any existing subscription when disabled
+    currentSubscription?.();
+    updateState(getInitialState);
+    return;
+  }
+  
+  // Initialize or reset the subscription when enabled or dependencies change
+  reset();
+  
+  return () => {
+    currentSubscription?.();
+  };
+});
🧹 Nitpick comments (7)
packages/tanstack-solid-query/src/internals/subscriptionOptions.ts (7)

168-170: Consider adding error handling during unsubscription

The currentSubscription?.() call doesn't handle potential errors that could occur during unsubscription. This might lead to incomplete cleanup if an error occurs.

-  currentSubscription?.();
+  try {
+    currentSubscription?.();
+  } catch (error) {
+    console.error('Error during subscription cleanup:', error);
+  }

177-182: Type casting to any can be replaced with more specific typing

The type assertion ...(prev as any) is using any, which bypasses type checking. Consider using a more specific type assertion to maintain type safety.

-        updateState((prev) => ({
-          ...(prev as any),
-          status: 'pending',
-          error: null,
-        }));
+        updateState((prev) => ({
+          ...prev,
+          status: 'pending' as const,
+          error: null,
+        }));

185-191: Repeated type casting pattern can be extracted into a utility function

The pattern of spreading (prev as any) and updating specific properties is repeated in several places. Consider extracting this into a utility function to reduce duplication and improve type safety.

+  // Add this helper function
+  const updateStateWithStatus = <S extends TRPCSubscriptionStatus>(
+    status: S,
+    updates: Partial<$Result> = {}
+  ) => {
+    updateState((prev) => ({
+      ...prev,
+      status,
+      ...updates,
+    }));
+  };

   // Then replace the instances with:
-  updateState((prev) => ({
-    ...(prev as any),
-    status: 'pending',
-    data,
-    error: null,
-  }));
+  updateStateWithStatus('pending', { data, error: null });

-  updateState((prev) => ({
-    ...(prev as any),
-    status: 'error',
-    error,
-  }));
+  updateStateWithStatus('error', { error });

Also applies to: 193-199


200-221: Missing default case in switch statement

The switch statement for handling connection state changes doesn't have a default case. While the current implementation covers all known states, adding a default case would make the code more robust against future changes.

         switch (result.state) {
           case 'connecting':
             return {
               ...prev,
               status: 'connecting',
               error: result.error,
             };
           case 'pending':
             // handled in onStarted
             return prev;
           case 'idle':
             return {
               ...prev,
               status: 'idle',
               data: undefined,
               error: null,
             };
+          default:
+            console.warn(`Unhandled connection state: ${result.state}`);
+            return prev;
         }

258-278: State update logic could be more efficient

The current implementation creates a new tracked result object on every state update, even when only specific properties change. Consider a more granular update approach to improve performance.

A more selective update mechanism could be implemented to only replace the specific properties that have changed, rather than creating an entirely new proxy object. This would be especially beneficial for larger state objects.

-  const updateState = (callback: (prevState: $Result) => $Result) => {
-    const prev = resultRef;
-    const next = (resultRef = callback(prev));
-
-    let shouldUpdate = false;
-    for (const key of trackedProps) {
-      if (prev[key] !== next[key]) {
-        shouldUpdate = true;
-        break;
-      }
-    }
-    if (shouldUpdate) {
-      setState(trackResult(next, addTrackedProp));
-    }
-  };
+  const updateState = (callback: (prevState: $Result) => $Result) => {
+    const prev = resultRef;
+    const next = (resultRef = callback(prev));
+
+    // Only update the specific properties that have changed and are being tracked
+    for (const key of trackedProps) {
+      if (prev[key] !== next[key]) {
+        setState(key, next[key]);
+      }
+    }
+  };

12-14: The imported TRPCQueryOptionsResult type doesn't seem to be used directly

The TRPCQueryOptionsResult type is imported but only used indirectly through the TRPCSubscriptionOptionsOut interface. Consider whether this import is necessary or if the types could be restructured for clarity.


1-15: Consider organizing imports for better readability

The imports mix external and internal dependencies. Consider organizing them by grouping external dependencies first, followed by internal ones, with a blank line separating the groups.

 import type { SkipToken } from '@tanstack/solid-query';
 import { hashKey, skipToken } from '@tanstack/solid-query';
 import type { TRPCClientErrorLike, TRPCUntypedClient } from '@trpc/client';
 import type { TRPCConnectionState } from '@trpc/client/unstable-internals';
 import type { Unsubscribable } from '@trpc/server/observable';
 import type { inferAsyncIterableYield } from '@trpc/server/unstable-core-do-not-import';
 import { createEffect } from 'solid-js';
 import { createStore } from 'solid-js/store';
+
 import type {
   ResolverDef,
   TRPCQueryKey,
   TRPCQueryOptionsResult,
 } from './types';
 import { createTRPCOptionsResult } from './utils';
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2793ee and 1898894.

📒 Files selected for processing (4)
  • packages/tanstack-solid-query/package.json (1 hunks)
  • packages/tanstack-solid-query/src/internals/Context.tsx (1 hunks)
  • packages/tanstack-solid-query/src/internals/subscriptionOptions.ts (1 hunks)
  • packages/tests/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/tests/package.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/tanstack-solid-query/package.json
  • packages/tanstack-solid-query/src/internals/Context.tsx
🧰 Additional context used
🪛 ESLint
packages/tanstack-solid-query/src/internals/subscriptionOptions.ts

[error] 252-252: Expected an assignment or function call and instead saw an expression.

(@typescript-eslint/no-unused-expressions)

import type { TRPCClientErrorLike, TRPCUntypedClient } from '@trpc/client';
import type { TRPCConnectionState } from '@trpc/client/unstable-internals';
import type { Unsubscribable } from '@trpc/server/observable';
import type { inferAsyncIterableYield } from '@trpc/server/unstable-core-do-not-import';
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Avoid importing from unstable APIs

The import from @trpc/server/unstable-core-do-not-import suggests you're using unstable APIs that may change in future versions. Consider exploring more stable alternatives if available.


🌐 Web query:

What are the stable alternatives to @trpc/server/unstable-core-do-not-import in the tRPC library?

💡 Result:

The @trpc/server/unstable-core-do-not-import module in tRPC is intentionally named to discourage direct imports, as indicated by its name. This module contains internal implementation details that aren't intended for public use but are necessary for the library's functionality.

Recommended Alternatives

Based on the tRPC team's guidance, there are several stable alternatives you should use instead:

  1. Primary Package Imports: The recommended approach is to import directly from the main packages[6]:

    • @trpc/server
    • @trpc/client
    • @trpc/react-query
    • @trpc/next
  2. Plugin-Specific Entry Points: The tRPC team is considering creating dedicated entrypoints for plugin development, such as @trpc/server/plugin[6]. This would provide a stable API for extending tRPC functionality.

  3. JSR Package: For newer environments, tRPC offers @trpc/server on JSR which provides the same core functionality with stable APIs[9].

Why Avoid Unstable Core Imports

The file itself contains clear guidance about not importing from it:

/**
 * **DO NOT IMPORT FROM THIS FILE**
 *
 * This file is here to:
 * - make TypeScript happy and prevent _"The inferred type of 'createContext' cannot be named without a reference to [...]"_.
 * - the the glue between the official `@trpc/*`-packages
 *
 * If you seem to need to import anything from here, please open an issue at https://github.com/trpc/trpc/issues
 */
```[4]

Developers who have attempted to import from this module have encountered issues, particularly in monorepos or when upgrading versions. One developer mentioned resolving type issues by explicitly re-exporting unresolved types, but acknowledged this approach is not recommended[2].

## Ongoing Improvements

The tRPC team is aware of the challenges with unstable imports and is working to address them:

1. There's an active feature request to "Remove that unstable imports that we can from the libs"[6].

2. The team is planning for v11 of tRPC, which might include improvements to the package structure and API stability[2].

3. When upgrading to v11, some developers have encountered TypeScript errors related to these unstable imports, which were resolved by adding the "DOM" lib to their TypeScript configuration[8].

If you're building an extension for tRPC or encountering specific challenges that require these internal modules, the recommended approach is to open an issue on the tRPC GitHub repository to request a stable API for your use case.

Citations:

- 1: https://trpc.io/faq
- 2: https://github.com/trpc/trpc/issues/3496
- 3: https://discord-questions.trpc.io/c/1020132255567454310?page=2
- 4: https://github.com/trpc/trpc/blob/next/packages/server/src/unstable-core-do-not-import.ts
- 5: https://pmc.ncbi.nlm.nih.gov/articles/PMC7820370/
- 6: https://github.com/trpc/trpc/issues/5484
- 7: https://pmc.ncbi.nlm.nih.gov/articles/PMC9675567/
- 8: https://discord-questions.trpc.io/m/1280593106311450665
- 9: https://jsr.io/@trpc/server
- 10: https://www.youtube.com/watch?v=7undQz4u1t0

---



</details>

**Avoid importing from unstable tRPC internals**

The import  
```ts
import type { inferAsyncIterableYield } from '@trpc/server/unstable-core-do-not-import';

pulls in an internal, unsupported API that may break without warning. Instead, use one of tRPC’s public entrypoints:

  • If inferAsyncIterableYield is exposed in @trpc/server, import it directly:
    import type { inferAsyncIterableYield } from '@trpc/server';
  • Otherwise, open an issue on the tRPC repo to request a stable export (e.g. under a future @trpc/server/plugin entrypoint), or locally re-export the type until it’s officially exposed.

This will safeguard your code against breaking changes when upgrading tRPC.

🤖 Prompt for AI Agents (early access)
In packages/tanstack-solid-query/src/internals/subscriptionOptions.ts at line 6, the import of inferAsyncIterableYield from '@trpc/server/unstable-core-do-not-import' uses an unstable internal API that may change unexpectedly. To fix this, replace the import to come from the stable public package '@trpc/server' if inferAsyncIterableYield is exported there. If it is not available publicly, consider opening an issue on the tRPC repository to request a stable export or create a local re-export of the type until it is officially exposed. This change will prevent future breakage due to unstable internal API usage.

Copy link
Member

@juliusmarminge juliusmarminge left a comment

Choose a reason for hiding this comment

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

👀👀👀

Please adress CI, it got quite a few errors. Please take a look at Coderabbit review as well

If stuff is missing in SolidQuery, I'd suggest go to the TanStack/query repo and adding it there first. I noticed there was quite a few deviations in vue-query when I tried to port this to Vue a while back.

Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
packages/tanstack-solid-query/test/infiniteQueryOptions.test.tsx (1)

41-43: ⚠️ Potential issue

Off-by-one error in next cursor calculation is still present

The comparison input.cursor + 1 > fixtureData.length allows next
to become fixtureData.length, which triggers an unnecessary extra
request that returns an empty page.
Switch to >= so next is undefined once the end of the dataset
is reached.

-next:
-  input.cursor + 1 > fixtureData.length
-    ? undefined
-    : input.cursor + 1,
+next:
+  input.cursor + 1 >= fixtureData.length
+    ? undefined
+    : input.cursor + 1,

This occurs in both router definitions (lines 41-43 and 334-336).

Also applies to: 334-336

packages/tanstack-solid-query/src/internals/types.ts (1)

25-26: ⚠️ Potential issue

Replace void with undefined in union type

Using void inside a union is confusing because void is intended
for return positions; static analysis (noConfusingVoidType) flags
this. Replace it with undefined to express “value may be absent”.

-type CursorInput = { cursor?: any };
-export type OptionalCursorInput = CursorInput | void;
+type CursorInput = { cursor?: any };
+export type OptionalCursorInput = CursorInput | undefined;

This keeps the intent clear and silences the linter.

🧰 Tools
🪛 Biome (1.9.4)

[error] 26-26: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

🧹 Nitpick comments (4)
packages/tanstack-solid-query/test/polymorphism.test.tsx (3)

17-17: Use import type for type-only imports

The JSX import is only used as a type and not as a value. Following TypeScript best practices, it should be imported using import type.

-import { JSX } from 'solid-js/jsx-runtime';
+import type { JSX } from 'solid-js/jsx-runtime';
🧰 Tools
🪛 ESLint

[error] 17-17: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)


28-28: Consider adding export type for Factory

The Factory import contains types that are used throughout the test file. For clarity and to follow the same pattern, consider using a type import here as well.

-import * as Factory from './polymorphism.factory';
+import type * as Factory from './polymorphism.factory';
+import { createExportRoute } from './polymorphism.factory';

276-276: Consider handling the null case more explicitly

Using -1 as a fallback ID when currentExport is null could lead to unexpected behavior if the API doesn't handle negative IDs properly. Consider disabling the query entirely or using a more explicit approach.

-      { id: props.currentExport ?? -1 },
+      { id: props.currentExport! },
       { enabled: props.currentExport !== null },

The non-null assertion operator is safe here because the query is only enabled when currentExport is not null.

packages/tanstack-solid-query/README.md (1)

13-15: Remove blank line inside blockquote for lint compliance
The blank line between the description and the warning block violates MD028 (no blank lines in a blockquote).
Apply this diff to remove it:

@@ lines 13-15
- > 
  > [!WARNING]
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

14-14: Blank line inside blockquote
null

(MD028, no-blanks-blockquote)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1898894 and c08ced1.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • packages/tanstack-solid-query/README.md (1 hunks)
  • packages/tanstack-solid-query/package.json (1 hunks)
  • packages/tanstack-solid-query/src/internals/infiniteQueryOptions.ts (1 hunks)
  • packages/tanstack-solid-query/src/internals/queryOptions.ts (1 hunks)
  • packages/tanstack-solid-query/src/internals/subscriptionOptions.ts (1 hunks)
  • packages/tanstack-solid-query/src/internals/types.ts (1 hunks)
  • packages/tanstack-solid-query/test/infiniteQueryOptions.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/polymorphism.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/skipToken.test.tsx (1 hunks)
  • packages/tanstack-solid-query/tsconfig.build.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/tanstack-solid-query/tsconfig.build.json
  • packages/tanstack-solid-query/test/skipToken.test.tsx
  • packages/tanstack-solid-query/package.json
  • packages/tanstack-solid-query/src/internals/infiniteQueryOptions.ts
  • packages/tanstack-solid-query/src/internals/subscriptionOptions.ts
  • packages/tanstack-solid-query/src/internals/queryOptions.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/tanstack-solid-query/test/polymorphism.test.tsx (4)
packages/tanstack-solid-query/test/polymorphism.factory.tsx (2)
  • FileExportStatusType (31-31)
  • ExportRouteLike (105-105)
packages/tanstack-solid-query/test/polymorphism.common.tsx (1)
  • t (4-4)
packages/tanstack-solid-query/test/__helpers.tsx (1)
  • testSolidResource (13-56)
packages/tanstack-solid-query/src/internals/createOptionsProxy.ts (1)
  • inferOutput (86-91)
🪛 ESLint
packages/tanstack-solid-query/test/polymorphism.test.tsx

[error] 17-17: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)

🪛 Biome (1.9.4)
packages/tanstack-solid-query/src/internals/types.ts

[error] 26-26: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

🪛 markdownlint-cli2 (0.17.2)
packages/tanstack-solid-query/README.md

14-14: Blank line inside blockquote
null

(MD028, no-blanks-blockquote)

🔇 Additional comments (9)
packages/tanstack-solid-query/test/polymorphism.test.tsx (4)

89-89: Great use of the new using syntax

Using the await using pattern for the test context is an excellent practice for ensuring proper cleanup of resources.


100-102: Good use of Solid.js primitives

Using createSignal instead of React's useState correctly follows Solid.js patterns, demonstrating a good understanding of the differences between the frameworks.


267-273: Excellent use of generics for type safety

The type parameter TStatus with constraint to Factory.ExportRouteLike['status'] ensures type safety while allowing the component to work with any compatible export route. The inferOutput utility type is used correctly to type the data passed to renderAdditionalFields.


1-315: Overall excellent implementation of polymorphic router interfaces

This test file demonstrates a robust approach to using polymorphic router interfaces in Solid.js with tRPC. The code:

  1. Creates reusable router factories with common interfaces
  2. Shows how to merge additional procedures while maintaining polymorphic compatibility
  3. Implements reusable UI components that work with any route matching the interface
  4. Properly tests user interactions with mutations and queries

The patterns established here provide an excellent foundation for developers to create type-safe, reusable components that work with tRPC routers in Solid.js applications.

🧰 Tools
🪛 ESLint

[error] 17-17: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)

packages/tanstack-solid-query/README.md (5)

1-3: Approve: Centered logo markup is clear
The use of HTML <p> and <a> tags for the tRPC logo is valid and should render correctly in most Markdown environments.


5-9: Approve: Package header and tagline
The headings and tagline “End-to-end typesafe APIs made easy” effectively introduce the package.


11-14: Approve: Correct package name and description
The README correctly names the package as @trpc/tanstack-solid-query and describes it as a wrapper for @tanstack/solid-query, addressing earlier feedback.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

14-14: Blank line inside blockquote
null

(MD028, no-blanks-blockquote)


26-27: Approve: Version requirement is clear
Specifying @tanstack/solid-query v5.75.0 or higher gives users a clear minimum version to install.


28-43: Approve: Installation commands updated
The npm, Yarn, pnpm, Bun, and Deno commands correctly reference both @trpc/tanstack-solid-query and @tanstack/solid-query.

Comment on lines +21 to +23
Refer to the [`@trpc/tanstack-react-query`
documentation](https://trpc.io/docs/client/tanstack-react-query/setup).

Copy link
Contributor

@coderabbitai coderabbitai bot May 13, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Update documentation link to Solid Query
The link currently points to the React Query docs; it should reference the Solid Query setup instead to avoid confusion.
Apply this diff:

@@ lines 21-23
- Refer to the [`@trpc/tanstack-react-query`
- documentation](https://trpc.io/docs/client/tanstack-react-query/setup).
+ Refer to the [`@trpc/tanstack-solid-query` documentation](https://trpc.io/docs/client/tanstack-solid-query/setup).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Refer to the [`@trpc/tanstack-react-query`
documentation](https://trpc.io/docs/client/tanstack-react-query/setup).
Refer to the [`@trpc/tanstack-solid-query` documentation](https://trpc.io/docs/client/tanstack-solid-query/setup).
🤖 Prompt for AI Agents (early access)
In packages/tanstack-solid-query/README.md around lines 21 to 23, the
documentation link incorrectly points to the React Query setup. Update the URL
to reference the Solid Query setup documentation instead, ensuring the link
directs users to the correct Solid Query client setup page.

Copy link
Author

Choose a reason for hiding this comment

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

There's no specific documentation for this package, yet. I'm intentionally referring to the React implementation because the API is really similar.

Copy link
Contributor

Choose a reason for hiding this comment

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

@torres-engineer I understand now - that makes perfect sense! Keeping the reference to the React Query documentation is the right approach when the APIs are so similar. It provides users with valuable guidance until Solid-specific documentation is created. Thanks for the clarification.

🐰 rubs whiskers thoughtfully

Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
packages/tanstack-solid-query/src/internals/subscriptionOptions.ts (3)

6-6: Avoid importing from unstable internal tRPC APIs.

The import from @trpc/server/unstable-core-do-not-import suggests you're using unstable APIs that may change in future versions. Consider exploring more stable alternatives.


251-255: Effect has no side-effects – likely a leftover.

The createEffect merely reads getInitialState() without doing anything with the result. This produces no runtime effect and may trigger linting warnings.

-createEffect(
-  on(reset, () => {
-    getInitialState();
-  }),
-);

Consider removing this effect as it appears to have no purpose.


281-290: Duplicate reset logic can spawn multiple subscriptions.

reset() is executed both in the initial effect (line 232) and in this cleanup effect when opts.enabled is true. If opts.queryKey is stable but some other reactive source triggers both effects, you may end up unsubscribing and resubscribing twice in quick succession.

Consider centralizing the subscription lifecycle in a single effect:

-createEffect(() => {
-  hashKey(opts.queryKey);
-
-  reset();
-});

// ...

-createEffect(() => {
-  if (!opts.enabled) {
-    return;
-  }
-  reset();
-
-  return () => {
-    currentSubscription?.();
-  };
-});
+createEffect(() => {
+  // This effect runs when either the query key changes or enabled changes
+  const key = hashKey(opts.queryKey);
+  const enabled = opts.enabled;
+  
+  if (!enabled) {
+    currentSubscription?.();
+    updateState(getInitialState);
+    return;
+  }
+  
+  reset();
+  
+  return () => {
+    currentSubscription?.();
+  };
+});
🧹 Nitpick comments (4)
packages/tanstack-solid-query/src/internals/subscriptionOptions.ts (4)

16-29: Reduce duplication between subscription option interfaces.

BaseTRPCSubscriptionOptionsIn and UnusedSkipTokenTRPCSubscriptionOptionsIn share identical callback definitions. Consider refactoring to reduce duplication:

+interface SubscriptionCallbacks<TOutput, TError> {
+  onStarted?: () => void;
+  onData?: (data: inferAsyncIterableYield<TOutput>) => void;
+  onError?: (err: TError) => void;
+  onConnectionStateChange?: (state: TRPCConnectionState<TError>) => void;
+}

-interface BaseTRPCSubscriptionOptionsIn<TOutput, TError> {
-  enabled?: boolean;
-  onStarted?: () => void;
-  onData?: (data: inferAsyncIterableYield<TOutput>) => void;
-  onError?: (err: TError) => void;
-  onConnectionStateChange?: (state: TRPCConnectionState<TError>) => void;
+interface BaseTRPCSubscriptionOptionsIn<TOutput, TError> 
+  extends SubscriptionCallbacks<TOutput, TError> {
+  enabled?: boolean;
}

-interface UnusedSkipTokenTRPCSubscriptionOptionsIn<TOutput, TError> {
-  onStarted?: () => void;
-  onData?: (data: inferAsyncIterableYield<TOutput>) => void;
-  onError?: (err: TError) => void;
-  onConnectionStateChange?: (state: TRPCConnectionState<TError>) => void;
+interface UnusedSkipTokenTRPCSubscriptionOptionsIn<TOutput, TError>
+  extends SubscriptionCallbacks<TOutput, TError> {
}

This reduces duplication and makes it easier to maintain these interfaces.


166-227: Consider using the discriminated union pattern more consistently in reset function.

The updateState calls in various callbacks use type casting with ...(prev as any) which bypasses TypeScript's type checking. Consider using a more type-safe approach by leveraging the discriminated union pattern already defined in your state types.

const reset = (): void => {
  // unsubscribe from the previous subscription
  currentSubscription?.();

  updateState(getInitialState);
  if (!opts.enabled) {
    return;
  }
  const subscription = opts.subscribe({
    onStarted: () => {
      opts.onStarted?.();
      updateState((prev) => ({
-        ...(prev as any),
+        ...prev,
        status: 'pending',
        error: null,
+        data: prev.data,
+        reset
      }));
    },
    onData: (data) => {
      opts.onData?.(data);
      updateState((prev) => ({
-        ...(prev as any),
+        ...prev,
        status: 'pending',
        data,
        error: null,
+        reset
      }));
    },
    onError: (error) => {
      opts.onError?.(error);
      updateState((prev) => ({
-        ...(prev as any),
+        ...prev,
        status: 'error',
        error,
+        data: prev.data,
+        reset
      }));
    },
    // ...
  });
  // ...
};

This maintains type safety and makes the code more maintainable.


229-233: Consider using solid-js's dependency tracking more explicitly.

The current effect doesn't explicitly track the dependency on opts.queryKey. Consider using the on API to make this dependency explicit:

-createEffect(() => {
-  hashKey(opts.queryKey);
-
-  reset();
-});
+createEffect(on(() => hashKey(opts.queryKey), () => {
+  reset();
+}));

This makes it clearer that the effect runs when the query key changes.


295-307: Improve type safety in the trackResult function.

The function doesn't handle potential non-existent property access, which could lead to runtime errors if the proxy is accessed with a key that doesn't exist on the target object.

function trackResult<T extends object>(
  result: T,
  onTrackResult: (key: keyof T) => void,
): T {
  const trackedResult = new Proxy(result, {
    get(target, prop) {
-      onTrackResult(prop as keyof T);
-      return target[prop as keyof T];
+      // Ensure prop is a valid key of T
+      if (typeof prop === 'string' || typeof prop === 'symbol') {
+        if (prop in target) {
+          onTrackResult(prop as keyof T);
+        }
+      }
+      return Reflect.get(target, prop);
    },
  });

  return trackedResult;
}

This prevents potential issues with non-existent property access and makes the code more robust.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c08ced1 and 373552e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • packages/tanstack-solid-query/package.json (1 hunks)
  • packages/tanstack-solid-query/src/internals/infiniteQueryOptions.ts (1 hunks)
  • packages/tanstack-solid-query/src/internals/subscriptionOptions.ts (1 hunks)
  • packages/tanstack-solid-query/tsconfig.build.json (1 hunks)
  • packages/tanstack-solid-query/tsconfig.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/tanstack-solid-query/tsconfig.build.json
  • packages/tanstack-solid-query/tsconfig.json
  • packages/tanstack-solid-query/package.json
  • packages/tanstack-solid-query/src/internals/infiniteQueryOptions.ts

Something about the `WebSocketServer` constructor not existing.

Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

♻️ Duplicate comments (4)
packages/tanstack-solid-query/test/client.test.tsx (1)

70-70: 🛠️ Refactor suggestion

Consider replacing Symbol.asyncDispose with makeAsyncResource().

Similar to other test files, using Symbol.asyncDispose directly is discouraged according to the static analysis hint. Consider refactoring to use the recommended makeAsyncResource() pattern.

🧰 Tools
🪛 ESLint

[error] 70-70: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/mutationOptions.test.tsx (1)

101-101: 🛠️ Refactor suggestion

Replace Symbol.asyncDispose with makeAsyncResource().

As in other test files, using Symbol.asyncDispose directly is discouraged. Refactor to use the recommended makeAsyncResource() pattern for resource management.

Also applies to: 166-166

🧰 Tools
🪛 ESLint

[error] 101-101: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/infiniteQueryOptions.test.tsx (1)

38-42: Fix the off-by-one error in cursor calculation

When input.cursor + 1 equals fixtureData.length, the current logic returns a next cursor that's out of bounds, leading to an extra empty page request.

Apply this change to fix the issue:

            next:
              input.cursor + 1 > fixtureData.length
                ? undefined
                : input.cursor + 1,
+            next:
+              input.cursor + 1 >= fixtureData.length
+                ? undefined
+                : input.cursor + 1,
packages/tanstack-solid-query/test/useSubscription.test.tsx (1)

15-31: Avoid exporting helpers from a test file

Helper functions in test files shouldn't be exported as they could leak into the public API.

Either:

  1. Remove the export keyword since they're only used within this file, or
  2. Move them to a dedicated helper file like test/__helpers/subscription.ts
-export const suppressLogs = () => {
+const suppressLogs = () => {
  // ...
}

-export const suppressLogsUntil = async (fn: () => Promise<void>) => {
+const suppressLogsUntil = async (fn: () => Promise<void>) => {
  // ...
}

Also applies to: 35-43

🧹 Nitpick comments (3)
packages/tanstack-solid-query/test/__helpers.tsx (1)

52-53: Consider adding migration guidance for the deprecated close method.

You've marked the close method as deprecated with a JSDoc comment, but it might be helpful to provide more specific guidance on how to properly use the resource manager instead.

packages/tanstack-solid-query/test/queryKeyable.test.tsx (1)

8-8: Use import type for type-only imports

Since TRPCQueryKey is only used as a type, it should be imported with import type to improve type checking and avoid potential runtime overhead.

-import { TRPCQueryKey } from '../src';
+import type { TRPCQueryKey } from '../src';
🧰 Tools
🪛 ESLint

[error] 8-8: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)

packages/tanstack-solid-query/test/polymorphism.test.tsx (1)

16-16: Prefer import type for pure-type imports

JSX is only used as a type, so ESLint rightfully flags this line. Switching to import type keeps the value bundle clean and satisfies the consistent-type-imports rule.

-import { JSX } from 'solid-js/jsx-runtime';
+import type { JSX } from 'solid-js/jsx-runtime';
🧰 Tools
🪛 ESLint

[error] 16-16: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 373552e and 6c4d58c.

📒 Files selected for processing (14)
  • packages/tanstack-solid-query/src/internals/Context.tsx (1 hunks)
  • packages/tanstack-solid-query/test/__helpers.tsx (1 hunks)
  • packages/tanstack-solid-query/test/client.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/infiniteQueryOptions.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/mutationOptions.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/polymorphism.common.tsx (1 hunks)
  • packages/tanstack-solid-query/test/polymorphism.factory.tsx (1 hunks)
  • packages/tanstack-solid-query/test/polymorphism.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/queryKeyable.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/queryOptions.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/skipToken.test.tsx (1 hunks)
  • packages/tanstack-solid-query/test/useSubscription.test.tsx (1 hunks)
  • packages/tanstack-solid-query/tsconfig.build.json (1 hunks)
  • packages/tanstack-solid-query/vitest.config.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/tanstack-solid-query/test/polymorphism.common.tsx
  • packages/tanstack-solid-query/tsconfig.build.json
  • packages/tanstack-solid-query/src/internals/Context.tsx
  • packages/tanstack-solid-query/vitest.config.ts
  • packages/tanstack-solid-query/test/polymorphism.factory.tsx
🧰 Additional context used
🧬 Code Graph Analysis (3)
packages/tanstack-solid-query/test/queryKeyable.test.tsx (4)
packages/tanstack-solid-query/test/polymorphism.common.tsx (1)
  • t (3-3)
packages/tanstack-solid-query/test/__helpers.tsx (1)
  • testSolidResource (12-55)
packages/tanstack-solid-query/src/internals/types.ts (1)
  • TRPCQueryKey (86-89)
packages/client/src/TRPCClientError.ts (1)
  • TRPCClientErrorLike (19-20)
packages/tanstack-solid-query/test/polymorphism.test.tsx (4)
packages/tanstack-solid-query/test/polymorphism.factory.tsx (2)
  • FileExportStatusType (30-30)
  • ExportRouteLike (104-104)
packages/tanstack-solid-query/test/polymorphism.common.tsx (1)
  • t (3-3)
packages/tanstack-solid-query/test/__helpers.tsx (1)
  • testSolidResource (12-55)
packages/tanstack-solid-query/src/internals/createOptionsProxy.ts (1)
  • inferOutput (86-91)
packages/tanstack-solid-query/test/queryOptions.test.tsx (5)
packages/server/src/unstable-core-do-not-import/stream/utils/createDeferred.ts (1)
  • createDeferred (2-11)
packages/tanstack-solid-query/test/polymorphism.common.tsx (1)
  • t (3-3)
packages/tanstack-solid-query/test/__helpers.tsx (1)
  • testSolidResource (12-55)
packages/client/src/TRPCClientError.ts (1)
  • TRPCClientErrorLike (19-20)
packages/server/src/unstable-core-do-not-import/initTRPC.ts (1)
  • context (47-52)
🪛 ESLint
packages/tanstack-solid-query/test/mutationOptions.test.tsx

[error] 101-101: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 166-166: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/queryKeyable.test.tsx

[error] 8-8: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)


[error] 129-129: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 165-165: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 234-234: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 264-264: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 302-302: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 340-340: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 375-375: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/__helpers.tsx

[error] 9-9: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)

packages/tanstack-solid-query/test/client.test.tsx

[error] 70-70: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/infiniteQueryOptions.test.tsx

[error] 198-198: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 221-221: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 324-324: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 404-404: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/polymorphism.test.tsx

[error] 16-16: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)


[error] 152-152: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 218-218: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/queryOptions.test.tsx

[error] 85-85: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 112-112: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 139-139: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 177-177: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 194-194: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/skipToken.test.tsx

[error] 64-64: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/useSubscription.test.tsx

[error] 41-41: Usage of Symbol.dispose is not allowed - use makeResource()

(no-restricted-syntax)


[error] 214-214: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 279-279: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 396-396: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 482-482: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

🪛 Biome (1.9.4)
packages/tanstack-solid-query/test/useSubscription.test.tsx

[error] 14-30: Do not export from a test file.

(lint/suspicious/noExportsInTest)


[error] 34-43: Do not export from a test file.

(lint/suspicious/noExportsInTest)

🔇 Additional comments (12)
packages/tanstack-solid-query/test/skipToken.test.tsx (2)

42-67: Well-structured test for skipToken functionality.

The test effectively verifies that skipToken is properly honored in both regular query options and infinite query options. The assertion that options.queryFn === skipToken ensures the core functionality works as expected.

🧰 Tools
🪛 ESLint

[error] 64-64: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


64-64:

✅ Verification successful

Consider replacing Symbol.asyncDispose with makeAsyncResource().

According to the static analysis hint, using Symbol.asyncDispose directly is discouraged. Consider refactoring to use the recommended makeAsyncResource() pattern instead.


🏁 Script executed:

#!/bin/bash
# Searching for any examples of makeAsyncResource pattern in the codebase
rg "makeAsyncResource" --type ts --type tsx

Length of output: 71


I’ll broaden the search to include all file types:


🏁 Script executed:

#!/bin/bash
# Search for any occurrences of makeAsyncResource in the entire repo
rg "makeAsyncResource"

Length of output: 1993


I can’t find any makeAsyncResource helper in the Solid-Query package, so suggesting it here is misleading. You can safely ignore this rule in tests where you’re directly invoking Symbol.asyncDispose.

Ignore Symbol.asyncDispose eslint warning in this test

To suppress the lint error without changing implementation:

 packages/tanstack-solid-query/test/skipToken.test.tsx
@@ lines 64
-      await ctx[Symbol.asyncDispose]();
+      // eslint-disable-next-line @your-org/no-async-dispose-symbol
+      await ctx[Symbol.asyncDispose]();

[suggest_suppression]

🧰 Tools
🪛 ESLint

[error] 64-64: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/__helpers.tsx (1)

12-55: Well-designed test helper with comprehensive utilities.

This helper function provides a robust foundation for testing Solid components with tRPC integration. It properly sets up the query client, creates necessary providers, and exposes all required hooks and utilities.

packages/tanstack-solid-query/test/client.test.tsx (1)

36-73: Well-structured test for useTRPCClient hook.

The test effectively verifies both the runtime behavior and type safety of the useTRPCClient hook. The use of expectTypeOf ensures proper type inference, while the UI testing confirms the component renders correctly after fetching data.

🧰 Tools
🪛 ESLint

[error] 70-70: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/mutationOptions.test.tsx (2)

46-103: Comprehensive test for mutation lifecycle hooks.

This test thoroughly validates the mutation options API, including proper type inference for inputs and outputs, and verification of callback execution order. The type assertions provide strong guarantees about the API's type safety.

🧰 Tools
🪛 ESLint

[error] 101-101: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


105-168: Well-implemented optimistic updates test.

The optimistic update test demonstrates a realistic use case, properly handling:

  1. Query cancelation before updates
  2. State backup for error recovery
  3. Cache invalidation after successful mutation
  4. Verification of the UI displaying optimistic data

This provides excellent coverage for a common mutation pattern.

🧰 Tools
🪛 ESLint

[error] 166-166: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/infiniteQueryOptions.test.tsx (1)

1-407: The test structure and coverage look comprehensive

This test file thoroughly validates the infiniteQueryOptions functionality, including:

  • Type safety for query keys, data, and error types
  • Core functionality for paginated queries with cursors
  • Proper handling of select transformations
  • Edge case handling for falsy cursors

The test cases provide good coverage for this feature.

🧰 Tools
🪛 ESLint

[error] 198-198: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 221-221: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 324-324: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 404-404: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/queryKeyable.test.tsx (1)

1-378: Test coverage is thorough and well-structured

The queryKeyable tests provide excellent coverage of the typed query key functionality:

  • Comprehensive tests for generating query filters at different router path levels
  • Proper type inference validation for query keys and filters
  • Validation of mutation keys and appropriate type constraints
  • Thorough type checking for error shapes

The test structure makes effective use of inline snapshots to verify the exact shape of the generated keys.

🧰 Tools
🪛 ESLint

[error] 8-8: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)


[error] 129-129: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 165-165: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 234-234: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 264-264: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 302-302: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 340-340: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 375-375: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/useSubscription.test.tsx (1)

127-485: Comprehensive subscription testing

The test cases thoroughly cover subscription functionality across different protocols (HTTP and WebSocket), including:

  • Subscription data flow via different implementation strategies (iterables and observables)
  • Connection state transitions and error handling
  • Subscription toggling and reset functionality
  • Proper cleanup on disabling or unmounting subscriptions

The tests provide robust coverage of both the happy path and error scenarios.

🧰 Tools
🪛 ESLint

[error] 214-214: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 279-279: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 396-396: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


[error] 482-482: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

packages/tanstack-solid-query/test/queryOptions.test.tsx (3)

38-43: Well-implemented async iterable for testing

The async iterable testing approach with deferred promises provides a controlled way to test async streaming responses in a deterministic manner. This is good practice for testing async iterables.


116-141: Good test for the skipToken feature

Testing the skipToken functionality is important as it's a key feature for conditionally enabling/disabling queries. This test properly validates both the runtime behavior and type inference when using skipToken.

🧰 Tools
🪛 ESLint

[error] 139-139: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)


181-196: Good verification of direct router calls

This test effectively verifies an important optimization - that direct server-side router calls don't make unnecessary network requests. This helps ensure efficient operations when using the proxy on the server.

🧰 Tools
🪛 ESLint

[error] 194-194: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

try {
await fn();
} finally {
_[Symbol.dispose]();
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use makeResource() instead of Symbol.dispose

According to the project's linting rules, direct usage of Symbol.dispose is not allowed.

  try {
    await fn();
  } finally {
-    _[Symbol.dispose]();
+    _[Symbol.asyncDispose]();
  }

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 ESLint

[error] 41-41: Usage of Symbol.dispose is not allowed - use makeResource()

(no-restricted-syntax)

🤖 Prompt for AI Agents
In packages/tanstack-solid-query/test/useSubscription.test.tsx at line 41,
replace the direct call to _[Symbol.dispose]() with the appropriate usage of
makeResource() as per the project's linting rules. Refactor the code to dispose
of resources using makeResource() instead of directly invoking Symbol.dispose to
comply with the linting standards.

Comment on lines +103 to +106
const invalidate = useMutation(() => ({
mutationFn: () =>
client.invalidateQueries(trpc.github.pathFilter()),
}));
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

useMutation is called with the wrong argument shape

useMutation(fn) treats the first argument as the mutation function, whereas you’re returning an options object that contains mutationFn. This causes the actual mutation never to run and the returned mutation object to behave unexpectedly.

-const invalidate = useMutation(() => ({
-  mutationFn: () =>
-    client.invalidateQueries(trpc.github.pathFilter()),
-}));
+const invalidate = useMutation({
+  mutationFn: () => client.invalidateQueries(trpc.github.pathFilter()),
+});

Apply the same change to the duplicate block below (lines 169-172) to avoid flaky tests and runtime errors.

Also applies to: 169-172

🤖 Prompt for AI Agents
In packages/tanstack-solid-query/test/polymorphism.test.tsx at lines 103-106 and
169-172, the useMutation hook is incorrectly called with an object containing
mutationFn instead of directly passing the mutation function. Fix this by
passing the mutation function itself as the first argument to useMutation,
removing the wrapping object. This ensures the mutation runs correctly and
prevents flaky tests and runtime errors.

Comment on lines +152 to +153
await ctx[Symbol.asyncDispose]();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid Stage-3 Symbol.asyncDispose in tests

Symbol.asyncDispose is experimental and fails ESLint’s no-restricted-syntax rule. testSolidResource already returns a close() helper (albeit marked deprecated) that performs the same cleanup.

-      } finally {
-        await ctx[Symbol.asyncDispose]();
+      } finally {
+        await ctx.close?.();
       }

Using a stable API sidesteps the lint error and keeps the tests compatible with current runtimes.

Also applies to: 218-219

🧰 Tools
🪛 ESLint

[error] 152-152: Usage of Symbol.asyncDispose is not allowed - use makeAsyncResource()

(no-restricted-syntax)

🤖 Prompt for AI Agents
In packages/tanstack-solid-query/test/polymorphism.test.tsx at lines 152-153 and
also lines 218-219, replace the usage of the experimental Symbol.asyncDispose
for cleanup with the stable close() helper returned by testSolidResource. This
avoids ESLint no-restricted-syntax errors and ensures compatibility with current
runtimes by calling ctx.close() instead of await ctx[Symbol.asyncDispose]().

Comment on lines +138 to +150
await vi.waitFor(() => {
expect($.container).toHaveTextContent(
'Last Export: `Search for Polymorphism Solid` (Working)',
);
});

await userEvent.click($.getByTestId('refreshBtn'));

await vi.waitFor(() => {
expect($.container).toHaveTextContent(
'Last Export: `Search for Polymorphism Solid` (Ready!)',
);
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

vi.waitFor does not exist – import waitFor from Testing-Library

vi only exposes mocking utilities; it has no waitFor method, so these lines will throw at runtime. Import waitFor from @solidjs/testing-library (re-exported from Testing-Library) and use it directly:

-import { describe, expect, test, vi } from 'vitest';
+import { describe, expect, test, vi } from 'vitest';
+import { waitFor } from '@solidjs/testing-library';
-await vi.waitFor(() => {
+await waitFor(() => {

Apply to both occurrences (lines 138-142 and 204-208).

Also applies to: 204-208

🤖 Prompt for AI Agents
In packages/tanstack-solid-query/test/polymorphism.test.tsx around lines 138 to
150, the code incorrectly uses vi.waitFor which does not exist and will cause
runtime errors. To fix this, import waitFor directly from
@solidjs/testing-library at the top of the file and replace all instances of
vi.waitFor with waitFor. Apply the same fix to the similar usage around lines
204 to 208 as well.

Comment on lines +236 to +244
const exportStarter = useMutation(() =>
props.route.start.mutationOptions({
async onSuccess(data) {
props.onExportStarted(data.id);

return await client.invalidateQueries(props.route.pathFilter());
},
}),
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

exportStarter wrapper prevents the mutation from executing

Wrapping props.route.start.mutationOptions() in an arrow function makes React Query think that function itself is the mutation, returning an object instead of a promise. Pass the options object directly instead:

-const exportStarter = useMutation(() =>
-  props.route.start.mutationOptions({
-    async onSuccess(data) {
-      props.onExportStarted(data.id);
-
-      return await client.invalidateQueries(props.route.pathFilter());
-    },
-  }),
-);
+const exportStarter = useMutation(
+  props.route.start.mutationOptions({
+    async onSuccess(data) {
+      props.onExportStarted(data.id);
+      await client.invalidateQueries(props.route.pathFilter());
+    },
+  }),
+);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const exportStarter = useMutation(() =>
props.route.start.mutationOptions({
async onSuccess(data) {
props.onExportStarted(data.id);
return await client.invalidateQueries(props.route.pathFilter());
},
}),
);
const exportStarter = useMutation(
props.route.start.mutationOptions({
async onSuccess(data) {
props.onExportStarted(data.id);
await client.invalidateQueries(props.route.pathFilter());
},
}),
);
🤖 Prompt for AI Agents
In packages/tanstack-solid-query/test/polymorphism.test.tsx around lines 236 to
244, the mutation is incorrectly wrapped in an arrow function causing React
Query to treat the function as the mutation instead of the mutation options
object. Fix this by passing the mutation options object returned from
props.route.start.mutationOptions() directly to useMutation without wrapping it
in another function.

Signed-off-by: João Augusto Costa Branco Marado Torres <torres.dev@disroot.org>
@pkg-pr-new
Copy link

pkg-pr-new bot commented May 16, 2025

Open in StackBlitz

@trpc/client

npm i https://pkg.pr.new/trpc/trpc/@trpc/client@6742

@trpc/next

npm i https://pkg.pr.new/trpc/trpc/@trpc/next@6742

@trpc/server

npm i https://pkg.pr.new/trpc/trpc/@trpc/server@6742

@trpc/react-query

npm i https://pkg.pr.new/trpc/trpc/@trpc/react-query@6742

@trpc/tanstack-react-query

npm i https://pkg.pr.new/trpc/trpc/@trpc/tanstack-react-query@6742

@trpc/tanstack-solid-query

npm i https://pkg.pr.new/trpc/trpc/@trpc/tanstack-solid-query@6742

@trpc/upgrade

npm i https://pkg.pr.new/trpc/trpc/@trpc/upgrade@6742

commit: f3f3b8f

@marvin-j97
Copy link

Are there any blockers in Tanstack Solid Query still for this to be working?

@torres-engineer
Copy link
Author

Are there any blockers in Tanstack Solid Query still for this to be working?

Hey! I just couldn't make all the tests pass, I don't remember exactly why but I think it has to do with the usage of Solid.js, not React, the tests were failing because "React doesn't exist". I couldn't figure it out, then I forgot about it.

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