feat(tanstack-query): define base options and interceptors via contract meta#1705
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
More templates
@orpc/ai-sdk
@orpc/arktype
@orpc/bun
@orpc/client
@orpc/cloudflare
@orpc/contract
@orpc/experimental-effect
@orpc/evlog
@orpc/json-schema
@orpc/nest
@orpc/next
@orpc/openapi
@orpc/opentelemetry
@orpc/pinia-colada
@orpc/pino
@orpc/publisher
@orpc/ratelimit
@orpc/server
@orpc/shared
@orpc/tanstack-query
@orpc/trpc
@orpc/valibot
@orpc/zod
commit: |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
ℹ️ No critical issues — one minor API-surface note inline.
Reviewed changes — added tanstackQueryMeta, getTanstackQueryMeta, and ContractMetaPlugin so base TanStack Query options and interceptors can be defined on a procedure contract and applied automatically as the default layer under utils options.
packages/tanstack-query/src/meta.ts— introduces thetanstackQueryMetacontract meta plugin,getTanstackQueryMetareader, andContractMetaPluginrouter utils plugin.packages/tanstack-query/src/procedure-utils.ts— addsmergeProcedureUtilsOptions/mergeProcedureUtilsModifierso option modifiers spread-merge and interceptors concatenate across layers.packages/tanstack-query/src/router-utils.ts— switches global/scoped per-procedure option merging tomergeProcedureUtilsOptionsto keep semantics consistent.packages/tanstack-query/src/index.ts— exports the new./metamodule and now also exports./plugin.- Tests and docs — adds
meta.test.ts/meta.test-d.ts, updates therouter-utils.test.tsmock, and documents the contract meta plugin.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
|
Heads-up: the inline suggestion in my review on The actual feedback is just a nit:
|
…ptionsUtilsPlugin
…ery-meta-plugin-edfe5e # Conflicts: # packages/tanstack-query/src/procedure-utils.ts # packages/tanstack-query/src/router-utils.test.ts # packages/tanstack-query/src/router-utils.ts
There was a problem hiding this comment.
Reviewed changes — the new commit changes mixed object/function modifier merging from "replace" to "compose," so a plain-object modifier now spreads into a function modifier's input rather than being discarded.
- Compose mixed object and function modifiers —
mergeProcedureUtilsModifiernow wraps the plain-object side in a function so it participates in composition instead of being replaced, and a new test validates both orderings.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
…tils and cover all keys
There was a problem hiding this comment.
ℹ️ No new issues — the refactor is clean. The one open thread from the prior review remains a pre-existing concern unrelated to this delta.
Reviewed changes — refactored isProcedureUtilsOptions from a private function in router-utils.ts into an exported utility in procedure-utils.ts with more comprehensive key validation, and reworked mock setup in router-utils tests to use importOriginal.
- Move
isProcedureUtilsOptionstoprocedure-utils.ts— the type guard now validates all known keys (prefix, interceptor arrays, modifier keys) via key-lookup arrays instead of only checking interceptor types. - Export
isProcedureUtilsOptions— the function becomes part of the public API viaexport * from './procedure-utils'. - Update
router-utils.test.tsmock — usesimportOriginalso real exports fromprocedure-utilspass through whileProcedureUtilsremains mocked.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
Reviewed changes — isProcedureUtilsOptions now accepts unknown keys instead of rejecting them, and the router-utils test for invalid scoped options was simplified and aligned with the new detection logic.
isProcedureUtilsOptionsallows unknown keys — the loop skips unrecognized keys rather than returningfalse, so extra properties mixed into scoped options don't prevent procedure-utils detection.- Simplified
router-utils.test.ts— replaced the parameterized interceptor-only test with a single test that validates the correct behavior withqueryInterceptors: { invalid: true }and verifies nestedchild.queryOptionsresolution.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
ℹ️ No new issues from this delta — the one open thread from a prior review (
9b1fdac) remains unaddressed.
Reviewed changes — tightened isProcedureUtilsOptions validation so interceptor array elements are checked for function type, and simplified the modifier-key check by removing a now-redundant typeof guard.
- Strengthen interceptor validation —
isProcedureUtilsOptionsnow rejects interceptor arrays containing non-function elements (e.g.[{ invalid: true }]), catching bad inputs that would cause runtime errors downstream. - Simplify modifier-key check — dropped the
typeof value[key] !== 'function'guard sinceisTypescriptObject(from@standardserver/shared) already covers functions per its contract: "Checks whether the provided container is a typescript object (object or function)."
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
Pull request overview
Adds a contract-level configuration mechanism for the TanStack Query integration by storing “base” procedure utils options/interceptors in contract meta and applying them automatically when building router utils. This fits the @orpc/tanstack-query package by enabling reusable, contract-authored defaults that are merged consistently with existing utils-level configuration.
Changes:
- Introduces
tanstackQuery()+getTanstackQueryMeta()and aContractOptionsUtilsPluginto store/apply base options via contract meta. - Centralizes procedure utils option merging/validation with
mergeProcedureUtilsOptions()and movesisProcedureUtilsOptions()intoprocedure-utils.ts. - Updates tests and documentation to cover contract meta options and plugin usage.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/tanstack-query/src/router-utils.ts | Uses centralized merge/validation when initializing per-procedure utils options. |
| packages/tanstack-query/src/router-utils.test.ts | Adjusts mocking and scoped-options tests to align with new validation/merge behavior. |
| packages/tanstack-query/src/procedure-utils.ts | Adds isProcedureUtilsOptions + option/modifier merge utilities. |
| packages/tanstack-query/src/procedure-utils.test.ts | Adds runtime-shape tests for isProcedureUtilsOptions. |
| packages/tanstack-query/src/meta.ts | New contract meta API (tanstackQuery, getTanstackQueryMeta) and ContractOptionsUtilsPlugin. |
| packages/tanstack-query/src/meta.test.ts | Tests meta storage/merging and plugin application through createRouterUtils. |
| packages/tanstack-query/src/meta.test-d.ts | Adds type-level assertions for tanstackQuery inference and invalid options. |
| packages/tanstack-query/src/index.ts | Exposes meta and plugin exports publicly. |
| apps/content/docs/integrations/tanstack-query.md | Documents the new Contract Options Plugin and contract-meta caveats/examples. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — refactored mergeProcedureUtilsOptions from per-key manual code to loop-based merging, added undefined reset semantics so explicit undefined on any interceptor or modifier key clears the base value, and switched router-utils.ts to use mergeProcedureUtilsOptions for the global+scoped options merge instead of manual toArray concatenation.
- Refactor
mergeProcedureUtilsOptions— replaced 12 lines of per-key merge calls with two loops overPROCEDURE_UTILS_INTERCEPTOR_KEYSandPROCEDURE_UTILS_MODIFIER_KEYS. Keys set toundefinedin the override now reset the base value (consistent across both interceptors and modifiers). - Tighten
mergeProcedureUtilsModifiersignature — params changed from optional to required, reflecting that callers always supply both. - Unify router-level merge —
createRouterUtilsInternalnow callsmergeProcedureUtilsOptions(globalBase, scoped)instead of manually wrapping each interceptor list with[...toArray(options.X), ...toArray(options.scoped?.X)]. - Docs update — the contract options description notes that passing
undefinedexplicitly resets the value from lower layers. - New test — validates that
meta(tanstackQuery({ queryOptions: undefined }))removes previously-set values.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — relocated mergeProcedureUtilsOptions unit tests from meta.test.ts to procedure-utils.test.ts, removed now-unnecessary toArray wrapping of interceptor values in router-utils.ts, and updated test assertions to reflect that mergeProcedureUtilsOptions handles the global+scoped interceptor merge internally.
- Move
mergeProcedureUtilsOptionstests toprocedure-utils.test.ts— the six merge tests (override by key presence,undefinedreset, interceptor concat, plain-object spread, function composition, mixed composition) now live alongside their implementation instead of inmeta.test.ts. - Drop
toArraywrapping inrouter-utils.ts— interceptor values passed tomergeProcedureUtilsOptionsno longer go throughtoArraysince the merge function correctly handlesundefinedvia itsif (baseValue && overrideValue)guard and the initial spread. - Simplify
router-utils.test.tsassertions — removed theemptyInterceptorsfixture and updated expectedProcedureUtilsconstructor args since empty interceptor arrays are no longer materialized by manual concatenation.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
… meta (#1718) ## Summary Port of #1705 to `@orpc/pinia-colada`. Define base Pinia Colada options and interceptors directly on a procedure contract via `piniaColada`, and apply them automatically with the new `ContractOptionsUtilsPlugin`. ```ts export const contract = { planet: { find: oc .input(z.object({ id: z.number() })) .meta(piniaColada({ queryOptions: { staleTime: 60 * 1000, }, })), }, } const orpc = createPiniaColadaUtils(client, { plugins: [new ContractOptionsUtilsPlugin(contract)], }) ``` - `piniaColada` infers input, output, and error types from the contract, supports all procedure utils options (keys, options, interceptors), and merges when applied multiple times - `ContractOptionsUtilsPlugin` applies meta options as the base layer: utils level options override them and utils interceptors run after meta interceptors - Merging is consistent across all layers: interceptors concatenate, plain option objects spread-merge, any pair involving a function modifier composes, and a key explicitly set to `undefined` resets the value from lower layers - `getPiniaColadaMeta` reads the stored options for custom integrations - `UseMutationFnContext` now matches the runtime merged mutation context, so values provided by a global `onMutate` are typed inside mutation interceptors via `UseMutationContextCommon` augmentation - Docs cover the plugin, the reference-only nature of contract types, and passing runtime values such as router utils through a global `onMutate` hook for optimistic updates

Summary
Define base TanStack Query options and interceptors directly on a procedure contract via
tanstackQuery, and apply them automatically with the newContractOptionsUtilsPlugin.tanstackQueryinfers input, output, and error types from the contract, supports all procedure utils options (keys, options, interceptors), and merges when applied multiple timesContractOptionsUtilsPluginapplies meta options as the base layer: utils level options override them and utils interceptors run after meta interceptorsgetTanstackQueryMetareads the stored options for custom integrations