From 0b319915bc64dc112282da70421656a620b68155 Mon Sep 17 00:00:00 2001 From: Evan Sutherland Date: Thu, 16 Oct 2025 22:31:37 -0500 Subject: [PATCH 1/8] export everything on default client --- src/main.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main.ts b/src/main.ts index 2997f67..ef5464b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,12 +7,28 @@ import { MutationAction, MutationData, MutationTagsContext, MutationTagsBeforeCo import { QueryAction, QueryData, QueryActionArgs, QueryTags, QueryOptions, Query, AwaitedQuery } from './types/query' import { QueryTag, QueryTagType, QueryTagCallback, QueryTagFactory } from './types/tags' -const { query, useQuery } = createQueryClient() +const { + query, + useQuery, + defineQuery, + setQueryData, + refreshQueryData, + mutate, + useMutation, + defineMutation, +} = createQueryClient() export { createQueryClient, tag, - query, useQuery + query, + useQuery, + defineQuery, + setQueryData, + refreshQueryData, + mutate, + useMutation, + defineMutation } export type { From 8f5eb6fac1100993e411ff199f75d9a4b399fda6 Mon Sep 17 00:00:00 2001 From: Evan Sutherland Date: Thu, 16 Oct 2025 22:31:50 -0500 Subject: [PATCH 2/8] update queries to reflect recent changes to params syntax --- docs/core-concepts/queries.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/core-concepts/queries.md b/docs/core-concepts/queries.md index 41b8e0c..4877072 100644 --- a/docs/core-concepts/queries.md +++ b/docs/core-concepts/queries.md @@ -9,7 +9,7 @@ function searchCats(breed?: string) { ... } -const catsQuery = query(searchCats, ['Maine Coon']) +const catsQuery = query(searchCats, () => ['Maine Coon']) ``` ## Query Properties @@ -29,7 +29,7 @@ const catsQuery = query(searchCats, ['Maine Coon']) The query includes `execute`, which can be called at any point to force the function to be called again. ```ts -const catsQuery = query(searchCats, ['Ragdoll']) +const catsQuery = query(searchCats, () => ['Ragdoll']) function refresh(): void { catsQuery.execute() @@ -45,9 +45,9 @@ Note that if awaiting a query, any errors that occur will be thrown. Consider pl ::: ```ts -const regularQuery = query(searchCats, ['Persian']) +const regularQuery = query(searchCats, () => ['Persian']) // ^? data: Cat[] | undefined -const awaitedQuery = await query(searchCats, ['Persian']) +const awaitedQuery = await query(searchCats, () => ['Persian']) // ^? data: Cat[] ``` @@ -68,7 +68,7 @@ By default a query that hasn't been executed (or hasn't finished executing) will ```ts const placeholder: Cat[] = [] -const catsQuery = await query(searchCats, ['Bengal'], { placeholder }) +const catsQuery = await query(searchCats, () => ['Bengal'], { placeholder }) // ^? data: Cat[] ``` @@ -77,7 +77,7 @@ const catsQuery = await query(searchCats, ['Bengal'], { placeholder }) Automatically re-trigger the function on an interval. Value provided is time in milliseconds. ```ts -const catsQuery = await query(searchCats, ['Persian'], { interval: 30_000 }) +const catsQuery = await query(searchCats, () => ['Persian'], { interval: 30_000 }) // automatically calls `searchCats` when query is created, and then again every 30 seconds ``` @@ -86,7 +86,7 @@ const catsQuery = await query(searchCats, ['Persian'], { interval: 30_000 }) Automatically re-try the function when an error occurs. By default the query will wait `500` milliseconds between retries. ```ts -const catsQuery = query(searchCats, ['Siamese'], { retries: 3 }) +const catsQuery = query(searchCats, () => ['Siamese'], { retries: 3 }) // will try to call `searchCats` a total of 3 times, waiting 500 MS between each attempt ``` @@ -94,7 +94,7 @@ Alternatively you can pass in `RetryOptions`, which allows you to specify both a ```ts const retries = { count: 1, delay: 1_000 } -const catsQuery = query(searchCats, ['Siamese'], { retries: 3 }) +const catsQuery = query(searchCats, () => ['Siamese'], { retries: 3 }) // will retry after 1,000 MS once if initial call fails ``` From 798051eef8ffeb10441c9fb3ea93de38c1436a4e Mon Sep 17 00:00:00 2001 From: Evan Sutherland Date: Thu, 16 Oct 2025 22:32:04 -0500 Subject: [PATCH 3/8] updated page for tags & invalidation --- docs/compare-to-tanstack.md | 2 +- docs/core-concepts/tags-invalidation.md | 428 +++++------------------- 2 files changed, 90 insertions(+), 340 deletions(-) diff --git a/docs/compare-to-tanstack.md b/docs/compare-to-tanstack.md index 11941a9..2740554 100644 --- a/docs/compare-to-tanstack.md +++ b/docs/compare-to-tanstack.md @@ -1,3 +1,3 @@ # Migrating from Tanstack -- no keys, caches function + arguments by default +- no keys (tags don't require user to adopt naming scheme), caches function + arguments by default diff --git a/docs/core-concepts/tags-invalidation.md b/docs/core-concepts/tags-invalidation.md index 2522b9b..edfc9f3 100644 --- a/docs/core-concepts/tags-invalidation.md +++ b/docs/core-concepts/tags-invalidation.md @@ -1,402 +1,152 @@ # Tags & Invalidation - \ No newline at end of file +::: From 65a4cba4971b83209b9238c4e8a3cefea1c1ec7c Mon Sep 17 00:00:00 2001 From: Evan Sutherland Date: Mon, 20 Oct 2025 20:01:34 -0500 Subject: [PATCH 4/8] code review suggestions --- docs/core-concepts/queries.md | 18 +++---- docs/core-concepts/tags-invalidation.md | 63 +++++-------------------- 2 files changed, 22 insertions(+), 59 deletions(-) diff --git a/docs/core-concepts/queries.md b/docs/core-concepts/queries.md index 4877072..cd3d20e 100644 --- a/docs/core-concepts/queries.md +++ b/docs/core-concepts/queries.md @@ -9,7 +9,7 @@ function searchCats(breed?: string) { ... } -const catsQuery = query(searchCats, () => ['Maine Coon']) +const catsQuery = query(searchCats, ['Maine Coon']) ``` ## Query Properties @@ -29,7 +29,7 @@ const catsQuery = query(searchCats, () => ['Maine Coon']) The query includes `execute`, which can be called at any point to force the function to be called again. ```ts -const catsQuery = query(searchCats, () => ['Ragdoll']) +const catsQuery = query(searchCats, ['Ragdoll']) function refresh(): void { catsQuery.execute() @@ -45,9 +45,9 @@ Note that if awaiting a query, any errors that occur will be thrown. Consider pl ::: ```ts -const regularQuery = query(searchCats, () => ['Persian']) +const regularQuery = query(searchCats, ['Persian']) // ^? data: Cat[] | undefined -const awaitedQuery = await query(searchCats, () => ['Persian']) +const awaitedQuery = await query(searchCats, ['Persian']) // ^? data: Cat[] ``` @@ -68,7 +68,7 @@ By default a query that hasn't been executed (or hasn't finished executing) will ```ts const placeholder: Cat[] = [] -const catsQuery = await query(searchCats, () => ['Bengal'], { placeholder }) +const catsQuery = await query(searchCats, ['Bengal'], { placeholder }) // ^? data: Cat[] ``` @@ -77,7 +77,7 @@ const catsQuery = await query(searchCats, () => ['Bengal'], { placeholder }) Automatically re-trigger the function on an interval. Value provided is time in milliseconds. ```ts -const catsQuery = await query(searchCats, () => ['Persian'], { interval: 30_000 }) +const catsQuery = await query(searchCats, ['Persian'], { interval: 30_000 }) // automatically calls `searchCats` when query is created, and then again every 30 seconds ``` @@ -86,7 +86,7 @@ const catsQuery = await query(searchCats, () => ['Persian'], { interval: 30_000 Automatically re-try the function when an error occurs. By default the query will wait `500` milliseconds between retries. ```ts -const catsQuery = query(searchCats, () => ['Siamese'], { retries: 3 }) +const catsQuery = query(searchCats, ['Siamese'], { retries: 3 }) // will try to call `searchCats` a total of 3 times, waiting 500 MS between each attempt ``` @@ -94,7 +94,7 @@ Alternatively you can pass in `RetryOptions`, which allows you to specify both a ```ts const retries = { count: 1, delay: 1_000 } -const catsQuery = query(searchCats, () => ['Siamese'], { retries: 3 }) +const catsQuery = query(searchCats, ['Siamese'], { retries: 3 }) // will retry after 1,000 MS once if initial call fails ``` @@ -108,7 +108,7 @@ The `useQuery` function adds some super useful, vue specific functionality you'd ### Parameters argument is reactive -When parameters for your query function change, the query is automatically updated. +The parameters for your query must be provided as a getter, which ensures they are reactive. When the parameters change, the query is automatically updated. The old query is disposed and a new query is created. ```ts import { useQuery } from '@kitbag/query' diff --git a/docs/core-concepts/tags-invalidation.md b/docs/core-concepts/tags-invalidation.md index edfc9f3..522f0d6 100644 --- a/docs/core-concepts/tags-invalidation.md +++ b/docs/core-concepts/tags-invalidation.md @@ -1,6 +1,6 @@ # Tags & Invalidation -When it comes time to refresh your query, there are a few options. First, each query has an `execute()` function, which will force the query to refetch and update the reactive `data` for your query but also any other query that shares the same function and arguments. +When it comes time to refresh your query, there are a few options. First, each query has an `execute()` function which will ensure your query function gets called again. ## refreshQueryData @@ -21,67 +21,30 @@ function handleRefreshClick(): void { ## Tags -Often we have multiple queries to different functions that are related to each other. For example, any queries that use the current user token in API headers would probably want to be called again if the token changes. Ideally these queries that are otherwise unrelated could be grouped together. +Often we have multiple queries to different functions that are related to each other. Ideally these queries that are otherwise unrelated could be grouped together. The group ensures an easy way to set or invalidate the cache for the whole group. -Tags offer a way to not only organize related queries but also to set and invalidate a cache for queries you might not have direct access to. Think of `tag` as a function that generates a unique identifier that helps Kitbag Query to find the query later. +As an example, let's group some queries that all use the same external API. That way when the API version changes, we can update all the queries at once because they share the same tag. -Since each tag generated is unique, we recommend creating and exporting your tags from a shared location. - -::: code-group - -```ts [tags.ts] -import { tag } from '@kitbag/query' - -export const requiresUserContext = tag() -``` - -::: - -Then from wherever queries are created the query options include `tags`, which expects an array of tags. - -::: code-group - -```vue [components/UserProfile.ts] +```vue -``` +const usesCatsApi = tag() -```vue [components/NotificationsIndicator.ts] - ``` -::: - -Then later perhaps when the user token changes, you can access and invalidate the cache for this tag. - -::: code-group - -```ts [services/auth.ts] -import { refreshQueryData } from '@kitbag/query' -import { requiresUserContext } from '../tags' - -function onLoginSuccessful(): void { - // refreshes both meQuery and notificationsQuery - refreshQueryData(requiresUserContext) -} -``` - -::: +Think of `tag` as a function that generates a unique identifier that helps Kitbag Query to find the query later. Since each tag generated is unique, we recommend creating and exporting your tags from a shared location. ## Tag Type -Kitbag Query also tracks a generic on each tag, which By default is `unknown`. This satisfies any query, but assigning your actual type not only validates the query type but also provides improved type safety later when accessing cached data, like in `setQueryData` +Kitbag Query also supports typed tags. Where a generic type can be added to a tag for extra type safety. By default the tag type is `unknown`. This satisfies any query, but assigning your actual type not only validates the query type but also provides improved type safety later when accessing cached data, like in `setQueryData`. ```ts import { tag, setQueryData } from '@kitbag/query' From 6162085f74590d69b3deb08c3588902b93ec333a Mon Sep 17 00:00:00 2001 From: Evan Sutherland Date: Wed, 22 Oct 2025 20:19:39 -0500 Subject: [PATCH 5/8] Update docs/core-concepts/tags-invalidation.md Co-authored-by: Craig Harshbarger --- docs/core-concepts/tags-invalidation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core-concepts/tags-invalidation.md b/docs/core-concepts/tags-invalidation.md index 522f0d6..a6e3260 100644 --- a/docs/core-concepts/tags-invalidation.md +++ b/docs/core-concepts/tags-invalidation.md @@ -21,7 +21,7 @@ function handleRefreshClick(): void { ## Tags -Often we have multiple queries to different functions that are related to each other. Ideally these queries that are otherwise unrelated could be grouped together. The group ensures an easy way to set or invalidate the cache for the whole group. +Often we have multiple queries to different functions that are related to each other. These queries that are otherwise unrelated could be grouped together. The group ensures an easy way to set or invalidate the cache for the whole group. As an example, let's group some queries that all use the same external API. That way when the API version changes, we can update all the queries at once because they share the same tag. From a26edef60df6040a9f80b004c35c36b0507da220 Mon Sep 17 00:00:00 2001 From: Evan Sutherland Date: Wed, 22 Oct 2025 21:04:58 -0500 Subject: [PATCH 6/8] code review suggestions --- docs/core-concepts/tags-invalidation.md | 60 ++++--------------------- 1 file changed, 9 insertions(+), 51 deletions(-) diff --git a/docs/core-concepts/tags-invalidation.md b/docs/core-concepts/tags-invalidation.md index a6e3260..9c70a73 100644 --- a/docs/core-concepts/tags-invalidation.md +++ b/docs/core-concepts/tags-invalidation.md @@ -23,20 +23,18 @@ function handleRefreshClick(): void { Often we have multiple queries to different functions that are related to each other. These queries that are otherwise unrelated could be grouped together. The group ensures an easy way to set or invalidate the cache for the whole group. -As an example, let's group some queries that all use the same external API. That way when the API version changes, we can update all the queries at once because they share the same tag. - ```vue ``` @@ -57,59 +55,19 @@ setQueryData(catTag, (data) => ...) ## Tag Factories -Tags can also be configured as factories, which offer a way to increase specificity through a callback you define. For example, if you have a bunch of instances of a component that has a query and you want to selectively invalidate cache. - -::: code-group - -```vue [components/CatViewer.vue] - -``` - -::: +Tags can also be configured as factories, which offer a way to increase specificity through a callback you define. -If in another part of your application you update the cat model, you could instead define a tag factory. - -::: code-group - -```ts [tags.ts] +```ts import { tag } from '@kitbag/query' export const catIdTag = tag(((catId: string) => catId)) ``` -```vue [components/CatViewer.vue] - -``` - -```vue [components/CatEditForm.vue] - ``` - -::: From 2750e581a5528153b2e7e7b9d35f403c9bf0bc92 Mon Sep 17 00:00:00 2001 From: Evan Sutherland Date: Fri, 24 Oct 2025 13:47:32 -0500 Subject: [PATCH 7/8] Update docs/core-concepts/tags-invalidation.md Co-authored-by: Craig Harshbarger --- docs/core-concepts/tags-invalidation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core-concepts/tags-invalidation.md b/docs/core-concepts/tags-invalidation.md index 9c70a73..58de977 100644 --- a/docs/core-concepts/tags-invalidation.md +++ b/docs/core-concepts/tags-invalidation.md @@ -21,7 +21,7 @@ function handleRefreshClick(): void { ## Tags -Often we have multiple queries to different functions that are related to each other. These queries that are otherwise unrelated could be grouped together. The group ensures an easy way to set or invalidate the cache for the whole group. +Often we have multiple queries to different functions that are related to each other. These queries could be grouped together using a tag. The tag ensures an easy way to set or invalidate the cache for the whole group. ```vue