Skip to content

ref: expose function to safeParse an queryKey into our ApiQueryKey schema#114026

Merged
TkDodo merged 5 commits intomasterfrom
tkdodo/ref/safe-parse-query-key
Apr 28, 2026
Merged

ref: expose function to safeParse an queryKey into our ApiQueryKey schema#114026
TkDodo merged 5 commits intomasterfrom
tkdodo/ref/safe-parse-query-key

Conversation

@TkDodo
Copy link
Copy Markdown
Collaborator

@TkDodo TkDodo commented Apr 27, 2026

when used for a predicate inside a QueryFilter, what we get as input is unknown[]. However, our parseQueryKey could only pass api query keys of v1 or v2 schema. When queries are created manually without useApiQuery (v1) or apiOptions (v2) they might not conform to that structure.

Therefore it’s unsafe to use parseQueryKey for predicate filter functions, and it would also type error.

This PR introduces a safeParseQueryKey function that uses a zod schema to safely parse any QueryKey and transforms the various versions into a single, readable structure. It will return undefined if the structure doesn’t match.

All places where we did manual predicate matching have been updated.

@TkDodo TkDodo changed the title ref: expose function to safeParse an queryKey into our url schema ref: expose function to safeParse an queryKey into our ApiQueryKey schema Apr 27, 2026
@github-actions github-actions Bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Apr 27, 2026
queryClient.invalidateQueries({
predicate: query => {
const key = query.queryKey[0];
const key = safeParseQueryKey(query.queryKey)?.url;
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

note: this query.queryKey[0] does not work with v2 QueryKeys 🚨

Comment on lines -19 to +22
function isIssueEndpointUrl(query: any) {
// v2 keys have metadata at [0] and URL at [1]
const key = query.queryKey;
const url =
typeof key[0] === 'object' && key[0]?.version === 'v2'
? (key[1] ?? '')
: (key[0] ?? '');
return issueApiEndpointRegexp.test(String(url));
function isIssueEndpointUrl(query: {queryKey: readonly unknown[]}) {
const url = safeParseQueryKey(query.queryKey)?.url;
return url !== undefined && issueApiEndpointRegexp.test(url);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

this parsing here did work with v1 and v2, but was still manual and might return false-positives for non api queries

): queryKey is V1InfiniteQueryKey | V2InfiniteQueryKey {
return typeof queryKey[0] === 'object' && queryKey[0].infinite;
): ParsedQueryKey {
return queryKeySchema.parse(queryKey);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

since the input is ApiQueryKey | InfiniteApiQueryKey, it should be safe here to do .parse (which can throw)

Comment on lines -279 to +287
const [url, options] = query.queryKey as [
string,
{query?: {referrer?: string}} | undefined,
];
return url === eventsUrl && options?.query?.referrer === 'replay_details';
const queryKey = safeParseQueryKey(query.queryKey);
if (!queryKey) {
return false;
}
return (
queryKey.url === eventsUrl &&
queryKey.options?.query?.referrer === 'replay_details'
);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

totally unsafe assertion here before

@TkDodo TkDodo marked this pull request as ready for review April 27, 2026 11:59
@TkDodo TkDodo requested review from a team as code owners April 27, 2026 11:59
@TkDodo TkDodo requested a review from a team April 27, 2026 12:14
@TkDodo TkDodo merged commit c9a4a48 into master Apr 28, 2026
65 checks passed
@TkDodo TkDodo deleted the tkdodo/ref/safe-parse-query-key branch April 28, 2026 07:06
cleptric pushed a commit that referenced this pull request May 5, 2026
…hema (#114026)

when used for a `predicate` inside a `QueryFilter`, what we get as input
is `unknown[]`. However, our `parseQueryKey` could only pass api query
keys of v1 or v2 schema. When queries are created manually without
`useApiQuery` (v1) or `apiOptions` (v2) they might not conform to that
structure.

Therefore it’s unsafe to use `parseQueryKey` for `predicate` filter
functions, and it would also type error.

This PR introduces a `safeParseQueryKey` function that uses a zod schema
to safely parse any QueryKey and transforms the various versions into a
single, readable structure. It will return `undefined` if the structure
doesn’t match.

All places where we did manual `predicate` matching have been updated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants