convex-route-query 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,72 +1,297 @@
1
1
  # convex-route-query
2
2
 
3
- Type-safe Convex query helpers for TanStack Router loaders and React Query Suspense.
3
+ Type-safe Convex query helpers for TanStack Router loaders and React Query
4
+ Suspense.
5
+
6
+ `convex-route-query` lets a route preload a Convex query once, return the typed
7
+ query args as loader data, and then read the same query from the route component
8
+ without rebuilding params or search state.
4
9
 
5
10
  ```ts
6
- import { createConvexRouteQuery } from "convex-route-query";
11
+ import { createFileRoute } from "@tanstack/react-router";
12
+ import { createConvexRouteQueries } from "convex-route-query";
7
13
  import { api } from "../convex/_generated/api";
8
14
 
9
- const listExperiences = createConvexRouteQuery(
10
- api.resume.queries.listExperiences,
11
- );
15
+ const { listExperiences } = createConvexRouteQueries({
16
+ listExperiences: api.resume.queries.listExperiences,
17
+ });
12
18
 
13
19
  export const Route = createFileRoute("/experience/")({
14
- loader: async ({ context }) => {
15
- await listExperiences.prefetchQuery(context.queryClient);
16
- },
20
+ loader: async (ctx) => ({
21
+ ...(await listExperiences.prefetchRoute(ctx)),
22
+ }),
17
23
  component: ExperiencePage,
18
24
  });
19
25
 
20
26
  function ExperiencePage() {
21
- const { data } = listExperiences.useSuspenseQuery();
27
+ const { data } = listExperiences.useSuspenseRouteQuery(Route);
22
28
 
23
29
  return <ExperienceList experiences={data} />;
24
30
  }
25
31
  ```
26
32
 
27
- Queries with arguments infer their argument object from the Convex function reference.
33
+ ## Why this exists
34
+
35
+ Convex, TanStack Router, and TanStack Query fit together beautifully, but route
36
+ data loading can still get repetitive:
37
+
38
+ - The loader has the route params, validated search params, and `QueryClient`.
39
+ - The component needs the same Convex args again to call `useSuspenseQuery`.
40
+ - Convex query args should stay inferred from the generated `api`.
41
+ - `queryKey`, `queryFn`, and `staleTime` should come from `convexQuery(...)`, not
42
+ be rewritten by hand.
43
+
44
+ This package gives each query a stable typed route key:
45
+
46
+ ```ts
47
+ const getPost = createConvexRouteQuery("getPost", api.blog.queries.getPost);
48
+ ```
49
+
50
+ The loader returns the key by spreading `prefetchRoute(...)`, and the component
51
+ uses that key with `useSuspenseRouteQuery(Route)`. TypeScript makes sure those
52
+ two sides match.
53
+
54
+ ## Table of contents
55
+
56
+ - [Install](#install)
57
+ - [Before you start](#before-you-start)
58
+ - [Basic usage](#basic-usage)
59
+ - [Search params](#search-params)
60
+ - [Path params and loader work](#path-params-and-loader-work)
61
+ - [Non-suspense usage](#non-suspense-usage)
62
+ - [API reference](#api-reference)
63
+ - [Notes](#notes)
64
+
65
+ ## Install
66
+
67
+ ```sh
68
+ bun add convex-route-query
69
+ ```
70
+
71
+ ```sh
72
+ npm install convex-route-query
73
+ ```
74
+
75
+ `convex-route-query` expects these peer dependencies to be installed in your app:
76
+
77
+ ```sh
78
+ bun add @convex-dev/react-query @tanstack/react-query convex react
79
+ ```
80
+
81
+ ## Before you start
82
+
83
+ This package assumes Convex is already configured with TanStack Query and that
84
+ your TanStack Router context exposes a `queryClient` to route loaders.
85
+
86
+ If you have not wired that up yet, start with the official Convex docs:
87
+
88
+ - [Convex with TanStack Query](https://docs.convex.dev/client/tanstack/tanstack-query/)
89
+ - [TanStack Start quickstart](https://docs.convex.dev/quickstart/tanstack-start)
90
+ - [TanStack Start with Convex](https://docs.convex.dev/client/tanstack/tanstack-start/)
91
+
92
+ Once that setup is in place, `convex-route-query` gives you route-level helpers
93
+ on top of it.
94
+
95
+ ## Basic usage
96
+
97
+ Use `createConvexRouteQueries(...)` when you want keys inferred from object
98
+ property names.
99
+
100
+ ```ts
101
+ import { createFileRoute } from "@tanstack/react-router";
102
+ import { createConvexRouteQueries } from "convex-route-query";
103
+ import { api } from "../convex/_generated/api";
104
+
105
+ const { listPosts } = createConvexRouteQueries({
106
+ listPosts: api.blog.queries.listPosts,
107
+ });
108
+
109
+ export const Route = createFileRoute("/blog/")({
110
+ loader: async (ctx) => ({
111
+ ...(await listPosts.prefetchRoute(ctx)),
112
+ }),
113
+ component: BlogIndexPage,
114
+ });
115
+
116
+ function BlogIndexPage() {
117
+ const { data: posts } = listPosts.useSuspenseRouteQuery(Route);
118
+
119
+ return <PostList posts={posts} />;
120
+ }
121
+ ```
122
+
123
+ `prefetchRoute(ctx)` warms the TanStack Query cache and returns a small typed
124
+ loader-data fragment. `useSuspenseRouteQuery(Route)` reads that fragment from
125
+ `Route.useLoaderData()` and subscribes to the same Convex query.
126
+
127
+ ## Search params
128
+
129
+ When search params drive the query, put the exact Convex args in
130
+ `loaderDeps`. TanStack Router will reload when those deps change, and
131
+ `prefetchRoute(ctx)` can use `ctx.deps` automatically.
28
132
 
29
133
  ```ts
30
- const getPost = createConvexRouteQuery(api.blog.queries.getPost);
134
+ import { createFileRoute } from "@tanstack/react-router";
135
+ import { z } from "zod";
136
+ import { createConvexRouteQueries } from "convex-route-query";
137
+ import { api } from "../convex/_generated/api";
138
+
139
+ const postsSearchSchema = z.object({
140
+ page: z.number().catch(1),
141
+ tag: z.string().catch("all"),
142
+ });
143
+
144
+ const { listPosts } = createConvexRouteQueries({
145
+ listPosts: api.blog.queries.listPosts,
146
+ });
147
+
148
+ export const Route = createFileRoute("/blog/")({
149
+ validateSearch: postsSearchSchema,
150
+ loaderDeps: ({ search }) => ({
151
+ page: search.page,
152
+ tag: search.tag,
153
+ }),
154
+ loader: async (ctx) => ({
155
+ ...(await listPosts.prefetchRoute(ctx)),
156
+ }),
157
+ component: BlogIndexPage,
158
+ });
159
+
160
+ function BlogIndexPage() {
161
+ const { data: posts } = listPosts.useSuspenseRouteQuery(Route);
162
+
163
+ return <PostList posts={posts} />;
164
+ }
165
+ ```
166
+
167
+ The component does not call `Route.useSearch()` or rebuild the query args. The
168
+ loader already serialized the typed query args for this route match.
169
+
170
+ ## Path params and loader work
171
+
172
+ Use an explicit key when you only need one query, or when you prefer to name it
173
+ directly.
174
+
175
+ ```ts
176
+ const getPost = createConvexRouteQuery("getPost", api.blog.queries.getPost);
177
+ ```
178
+
179
+ For path params, or any loader that needs to combine params with other data, pass
180
+ the Convex args to `fetchRoute` or `prefetchRoute` explicitly. The component
181
+ still reads them from loader data.
182
+
183
+ ```ts
184
+ import { createFileRoute, notFound } from "@tanstack/react-router";
185
+ import { createConvexRouteQuery } from "convex-route-query";
186
+ import { api } from "../convex/_generated/api";
187
+
188
+ const getPost = createConvexRouteQuery("getPost", api.blog.queries.getPost);
31
189
 
32
190
  export const Route = createFileRoute("/blog/$slug")({
33
- loader: async ({ context, params }) => {
34
- const post = await getPost.fetchQuery(context.queryClient, {
35
- slug: params.slug,
191
+ loader: async (ctx) => {
192
+ const post = await getPost.fetchRoute(ctx, {
193
+ slug: ctx.params.slug,
36
194
  });
37
195
 
38
- if (!post) {
196
+ if (!post.data) {
39
197
  throw notFound();
40
198
  }
41
199
 
42
- return { post };
200
+ return {
201
+ ...post.routeData,
202
+ title: post.data.title,
203
+ };
43
204
  },
44
205
  component: BlogPostPage,
45
206
  });
46
207
 
47
208
  function BlogPostPage() {
48
- const { slug } = Route.useParams();
49
- const { data: post } = getPost.useSuspenseQuery({ slug });
209
+ const { data: post } = getPost.useSuspenseRouteQuery(Route);
210
+ const { title } = Route.useLoaderData();
50
211
 
51
- return <Post post={post} />;
212
+ return <Post post={post} title={title} />;
52
213
  }
53
214
  ```
54
215
 
55
- ## Install
216
+ Your loader can keep doing normal loader work: auth, redirects, extra prefetches,
217
+ metadata, and anything else. Just include the route data returned by
218
+ `prefetchRoute(...)` or `fetchRoute(...).routeData`.
56
219
 
57
- ```sh
58
- bun add convex-route-query
220
+ ## Non-suspense usage
221
+
222
+ Use `useQuery` when a component should render its own pending state.
223
+
224
+ ```ts
225
+ function DraftPostPage() {
226
+ const { slug } = Route.useParams();
227
+ const { data: post, isPending } = getPost.useQuery(
228
+ { slug },
229
+ { enabled: Boolean(slug) },
230
+ );
231
+
232
+ if (isPending) {
233
+ return <Spinner />;
234
+ }
235
+
236
+ return <PostEditor post={post} />;
237
+ }
59
238
  ```
60
239
 
61
- ## API
240
+ `useQuery` accepts normal TanStack Query options except the generated Convex
241
+ options owned by this package: `queryKey`, `queryFn`, and `staleTime`.
242
+
243
+ ## API reference
62
244
 
63
245
  ### `createConvexRouteQuery(query)`
64
246
 
65
- Returns an object with:
247
+ ```ts
248
+ const query = createConvexRouteQuery(api.someModule.someQuery);
249
+ ```
250
+
251
+ Creates the low-level helper. The runtime route key is derived from the Convex
252
+ function name, but TypeScript only sees a general `string` key.
253
+
254
+ ### `createConvexRouteQuery(id, query)`
255
+
256
+ ```ts
257
+ const getPost = createConvexRouteQuery("getPost", api.blog.queries.getPost);
258
+ ```
259
+
260
+ Creates a route-aware helper with an explicit typed key.
261
+
262
+ ### `createConvexRouteQueries(queries)`
263
+
264
+ ```ts
265
+ const { getPost, listPosts } = createConvexRouteQueries({
266
+ getPost: api.blog.queries.getPost,
267
+ listPosts: api.blog.queries.listPosts,
268
+ });
269
+ ```
270
+
271
+ Creates route-aware helpers whose typed keys are inferred from the object keys.
272
+
273
+ ### Helpers
274
+
275
+ | Helper | Use it when | Returns |
276
+ | ------------------------------------- | -------------------------------------------------------------- | ------------------------------------ |
277
+ | `options(...args)` | You need the underlying `convexQuery(...)` options. | Convex query options |
278
+ | `fetchQuery(queryClient, ...args)` | A loader or utility needs the query result directly. | `Promise<FunctionReturnType<Query>>` |
279
+ | `prefetchQuery(queryClient, ...args)` | A loader or utility should warm the cache directly. | `Promise<void>` |
280
+ | `fetchRoute(ctx, ...args?)` | A loader needs the result and a typed route-data fragment. | `{ data, routeData }` |
281
+ | `prefetchRoute(ctx, ...args?)` | A loader should warm the cache and return route data. | Typed route-data fragment |
282
+ | `useSuspenseRouteQuery(Route)` | A route component should read the query args from loader data. | Suspense query result |
283
+ | `useQuery(...args, queryOptions)` | A component wants non-suspense query state. | Query result |
284
+ | `useSuspenseQuery(...args)` | A component already has the args available. | Suspense query result |
285
+
286
+ The route helpers need `ctx.context.queryClient`. If no args are passed to
287
+ `fetchRoute` or `prefetchRoute`, the helper uses `ctx.deps`.
66
288
 
67
- - `options(...args)` - the underlying `convexQuery(...)` options.
68
- - `fetchQuery(queryClient, ...args)` - calls `queryClient.fetchQuery(...)`.
69
- - `prefetchQuery(queryClient, ...args)` - calls `queryClient.prefetchQuery(...)`.
70
- - `useSuspenseQuery(...args)` - calls React Query's `useSuspenseQuery(...)`.
289
+ ## Notes
71
290
 
72
- The loader helpers need a `QueryClient` because loaders run outside React context. The hook reads the `QueryClient` from React context.
291
+ - This package is intentionally small. It wraps Convex queries for route loading
292
+ and component reads; mutations and actions should use the normal Convex and
293
+ TanStack Query APIs.
294
+ - The internal loader-data key is stable and typed from your explicit key or from
295
+ `createConvexRouteQueries(...)` object keys.
296
+ - Convex query options are generated by `@convex-dev/react-query`, including the
297
+ query key and infinite stale time.
package/dist/index.cjs CHANGED
@@ -1,10 +1,21 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _convex_dev_react_query = require("@convex-dev/react-query");
3
3
  let _tanstack_react_query = require("@tanstack/react-query");
4
+ let convex_server = require("convex/server");
4
5
  //#region src/index.ts
5
- function createConvexRouteQuery(query) {
6
+ const routeDataKeyPrefix = "__convexRouteQuery:";
7
+ function createConvexRouteQuery(idOrQuery, maybeQuery) {
8
+ const query = maybeQuery ?? idOrQuery;
9
+ const id = typeof idOrQuery === "string" ? idOrQuery : (0, convex_server.getFunctionName)(idOrQuery);
10
+ const loaderDataKey = `${routeDataKeyPrefix}${id}`;
6
11
  const createOptions = _convex_dev_react_query.convexQuery;
7
12
  const options = (...args) => createOptions(query, ...args);
13
+ const createLoaderData = (args) => Object.fromEntries([[loaderDataKey, args]]);
14
+ const getRouteArgs = (routeContext, args) => args.length > 0 ? args[0] : "deps" in routeContext && routeContext.deps !== void 0 ? routeContext.deps : {};
15
+ const getLoaderDataArgs = (loaderData) => {
16
+ if (typeof loaderData !== "object" || loaderData === null || !(loaderDataKey in loaderData)) throw new Error(`Missing convex-route-query loader data for "${String(id)}". Return the result of prefetchRoute(...) from this route's loader.`);
17
+ return loaderData[loaderDataKey];
18
+ };
8
19
  return {
9
20
  options,
10
21
  fetchQuery(queryClient, ...args) {
@@ -13,12 +24,38 @@ function createConvexRouteQuery(query) {
13
24
  prefetchQuery(queryClient, ...args) {
14
25
  return queryClient.prefetchQuery(options(...args));
15
26
  },
27
+ async fetchRoute(routeContext, ...args) {
28
+ const queryArgs = getRouteArgs(routeContext, args);
29
+ return {
30
+ data: await routeContext.context.queryClient.fetchQuery(options(...[queryArgs])),
31
+ routeData: createLoaderData(queryArgs)
32
+ };
33
+ },
34
+ async prefetchRoute(routeContext, ...args) {
35
+ const queryArgs = getRouteArgs(routeContext, args);
36
+ await routeContext.context.queryClient.prefetchQuery(options(...[queryArgs]));
37
+ return createLoaderData(queryArgs);
38
+ },
39
+ useQuery(...args) {
40
+ const [queryArgs, queryOptions] = args;
41
+ return (0, _tanstack_react_query.useQuery)({
42
+ ...queryOptions,
43
+ ...options(...[queryArgs])
44
+ });
45
+ },
46
+ useSuspenseRouteQuery(route) {
47
+ return (0, _tanstack_react_query.useSuspenseQuery)(options(...[getLoaderDataArgs(route.useLoaderData())]));
48
+ },
16
49
  useSuspenseQuery(...args) {
17
50
  return (0, _tanstack_react_query.useSuspenseQuery)(options(...args));
18
51
  }
19
52
  };
20
53
  }
54
+ function createConvexRouteQueries(queries) {
55
+ return Object.fromEntries(Object.entries(queries).map(([id, query]) => [id, createConvexRouteQuery(id, query)]));
56
+ }
21
57
  //#endregion
58
+ exports.createConvexRouteQueries = createConvexRouteQueries;
22
59
  exports.createConvexRouteQuery = createConvexRouteQuery;
23
60
 
24
61
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["convexQuery"],"sources":["../src/index.ts"],"sourcesContent":["import { convexQuery } from \"@convex-dev/react-query\";\nimport {\n useSuspenseQuery as useTanStackSuspenseQuery,\n type UseSuspenseQueryResult,\n} from \"@tanstack/react-query\";\nimport type {\n FunctionArgs,\n FunctionReference,\n FunctionReturnType,\n OptionalRestArgs,\n} from \"convex/server\";\n\nexport type ConvexRouteQueryOptions<Query extends FunctionReference<\"query\">> =\n {\n queryKey: [\"convexQuery\", Query, FunctionArgs<Query>];\n staleTime: number;\n };\n\nexport type ConvexRouteQuery<Query extends FunctionReference<\"query\">> = {\n options: (...args: OptionalRestArgs<Query>) => ConvexRouteQueryOptions<Query>;\n fetchQuery: (\n queryClient: ConvexRouteQueryClient<Query>,\n ...args: OptionalRestArgs<Query>\n ) => Promise<FunctionReturnType<Query>>;\n prefetchQuery: (\n queryClient: ConvexRouteQueryClient<Query>,\n ...args: OptionalRestArgs<Query>\n ) => Promise<void>;\n useSuspenseQuery: (\n ...args: OptionalRestArgs<Query>\n ) => UseSuspenseQueryResult<FunctionReturnType<Query>, Error>;\n};\n\nexport type ConvexRouteQueryClient<Query extends FunctionReference<\"query\">> = {\n fetchQuery: (options: ConvexRouteQueryOptions<Query>) => Promise<unknown>;\n prefetchQuery: (options: ConvexRouteQueryOptions<Query>) => Promise<void>;\n};\n\ntype CreateConvexQueryOptions<Query extends FunctionReference<\"query\">> = (\n query: Query,\n ...args: OptionalRestArgs<Query>\n) => ConvexRouteQueryOptions<Query>;\n\nexport function createConvexRouteQuery<\n Query extends FunctionReference<\"query\">,\n>(query: Query): ConvexRouteQuery<Query> {\n const createOptions =\n convexQuery as unknown as CreateConvexQueryOptions<Query>;\n const options = (...args: OptionalRestArgs<Query>) =>\n createOptions(query, ...args);\n\n return {\n options,\n fetchQuery(queryClient, ...args) {\n return queryClient.fetchQuery(options(...args)) as Promise<\n FunctionReturnType<Query>\n >;\n },\n prefetchQuery(queryClient, ...args) {\n return queryClient.prefetchQuery(options(...args));\n },\n useSuspenseQuery(...args) {\n return useTanStackSuspenseQuery(options(...args));\n },\n };\n}\n"],"mappings":";;;;AA2CA,SAAgB,uBAEd,OAAuC;CACvC,MAAM,gBACJA,wBAAAA;CACF,MAAM,WAAW,GAAG,SAClB,cAAc,OAAO,GAAG,IAAI;CAE9B,OAAO;EACL;EACA,WAAW,aAAa,GAAG,MAAM;GAC/B,OAAO,YAAY,WAAW,QAAQ,GAAG,IAAI,CAAC;EAGhD;EACA,cAAc,aAAa,GAAG,MAAM;GAClC,OAAO,YAAY,cAAc,QAAQ,GAAG,IAAI,CAAC;EACnD;EACA,iBAAiB,GAAG,MAAM;GACxB,QAAA,GAAA,sBAAA,iBAAA,CAAgC,QAAQ,GAAG,IAAI,CAAC;EAClD;CACF;AACF"}
1
+ {"version":3,"file":"index.cjs","names":["convexQuery","routeArgs"],"sources":["../src/index.ts"],"sourcesContent":["import { convexQuery } from \"@convex-dev/react-query\";\nimport {\n useQuery as useTanStackQuery,\n useSuspenseQuery as useTanStackSuspenseQuery,\n type UseQueryOptions,\n type UseQueryResult,\n type UseSuspenseQueryResult,\n} from \"@tanstack/react-query\";\nimport {\n getFunctionName,\n type ArgsAndOptions,\n type FunctionArgs,\n type FunctionReference,\n type FunctionReturnType,\n type OptionalRestArgs,\n} from \"convex/server\";\n\nconst routeDataKeyPrefix = \"__convexRouteQuery:\";\n\nexport type ConvexRouteQueryLoaderKey<Id extends string> =\n `${typeof routeDataKeyPrefix}${Id}`;\n\nexport type ConvexRouteQueryLoaderData<\n Id extends string,\n Query extends FunctionReference<\"query\">,\n> = Record<ConvexRouteQueryLoaderKey<Id>, FunctionArgs<Query>>;\n\nexport type ConvexRouteQueryOptions<Query extends FunctionReference<\"query\">> =\n {\n queryKey: [\"convexQuery\", Query, FunctionArgs<Query>];\n staleTime: number;\n };\n\nexport type ConvexRouteUseQueryOptions<\n Query extends FunctionReference<\"query\">,\n Data = FunctionReturnType<Query>,\n> = Omit<\n UseQueryOptions<\n FunctionReturnType<Query>,\n Error,\n Data,\n ConvexRouteQueryOptions<Query>[\"queryKey\"]\n >,\n \"queryKey\" | \"queryFn\" | \"staleTime\"\n>;\n\nexport type ConvexRouteQuery<\n Query extends FunctionReference<\"query\">,\n Id extends string = string,\n> = {\n options: (...args: OptionalRestArgs<Query>) => ConvexRouteQueryOptions<Query>;\n fetchQuery: (\n queryClient: ConvexRouteQueryClient<Query>,\n ...args: OptionalRestArgs<Query>\n ) => Promise<FunctionReturnType<Query>>;\n prefetchQuery: (\n queryClient: ConvexRouteQueryClient<Query>,\n ...args: OptionalRestArgs<Query>\n ) => Promise<void>;\n fetchRoute: {\n (\n routeContext: ConvexRouteQueryRouteContext<Query>,\n ): Promise<ConvexRouteQueryFetchRouteResult<Id, Query>>;\n (\n routeContext: ConvexRouteQueryClientContext<Query>,\n ...args: OptionalRestArgs<Query>\n ): Promise<ConvexRouteQueryFetchRouteResult<Id, Query>>;\n };\n prefetchRoute: {\n (\n routeContext: ConvexRouteQueryRouteContext<Query>,\n ): Promise<ConvexRouteQueryLoaderData<Id, Query>>;\n (\n routeContext: ConvexRouteQueryClientContext<Query>,\n ...args: OptionalRestArgs<Query>\n ): Promise<ConvexRouteQueryLoaderData<Id, Query>>;\n };\n useQuery: <Data = FunctionReturnType<Query>>(\n ...args: ArgsAndOptions<Query, ConvexRouteUseQueryOptions<Query, Data>>\n ) => UseQueryResult<Data, Error>;\n useSuspenseRouteQuery: (\n route: ConvexRouteQueryRoute<Id, Query>,\n ) => UseSuspenseQueryResult<FunctionReturnType<Query>, Error>;\n useSuspenseQuery: (\n ...args: OptionalRestArgs<Query>\n ) => UseSuspenseQueryResult<FunctionReturnType<Query>, Error>;\n};\n\nexport type ConvexRouteQueryClient<Query extends FunctionReference<\"query\">> = {\n fetchQuery: (options: ConvexRouteQueryOptions<Query>) => Promise<unknown>;\n prefetchQuery: (options: ConvexRouteQueryOptions<Query>) => Promise<void>;\n};\n\nexport type ConvexRouteQueryClientContext<\n Query extends FunctionReference<\"query\">,\n> = {\n context: {\n queryClient: ConvexRouteQueryClient<Query>;\n };\n};\n\ntype ConvexRouteQueryRouteDeps<Query extends FunctionReference<\"query\">> =\n keyof FunctionArgs<Query> extends never\n ? {\n deps?: FunctionArgs<Query>;\n }\n : {\n deps: FunctionArgs<Query>;\n };\n\nexport type ConvexRouteQueryRouteContext<\n Query extends FunctionReference<\"query\">,\n> = ConvexRouteQueryClientContext<Query> & ConvexRouteQueryRouteDeps<Query>;\n\nexport type ConvexRouteQueryFetchRouteResult<\n Id extends string,\n Query extends FunctionReference<\"query\">,\n> = {\n data: FunctionReturnType<Query>;\n routeData: ConvexRouteQueryLoaderData<Id, Query>;\n};\n\nexport type ConvexRouteQueryRoute<\n Id extends string,\n Query extends FunctionReference<\"query\">,\n> = {\n useLoaderData: () => ConvexRouteQueryLoaderData<Id, Query>;\n};\n\ntype CreateConvexQueryOptions<Query extends FunctionReference<\"query\">> = (\n query: Query,\n ...args: OptionalRestArgs<Query>\n) => ConvexRouteQueryOptions<Query>;\n\nexport function createConvexRouteQuery<\n Query extends FunctionReference<\"query\">,\n>(query: Query): ConvexRouteQuery<Query>;\nexport function createConvexRouteQuery<\n const Id extends string,\n Query extends FunctionReference<\"query\">,\n>(id: Id, query: Query): ConvexRouteQuery<Query, Id>;\nexport function createConvexRouteQuery<\n const Id extends string,\n Query extends FunctionReference<\"query\">,\n>(\n idOrQuery: Id | Query,\n maybeQuery?: Query,\n): ConvexRouteQuery<Query, Id | string> {\n const query = (maybeQuery ?? idOrQuery) as Query;\n const id =\n typeof idOrQuery === \"string\"\n ? idOrQuery\n : getFunctionName(idOrQuery as Query);\n const loaderDataKey =\n `${routeDataKeyPrefix}${id}` as ConvexRouteQueryLoaderKey<Id | string>;\n const createOptions =\n convexQuery as unknown as CreateConvexQueryOptions<Query>;\n const options = (...args: OptionalRestArgs<Query>) =>\n createOptions(query, ...args);\n const createLoaderData = (args: FunctionArgs<Query>) =>\n Object.fromEntries([\n [loaderDataKey, args],\n ]) as unknown as ConvexRouteQueryLoaderData<Id | string, Query>;\n const getRouteArgs = (\n routeContext:\n | ConvexRouteQueryClientContext<Query>\n | ConvexRouteQueryRouteContext<Query>,\n args: OptionalRestArgs<Query>,\n ) =>\n (args.length > 0\n ? args[0]\n : \"deps\" in routeContext && routeContext.deps !== undefined\n ? routeContext.deps\n : {}) as FunctionArgs<Query>;\n const getLoaderDataArgs = (\n loaderData: ConvexRouteQueryLoaderData<Id, Query>,\n ) => {\n if (\n typeof loaderData !== \"object\" ||\n loaderData === null ||\n !(loaderDataKey in loaderData)\n ) {\n throw new Error(\n `Missing convex-route-query loader data for \"${String(id)}\". Return the result of prefetchRoute(...) from this route's loader.`,\n );\n }\n\n return loaderData[\n loaderDataKey as keyof typeof loaderData\n ] as FunctionArgs<Query>;\n };\n\n return {\n options,\n fetchQuery(queryClient, ...args) {\n return queryClient.fetchQuery(options(...args)) as Promise<\n FunctionReturnType<Query>\n >;\n },\n prefetchQuery(queryClient, ...args) {\n return queryClient.prefetchQuery(options(...args));\n },\n async fetchRoute(routeContext, ...args) {\n const routeArgs = args as OptionalRestArgs<Query>;\n const queryArgs = getRouteArgs(routeContext, routeArgs);\n const data = await routeContext.context.queryClient.fetchQuery(\n options(...([queryArgs] as OptionalRestArgs<Query>)),\n );\n\n return {\n data: data as FunctionReturnType<Query>,\n routeData: createLoaderData(queryArgs),\n };\n },\n async prefetchRoute(routeContext, ...args) {\n const routeArgs = args as OptionalRestArgs<Query>;\n const queryArgs = getRouteArgs(routeContext, routeArgs);\n\n await routeContext.context.queryClient.prefetchQuery(\n options(...([queryArgs] as OptionalRestArgs<Query>)),\n );\n\n return createLoaderData(queryArgs);\n },\n useQuery(...args) {\n const [queryArgs, queryOptions] = args;\n\n return useTanStackQuery({\n ...queryOptions,\n ...options(...([queryArgs] as OptionalRestArgs<Query>)),\n });\n },\n useSuspenseRouteQuery(route) {\n const loaderData = route.useLoaderData();\n const queryArgs = getLoaderDataArgs(loaderData);\n\n return useTanStackSuspenseQuery(\n options(...([queryArgs] as OptionalRestArgs<Query>)),\n );\n },\n useSuspenseQuery(...args) {\n return useTanStackSuspenseQuery(options(...args));\n },\n };\n}\n\nexport function createConvexRouteQueries<\n const Queries extends Record<string, FunctionReference<\"query\">>,\n>(\n queries: Queries,\n): {\n [Id in keyof Queries & string]: ConvexRouteQuery<Queries[Id], Id>;\n} {\n return Object.fromEntries(\n Object.entries(queries).map(([id, query]) => [\n id,\n createConvexRouteQuery(id, query),\n ]),\n ) as unknown as {\n [Id in keyof Queries & string]: ConvexRouteQuery<Queries[Id], Id>;\n };\n}\n"],"mappings":";;;;;AAiBA,MAAM,qBAAqB;AA4H3B,SAAgB,uBAId,WACA,YACsC;CACtC,MAAM,QAAS,cAAc;CAC7B,MAAM,KACJ,OAAO,cAAc,WACjB,aAAA,GAAA,cAAA,gBAAA,CACgB,SAAkB;CACxC,MAAM,gBACJ,GAAG,qBAAqB;CAC1B,MAAM,gBACJA,wBAAAA;CACF,MAAM,WAAW,GAAG,SAClB,cAAc,OAAO,GAAG,IAAI;CAC9B,MAAM,oBAAoB,SACxB,OAAO,YAAY,CACjB,CAAC,eAAe,IAAI,CACtB,CAAC;CACH,MAAM,gBACJ,cAGA,SAEC,KAAK,SAAS,IACX,KAAK,KACL,UAAU,gBAAgB,aAAa,SAAS,KAAA,IAC9C,aAAa,OACb,CAAC;CACT,MAAM,qBACJ,eACG;EACH,IACE,OAAO,eAAe,YACtB,eAAe,QACf,EAAE,iBAAiB,aAEnB,MAAM,IAAI,MACR,+CAA+C,OAAO,EAAE,EAAE,qEAC5D;EAGF,OAAO,WACL;CAEJ;CAEA,OAAO;EACL;EACA,WAAW,aAAa,GAAG,MAAM;GAC/B,OAAO,YAAY,WAAW,QAAQ,GAAG,IAAI,CAAC;EAGhD;EACA,cAAc,aAAa,GAAG,MAAM;GAClC,OAAO,YAAY,cAAc,QAAQ,GAAG,IAAI,CAAC;EACnD;EACA,MAAM,WAAW,cAAc,GAAG,MAAM;GAEtC,MAAM,YAAY,aAAa,cAAcC,IAAS;GAKtD,OAAO;IACL,MAAM,MALW,aAAa,QAAQ,YAAY,WAClD,QAAQ,GAAI,CAAC,SAAS,CAA6B,CACrD;IAIE,WAAW,iBAAiB,SAAS;GACvC;EACF;EACA,MAAM,cAAc,cAAc,GAAG,MAAM;GAEzC,MAAM,YAAY,aAAa,cAAcA,IAAS;GAEtD,MAAM,aAAa,QAAQ,YAAY,cACrC,QAAQ,GAAI,CAAC,SAAS,CAA6B,CACrD;GAEA,OAAO,iBAAiB,SAAS;EACnC;EACA,SAAS,GAAG,MAAM;GAChB,MAAM,CAAC,WAAW,gBAAgB;GAElC,QAAA,GAAA,sBAAA,SAAA,CAAwB;IACtB,GAAG;IACH,GAAG,QAAQ,GAAI,CAAC,SAAS,CAA6B;GACxD,CAAC;EACH;EACA,sBAAsB,OAAO;GAI3B,QAAA,GAAA,sBAAA,iBAAA,CACE,QAAQ,GAAI,CAHI,kBADC,MAAM,cACoB,CAGtB,CAAC,CAA6B,CACrD;EACF;EACA,iBAAiB,GAAG,MAAM;GACxB,QAAA,GAAA,sBAAA,iBAAA,CAAgC,QAAQ,GAAG,IAAI,CAAC;EAClD;CACF;AACF;AAEA,SAAgB,yBAGd,SAGA;CACA,OAAO,OAAO,YACZ,OAAO,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,WAAW,CAC3C,IACA,uBAAuB,IAAI,KAAK,CAClC,CAAC,CACH;AAGF"}
package/dist/index.d.cts CHANGED
@@ -1,22 +1,56 @@
1
- import { UseSuspenseQueryResult } from "@tanstack/react-query";
2
- import { FunctionArgs, FunctionReference, FunctionReturnType, OptionalRestArgs } from "convex/server";
1
+ import { UseQueryOptions, UseQueryResult, UseSuspenseQueryResult } from "@tanstack/react-query";
2
+ import { ArgsAndOptions, FunctionArgs, FunctionReference, FunctionReturnType, OptionalRestArgs } from "convex/server";
3
3
 
4
4
  //#region src/index.d.ts
5
+ declare const routeDataKeyPrefix = "__convexRouteQuery:";
6
+ type ConvexRouteQueryLoaderKey<Id extends string> = `${typeof routeDataKeyPrefix}${Id}`;
7
+ type ConvexRouteQueryLoaderData<Id extends string, Query extends FunctionReference<"query">> = Record<ConvexRouteQueryLoaderKey<Id>, FunctionArgs<Query>>;
5
8
  type ConvexRouteQueryOptions<Query extends FunctionReference<"query">> = {
6
9
  queryKey: ["convexQuery", Query, FunctionArgs<Query>];
7
10
  staleTime: number;
8
11
  };
9
- type ConvexRouteQuery<Query extends FunctionReference<"query">> = {
12
+ type ConvexRouteUseQueryOptions<Query extends FunctionReference<"query">, Data = FunctionReturnType<Query>> = Omit<UseQueryOptions<FunctionReturnType<Query>, Error, Data, ConvexRouteQueryOptions<Query>["queryKey"]>, "queryKey" | "queryFn" | "staleTime">;
13
+ type ConvexRouteQuery<Query extends FunctionReference<"query">, Id extends string = string> = {
10
14
  options: (...args: OptionalRestArgs<Query>) => ConvexRouteQueryOptions<Query>;
11
15
  fetchQuery: (queryClient: ConvexRouteQueryClient<Query>, ...args: OptionalRestArgs<Query>) => Promise<FunctionReturnType<Query>>;
12
16
  prefetchQuery: (queryClient: ConvexRouteQueryClient<Query>, ...args: OptionalRestArgs<Query>) => Promise<void>;
17
+ fetchRoute: {
18
+ (routeContext: ConvexRouteQueryRouteContext<Query>): Promise<ConvexRouteQueryFetchRouteResult<Id, Query>>;
19
+ (routeContext: ConvexRouteQueryClientContext<Query>, ...args: OptionalRestArgs<Query>): Promise<ConvexRouteQueryFetchRouteResult<Id, Query>>;
20
+ };
21
+ prefetchRoute: {
22
+ (routeContext: ConvexRouteQueryRouteContext<Query>): Promise<ConvexRouteQueryLoaderData<Id, Query>>;
23
+ (routeContext: ConvexRouteQueryClientContext<Query>, ...args: OptionalRestArgs<Query>): Promise<ConvexRouteQueryLoaderData<Id, Query>>;
24
+ };
25
+ useQuery: <Data = FunctionReturnType<Query>>(...args: ArgsAndOptions<Query, ConvexRouteUseQueryOptions<Query, Data>>) => UseQueryResult<Data, Error>;
26
+ useSuspenseRouteQuery: (route: ConvexRouteQueryRoute<Id, Query>) => UseSuspenseQueryResult<FunctionReturnType<Query>, Error>;
13
27
  useSuspenseQuery: (...args: OptionalRestArgs<Query>) => UseSuspenseQueryResult<FunctionReturnType<Query>, Error>;
14
28
  };
15
29
  type ConvexRouteQueryClient<Query extends FunctionReference<"query">> = {
16
30
  fetchQuery: (options: ConvexRouteQueryOptions<Query>) => Promise<unknown>;
17
31
  prefetchQuery: (options: ConvexRouteQueryOptions<Query>) => Promise<void>;
18
32
  };
33
+ type ConvexRouteQueryClientContext<Query extends FunctionReference<"query">> = {
34
+ context: {
35
+ queryClient: ConvexRouteQueryClient<Query>;
36
+ };
37
+ };
38
+ type ConvexRouteQueryRouteDeps<Query extends FunctionReference<"query">> = keyof FunctionArgs<Query> extends never ? {
39
+ deps?: FunctionArgs<Query>;
40
+ } : {
41
+ deps: FunctionArgs<Query>;
42
+ };
43
+ type ConvexRouteQueryRouteContext<Query extends FunctionReference<"query">> = ConvexRouteQueryClientContext<Query> & ConvexRouteQueryRouteDeps<Query>;
44
+ type ConvexRouteQueryFetchRouteResult<Id extends string, Query extends FunctionReference<"query">> = {
45
+ data: FunctionReturnType<Query>;
46
+ routeData: ConvexRouteQueryLoaderData<Id, Query>;
47
+ };
48
+ type ConvexRouteQueryRoute<Id extends string, Query extends FunctionReference<"query">> = {
49
+ useLoaderData: () => ConvexRouteQueryLoaderData<Id, Query>;
50
+ };
19
51
  declare function createConvexRouteQuery<Query extends FunctionReference<"query">>(query: Query): ConvexRouteQuery<Query>;
52
+ declare function createConvexRouteQuery<const Id extends string, Query extends FunctionReference<"query">>(id: Id, query: Query): ConvexRouteQuery<Query, Id>;
53
+ declare function createConvexRouteQueries<const Queries extends Record<string, FunctionReference<"query">>>(queries: Queries): { [Id in keyof Queries & string]: ConvexRouteQuery<Queries[Id], Id> };
20
54
  //#endregion
21
- export { ConvexRouteQuery, ConvexRouteQueryClient, ConvexRouteQueryOptions, createConvexRouteQuery };
55
+ export { ConvexRouteQuery, ConvexRouteQueryClient, ConvexRouteQueryClientContext, ConvexRouteQueryFetchRouteResult, ConvexRouteQueryLoaderData, ConvexRouteQueryLoaderKey, ConvexRouteQueryOptions, ConvexRouteQueryRoute, ConvexRouteQueryRouteContext, ConvexRouteUseQueryOptions, createConvexRouteQueries, createConvexRouteQuery };
22
56
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;KAYY,uBAAA,eAAsC,iBAAA;EAE9C,QAAA,kBAA0B,KAAA,EAAO,YAAA,CAAa,KAAA;EAC9C,SAAA;AAAA;AAAA,KAGQ,gBAAA,eAA+B,iBAAA;EACzC,OAAA,MAAa,IAAA,EAAM,gBAAA,CAAiB,KAAA,MAAW,uBAAA,CAAwB,KAAA;EACvE,UAAA,GACE,WAAA,EAAa,sBAAA,CAAuB,KAAA,MACjC,IAAA,EAAM,gBAAA,CAAiB,KAAA,MACvB,OAAA,CAAQ,kBAAA,CAAmB,KAAA;EAChC,aAAA,GACE,WAAA,EAAa,sBAAA,CAAuB,KAAA,MACjC,IAAA,EAAM,gBAAA,CAAiB,KAAA,MACvB,OAAA;EACL,gBAAA,MACK,IAAA,EAAM,gBAAA,CAAiB,KAAA,MACvB,sBAAA,CAAuB,kBAAA,CAAmB,KAAA,GAAQ,KAAA;AAAA;AAAA,KAG7C,sBAAA,eAAqC,iBAAA;EAC/C,UAAA,GAAa,OAAA,EAAS,uBAAA,CAAwB,KAAA,MAAW,OAAA;EACzD,aAAA,GAAgB,OAAA,EAAS,uBAAA,CAAwB,KAAA,MAAW,OAAA;AAAA;AAAA,iBAQ9C,sBAAA,eACA,iBAAA,WACd,KAAA,EAAO,KAAA,GAAQ,gBAAA,CAAiB,KAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -1,22 +1,56 @@
1
- import { UseSuspenseQueryResult } from "@tanstack/react-query";
2
- import { FunctionArgs, FunctionReference, FunctionReturnType, OptionalRestArgs } from "convex/server";
1
+ import { UseQueryOptions, UseQueryResult, UseSuspenseQueryResult } from "@tanstack/react-query";
2
+ import { ArgsAndOptions, FunctionArgs, FunctionReference, FunctionReturnType, OptionalRestArgs } from "convex/server";
3
3
 
4
4
  //#region src/index.d.ts
5
+ declare const routeDataKeyPrefix = "__convexRouteQuery:";
6
+ type ConvexRouteQueryLoaderKey<Id extends string> = `${typeof routeDataKeyPrefix}${Id}`;
7
+ type ConvexRouteQueryLoaderData<Id extends string, Query extends FunctionReference<"query">> = Record<ConvexRouteQueryLoaderKey<Id>, FunctionArgs<Query>>;
5
8
  type ConvexRouteQueryOptions<Query extends FunctionReference<"query">> = {
6
9
  queryKey: ["convexQuery", Query, FunctionArgs<Query>];
7
10
  staleTime: number;
8
11
  };
9
- type ConvexRouteQuery<Query extends FunctionReference<"query">> = {
12
+ type ConvexRouteUseQueryOptions<Query extends FunctionReference<"query">, Data = FunctionReturnType<Query>> = Omit<UseQueryOptions<FunctionReturnType<Query>, Error, Data, ConvexRouteQueryOptions<Query>["queryKey"]>, "queryKey" | "queryFn" | "staleTime">;
13
+ type ConvexRouteQuery<Query extends FunctionReference<"query">, Id extends string = string> = {
10
14
  options: (...args: OptionalRestArgs<Query>) => ConvexRouteQueryOptions<Query>;
11
15
  fetchQuery: (queryClient: ConvexRouteQueryClient<Query>, ...args: OptionalRestArgs<Query>) => Promise<FunctionReturnType<Query>>;
12
16
  prefetchQuery: (queryClient: ConvexRouteQueryClient<Query>, ...args: OptionalRestArgs<Query>) => Promise<void>;
17
+ fetchRoute: {
18
+ (routeContext: ConvexRouteQueryRouteContext<Query>): Promise<ConvexRouteQueryFetchRouteResult<Id, Query>>;
19
+ (routeContext: ConvexRouteQueryClientContext<Query>, ...args: OptionalRestArgs<Query>): Promise<ConvexRouteQueryFetchRouteResult<Id, Query>>;
20
+ };
21
+ prefetchRoute: {
22
+ (routeContext: ConvexRouteQueryRouteContext<Query>): Promise<ConvexRouteQueryLoaderData<Id, Query>>;
23
+ (routeContext: ConvexRouteQueryClientContext<Query>, ...args: OptionalRestArgs<Query>): Promise<ConvexRouteQueryLoaderData<Id, Query>>;
24
+ };
25
+ useQuery: <Data = FunctionReturnType<Query>>(...args: ArgsAndOptions<Query, ConvexRouteUseQueryOptions<Query, Data>>) => UseQueryResult<Data, Error>;
26
+ useSuspenseRouteQuery: (route: ConvexRouteQueryRoute<Id, Query>) => UseSuspenseQueryResult<FunctionReturnType<Query>, Error>;
13
27
  useSuspenseQuery: (...args: OptionalRestArgs<Query>) => UseSuspenseQueryResult<FunctionReturnType<Query>, Error>;
14
28
  };
15
29
  type ConvexRouteQueryClient<Query extends FunctionReference<"query">> = {
16
30
  fetchQuery: (options: ConvexRouteQueryOptions<Query>) => Promise<unknown>;
17
31
  prefetchQuery: (options: ConvexRouteQueryOptions<Query>) => Promise<void>;
18
32
  };
33
+ type ConvexRouteQueryClientContext<Query extends FunctionReference<"query">> = {
34
+ context: {
35
+ queryClient: ConvexRouteQueryClient<Query>;
36
+ };
37
+ };
38
+ type ConvexRouteQueryRouteDeps<Query extends FunctionReference<"query">> = keyof FunctionArgs<Query> extends never ? {
39
+ deps?: FunctionArgs<Query>;
40
+ } : {
41
+ deps: FunctionArgs<Query>;
42
+ };
43
+ type ConvexRouteQueryRouteContext<Query extends FunctionReference<"query">> = ConvexRouteQueryClientContext<Query> & ConvexRouteQueryRouteDeps<Query>;
44
+ type ConvexRouteQueryFetchRouteResult<Id extends string, Query extends FunctionReference<"query">> = {
45
+ data: FunctionReturnType<Query>;
46
+ routeData: ConvexRouteQueryLoaderData<Id, Query>;
47
+ };
48
+ type ConvexRouteQueryRoute<Id extends string, Query extends FunctionReference<"query">> = {
49
+ useLoaderData: () => ConvexRouteQueryLoaderData<Id, Query>;
50
+ };
19
51
  declare function createConvexRouteQuery<Query extends FunctionReference<"query">>(query: Query): ConvexRouteQuery<Query>;
52
+ declare function createConvexRouteQuery<const Id extends string, Query extends FunctionReference<"query">>(id: Id, query: Query): ConvexRouteQuery<Query, Id>;
53
+ declare function createConvexRouteQueries<const Queries extends Record<string, FunctionReference<"query">>>(queries: Queries): { [Id in keyof Queries & string]: ConvexRouteQuery<Queries[Id], Id> };
20
54
  //#endregion
21
- export { ConvexRouteQuery, ConvexRouteQueryClient, ConvexRouteQueryOptions, createConvexRouteQuery };
55
+ export { ConvexRouteQuery, ConvexRouteQueryClient, ConvexRouteQueryClientContext, ConvexRouteQueryFetchRouteResult, ConvexRouteQueryLoaderData, ConvexRouteQueryLoaderKey, ConvexRouteQueryOptions, ConvexRouteQueryRoute, ConvexRouteQueryRouteContext, ConvexRouteUseQueryOptions, createConvexRouteQueries, createConvexRouteQuery };
22
56
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;KAYY,uBAAA,eAAsC,iBAAA;EAE9C,QAAA,kBAA0B,KAAA,EAAO,YAAA,CAAa,KAAA;EAC9C,SAAA;AAAA;AAAA,KAGQ,gBAAA,eAA+B,iBAAA;EACzC,OAAA,MAAa,IAAA,EAAM,gBAAA,CAAiB,KAAA,MAAW,uBAAA,CAAwB,KAAA;EACvE,UAAA,GACE,WAAA,EAAa,sBAAA,CAAuB,KAAA,MACjC,IAAA,EAAM,gBAAA,CAAiB,KAAA,MACvB,OAAA,CAAQ,kBAAA,CAAmB,KAAA;EAChC,aAAA,GACE,WAAA,EAAa,sBAAA,CAAuB,KAAA,MACjC,IAAA,EAAM,gBAAA,CAAiB,KAAA,MACvB,OAAA;EACL,gBAAA,MACK,IAAA,EAAM,gBAAA,CAAiB,KAAA,MACvB,sBAAA,CAAuB,kBAAA,CAAmB,KAAA,GAAQ,KAAA;AAAA;AAAA,KAG7C,sBAAA,eAAqC,iBAAA;EAC/C,UAAA,GAAa,OAAA,EAAS,uBAAA,CAAwB,KAAA,MAAW,OAAA;EACzD,aAAA,GAAgB,OAAA,EAAS,uBAAA,CAAwB,KAAA,MAAW,OAAA;AAAA;AAAA,iBAQ9C,sBAAA,eACA,iBAAA,WACd,KAAA,EAAO,KAAA,GAAQ,gBAAA,CAAiB,KAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;cAiBM,kBAAA;AAAA,KAEM,yBAAA,gCACA,kBAAA,GAAqB,EAAE;AAAA,KAEvB,0BAAA,kCAEI,iBAAA,aACZ,MAAA,CAAO,yBAAA,CAA0B,EAAA,GAAK,YAAA,CAAa,KAAA;AAAA,KAE3C,uBAAA,eAAsC,iBAAA;EAE9C,QAAA,kBAA0B,KAAA,EAAO,YAAA,CAAa,KAAA;EAC9C,SAAA;AAAA;AAAA,KAGQ,0BAAA,eACI,iBAAA,kBACP,kBAAA,CAAmB,KAAA,KACxB,IAAA,CACF,eAAA,CACE,kBAAA,CAAmB,KAAA,GACnB,KAAA,EACA,IAAA,EACA,uBAAA,CAAwB,KAAA;AAAA,KAKhB,gBAAA,eACI,iBAAA;EAGd,OAAA,MAAa,IAAA,EAAM,gBAAA,CAAiB,KAAA,MAAW,uBAAA,CAAwB,KAAA;EACvE,UAAA,GACE,WAAA,EAAa,sBAAA,CAAuB,KAAA,MACjC,IAAA,EAAM,gBAAA,CAAiB,KAAA,MACvB,OAAA,CAAQ,kBAAA,CAAmB,KAAA;EAChC,aAAA,GACE,WAAA,EAAa,sBAAA,CAAuB,KAAA,MACjC,IAAA,EAAM,gBAAA,CAAiB,KAAA,MACvB,OAAA;EACL,UAAA;IAAA,CAEI,YAAA,EAAc,4BAAA,CAA6B,KAAA,IAC1C,OAAA,CAAQ,gCAAA,CAAiC,EAAA,EAAI,KAAA;IAAA,CAE9C,YAAA,EAAc,6BAAA,CAA8B,KAAA,MACzC,IAAA,EAAM,gBAAA,CAAiB,KAAA,IACzB,OAAA,CAAQ,gCAAA,CAAiC,EAAA,EAAI,KAAA;EAAA;EAElD,aAAA;IAAA,CAEI,YAAA,EAAc,4BAAA,CAA6B,KAAA,IAC1C,OAAA,CAAQ,0BAAA,CAA2B,EAAA,EAAI,KAAA;IAAA,CAExC,YAAA,EAAc,6BAAA,CAA8B,KAAA,MACzC,IAAA,EAAM,gBAAA,CAAiB,KAAA,IACzB,OAAA,CAAQ,0BAAA,CAA2B,EAAA,EAAI,KAAA;EAAA;EAE5C,QAAA,UAAkB,kBAAA,CAAmB,KAAA,MAChC,IAAA,EAAM,cAAA,CAAe,KAAA,EAAO,0BAAA,CAA2B,KAAA,EAAO,IAAA,OAC9D,cAAA,CAAe,IAAA,EAAM,KAAA;EAC1B,qBAAA,GACE,KAAA,EAAO,qBAAA,CAAsB,EAAA,EAAI,KAAA,MAC9B,sBAAA,CAAuB,kBAAA,CAAmB,KAAA,GAAQ,KAAA;EACvD,gBAAA,MACK,IAAA,EAAM,gBAAA,CAAiB,KAAA,MACvB,sBAAA,CAAuB,kBAAA,CAAmB,KAAA,GAAQ,KAAA;AAAA;AAAA,KAG7C,sBAAA,eAAqC,iBAAA;EAC/C,UAAA,GAAa,OAAA,EAAS,uBAAA,CAAwB,KAAA,MAAW,OAAA;EACzD,aAAA,GAAgB,OAAA,EAAS,uBAAA,CAAwB,KAAA,MAAW,OAAA;AAAA;AAAA,KAGlD,6BAAA,eACI,iBAAA;EAEd,OAAA;IACE,WAAA,EAAa,sBAAA,CAAuB,KAAA;EAAA;AAAA;AAAA,KAInC,yBAAA,eAAwC,iBAAA,mBACrC,YAAA,CAAa,KAAA;EAEb,IAAA,GAAO,YAAA,CAAa,KAAA;AAAA;EAGpB,IAAA,EAAM,YAAA,CAAa,KAAA;AAAA;AAAA,KAGf,4BAAA,eACI,iBAAA,aACZ,6BAAA,CAA8B,KAAA,IAAS,yBAAA,CAA0B,KAAA;AAAA,KAEzD,gCAAA,kCAEI,iBAAA;EAEd,IAAA,EAAM,kBAAA,CAAmB,KAAA;EACzB,SAAA,EAAW,0BAAA,CAA2B,EAAA,EAAI,KAAA;AAAA;AAAA,KAGhC,qBAAA,kCAEI,iBAAA;EAEd,aAAA,QAAqB,0BAAA,CAA2B,EAAA,EAAI,KAAA;AAAA;AAAA,iBAQtC,sBAAA,eACA,iBAAA,WACd,KAAA,EAAO,KAAA,GAAQ,gBAAA,CAAiB,KAAA;AAAA,iBAClB,sBAAA,wCAEA,iBAAA,WACd,EAAA,EAAI,EAAA,EAAI,KAAA,EAAO,KAAA,GAAQ,gBAAA,CAAiB,KAAA,EAAO,EAAA;AAAA,iBA0GjC,wBAAA,uBACQ,MAAA,SAAe,iBAAA,YAErC,OAAA,EAAS,OAAA,kBAEI,OAAA,YAAmB,gBAAA,CAAiB,OAAA,CAAQ,EAAA,GAAK,EAAA"}
package/dist/index.mjs CHANGED
@@ -1,9 +1,20 @@
1
1
  import { convexQuery } from "@convex-dev/react-query";
2
- import { useSuspenseQuery } from "@tanstack/react-query";
2
+ import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
3
+ import { getFunctionName } from "convex/server";
3
4
  //#region src/index.ts
4
- function createConvexRouteQuery(query) {
5
+ const routeDataKeyPrefix = "__convexRouteQuery:";
6
+ function createConvexRouteQuery(idOrQuery, maybeQuery) {
7
+ const query = maybeQuery ?? idOrQuery;
8
+ const id = typeof idOrQuery === "string" ? idOrQuery : getFunctionName(idOrQuery);
9
+ const loaderDataKey = `${routeDataKeyPrefix}${id}`;
5
10
  const createOptions = convexQuery;
6
11
  const options = (...args) => createOptions(query, ...args);
12
+ const createLoaderData = (args) => Object.fromEntries([[loaderDataKey, args]]);
13
+ const getRouteArgs = (routeContext, args) => args.length > 0 ? args[0] : "deps" in routeContext && routeContext.deps !== void 0 ? routeContext.deps : {};
14
+ const getLoaderDataArgs = (loaderData) => {
15
+ if (typeof loaderData !== "object" || loaderData === null || !(loaderDataKey in loaderData)) throw new Error(`Missing convex-route-query loader data for "${String(id)}". Return the result of prefetchRoute(...) from this route's loader.`);
16
+ return loaderData[loaderDataKey];
17
+ };
7
18
  return {
8
19
  options,
9
20
  fetchQuery(queryClient, ...args) {
@@ -12,12 +23,37 @@ function createConvexRouteQuery(query) {
12
23
  prefetchQuery(queryClient, ...args) {
13
24
  return queryClient.prefetchQuery(options(...args));
14
25
  },
26
+ async fetchRoute(routeContext, ...args) {
27
+ const queryArgs = getRouteArgs(routeContext, args);
28
+ return {
29
+ data: await routeContext.context.queryClient.fetchQuery(options(...[queryArgs])),
30
+ routeData: createLoaderData(queryArgs)
31
+ };
32
+ },
33
+ async prefetchRoute(routeContext, ...args) {
34
+ const queryArgs = getRouteArgs(routeContext, args);
35
+ await routeContext.context.queryClient.prefetchQuery(options(...[queryArgs]));
36
+ return createLoaderData(queryArgs);
37
+ },
38
+ useQuery(...args) {
39
+ const [queryArgs, queryOptions] = args;
40
+ return useQuery({
41
+ ...queryOptions,
42
+ ...options(...[queryArgs])
43
+ });
44
+ },
45
+ useSuspenseRouteQuery(route) {
46
+ return useSuspenseQuery(options(...[getLoaderDataArgs(route.useLoaderData())]));
47
+ },
15
48
  useSuspenseQuery(...args) {
16
49
  return useSuspenseQuery(options(...args));
17
50
  }
18
51
  };
19
52
  }
53
+ function createConvexRouteQueries(queries) {
54
+ return Object.fromEntries(Object.entries(queries).map(([id, query]) => [id, createConvexRouteQuery(id, query)]));
55
+ }
20
56
  //#endregion
21
- export { createConvexRouteQuery };
57
+ export { createConvexRouteQueries, createConvexRouteQuery };
22
58
 
23
59
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["useTanStackSuspenseQuery"],"sources":["../src/index.ts"],"sourcesContent":["import { convexQuery } from \"@convex-dev/react-query\";\nimport {\n useSuspenseQuery as useTanStackSuspenseQuery,\n type UseSuspenseQueryResult,\n} from \"@tanstack/react-query\";\nimport type {\n FunctionArgs,\n FunctionReference,\n FunctionReturnType,\n OptionalRestArgs,\n} from \"convex/server\";\n\nexport type ConvexRouteQueryOptions<Query extends FunctionReference<\"query\">> =\n {\n queryKey: [\"convexQuery\", Query, FunctionArgs<Query>];\n staleTime: number;\n };\n\nexport type ConvexRouteQuery<Query extends FunctionReference<\"query\">> = {\n options: (...args: OptionalRestArgs<Query>) => ConvexRouteQueryOptions<Query>;\n fetchQuery: (\n queryClient: ConvexRouteQueryClient<Query>,\n ...args: OptionalRestArgs<Query>\n ) => Promise<FunctionReturnType<Query>>;\n prefetchQuery: (\n queryClient: ConvexRouteQueryClient<Query>,\n ...args: OptionalRestArgs<Query>\n ) => Promise<void>;\n useSuspenseQuery: (\n ...args: OptionalRestArgs<Query>\n ) => UseSuspenseQueryResult<FunctionReturnType<Query>, Error>;\n};\n\nexport type ConvexRouteQueryClient<Query extends FunctionReference<\"query\">> = {\n fetchQuery: (options: ConvexRouteQueryOptions<Query>) => Promise<unknown>;\n prefetchQuery: (options: ConvexRouteQueryOptions<Query>) => Promise<void>;\n};\n\ntype CreateConvexQueryOptions<Query extends FunctionReference<\"query\">> = (\n query: Query,\n ...args: OptionalRestArgs<Query>\n) => ConvexRouteQueryOptions<Query>;\n\nexport function createConvexRouteQuery<\n Query extends FunctionReference<\"query\">,\n>(query: Query): ConvexRouteQuery<Query> {\n const createOptions =\n convexQuery as unknown as CreateConvexQueryOptions<Query>;\n const options = (...args: OptionalRestArgs<Query>) =>\n createOptions(query, ...args);\n\n return {\n options,\n fetchQuery(queryClient, ...args) {\n return queryClient.fetchQuery(options(...args)) as Promise<\n FunctionReturnType<Query>\n >;\n },\n prefetchQuery(queryClient, ...args) {\n return queryClient.prefetchQuery(options(...args));\n },\n useSuspenseQuery(...args) {\n return useTanStackSuspenseQuery(options(...args));\n },\n };\n}\n"],"mappings":";;;AA2CA,SAAgB,uBAEd,OAAuC;CACvC,MAAM,gBACJ;CACF,MAAM,WAAW,GAAG,SAClB,cAAc,OAAO,GAAG,IAAI;CAE9B,OAAO;EACL;EACA,WAAW,aAAa,GAAG,MAAM;GAC/B,OAAO,YAAY,WAAW,QAAQ,GAAG,IAAI,CAAC;EAGhD;EACA,cAAc,aAAa,GAAG,MAAM;GAClC,OAAO,YAAY,cAAc,QAAQ,GAAG,IAAI,CAAC;EACnD;EACA,iBAAiB,GAAG,MAAM;GACxB,OAAOA,iBAAyB,QAAQ,GAAG,IAAI,CAAC;EAClD;CACF;AACF"}
1
+ {"version":3,"file":"index.mjs","names":["routeArgs","useTanStackQuery","useTanStackSuspenseQuery"],"sources":["../src/index.ts"],"sourcesContent":["import { convexQuery } from \"@convex-dev/react-query\";\nimport {\n useQuery as useTanStackQuery,\n useSuspenseQuery as useTanStackSuspenseQuery,\n type UseQueryOptions,\n type UseQueryResult,\n type UseSuspenseQueryResult,\n} from \"@tanstack/react-query\";\nimport {\n getFunctionName,\n type ArgsAndOptions,\n type FunctionArgs,\n type FunctionReference,\n type FunctionReturnType,\n type OptionalRestArgs,\n} from \"convex/server\";\n\nconst routeDataKeyPrefix = \"__convexRouteQuery:\";\n\nexport type ConvexRouteQueryLoaderKey<Id extends string> =\n `${typeof routeDataKeyPrefix}${Id}`;\n\nexport type ConvexRouteQueryLoaderData<\n Id extends string,\n Query extends FunctionReference<\"query\">,\n> = Record<ConvexRouteQueryLoaderKey<Id>, FunctionArgs<Query>>;\n\nexport type ConvexRouteQueryOptions<Query extends FunctionReference<\"query\">> =\n {\n queryKey: [\"convexQuery\", Query, FunctionArgs<Query>];\n staleTime: number;\n };\n\nexport type ConvexRouteUseQueryOptions<\n Query extends FunctionReference<\"query\">,\n Data = FunctionReturnType<Query>,\n> = Omit<\n UseQueryOptions<\n FunctionReturnType<Query>,\n Error,\n Data,\n ConvexRouteQueryOptions<Query>[\"queryKey\"]\n >,\n \"queryKey\" | \"queryFn\" | \"staleTime\"\n>;\n\nexport type ConvexRouteQuery<\n Query extends FunctionReference<\"query\">,\n Id extends string = string,\n> = {\n options: (...args: OptionalRestArgs<Query>) => ConvexRouteQueryOptions<Query>;\n fetchQuery: (\n queryClient: ConvexRouteQueryClient<Query>,\n ...args: OptionalRestArgs<Query>\n ) => Promise<FunctionReturnType<Query>>;\n prefetchQuery: (\n queryClient: ConvexRouteQueryClient<Query>,\n ...args: OptionalRestArgs<Query>\n ) => Promise<void>;\n fetchRoute: {\n (\n routeContext: ConvexRouteQueryRouteContext<Query>,\n ): Promise<ConvexRouteQueryFetchRouteResult<Id, Query>>;\n (\n routeContext: ConvexRouteQueryClientContext<Query>,\n ...args: OptionalRestArgs<Query>\n ): Promise<ConvexRouteQueryFetchRouteResult<Id, Query>>;\n };\n prefetchRoute: {\n (\n routeContext: ConvexRouteQueryRouteContext<Query>,\n ): Promise<ConvexRouteQueryLoaderData<Id, Query>>;\n (\n routeContext: ConvexRouteQueryClientContext<Query>,\n ...args: OptionalRestArgs<Query>\n ): Promise<ConvexRouteQueryLoaderData<Id, Query>>;\n };\n useQuery: <Data = FunctionReturnType<Query>>(\n ...args: ArgsAndOptions<Query, ConvexRouteUseQueryOptions<Query, Data>>\n ) => UseQueryResult<Data, Error>;\n useSuspenseRouteQuery: (\n route: ConvexRouteQueryRoute<Id, Query>,\n ) => UseSuspenseQueryResult<FunctionReturnType<Query>, Error>;\n useSuspenseQuery: (\n ...args: OptionalRestArgs<Query>\n ) => UseSuspenseQueryResult<FunctionReturnType<Query>, Error>;\n};\n\nexport type ConvexRouteQueryClient<Query extends FunctionReference<\"query\">> = {\n fetchQuery: (options: ConvexRouteQueryOptions<Query>) => Promise<unknown>;\n prefetchQuery: (options: ConvexRouteQueryOptions<Query>) => Promise<void>;\n};\n\nexport type ConvexRouteQueryClientContext<\n Query extends FunctionReference<\"query\">,\n> = {\n context: {\n queryClient: ConvexRouteQueryClient<Query>;\n };\n};\n\ntype ConvexRouteQueryRouteDeps<Query extends FunctionReference<\"query\">> =\n keyof FunctionArgs<Query> extends never\n ? {\n deps?: FunctionArgs<Query>;\n }\n : {\n deps: FunctionArgs<Query>;\n };\n\nexport type ConvexRouteQueryRouteContext<\n Query extends FunctionReference<\"query\">,\n> = ConvexRouteQueryClientContext<Query> & ConvexRouteQueryRouteDeps<Query>;\n\nexport type ConvexRouteQueryFetchRouteResult<\n Id extends string,\n Query extends FunctionReference<\"query\">,\n> = {\n data: FunctionReturnType<Query>;\n routeData: ConvexRouteQueryLoaderData<Id, Query>;\n};\n\nexport type ConvexRouteQueryRoute<\n Id extends string,\n Query extends FunctionReference<\"query\">,\n> = {\n useLoaderData: () => ConvexRouteQueryLoaderData<Id, Query>;\n};\n\ntype CreateConvexQueryOptions<Query extends FunctionReference<\"query\">> = (\n query: Query,\n ...args: OptionalRestArgs<Query>\n) => ConvexRouteQueryOptions<Query>;\n\nexport function createConvexRouteQuery<\n Query extends FunctionReference<\"query\">,\n>(query: Query): ConvexRouteQuery<Query>;\nexport function createConvexRouteQuery<\n const Id extends string,\n Query extends FunctionReference<\"query\">,\n>(id: Id, query: Query): ConvexRouteQuery<Query, Id>;\nexport function createConvexRouteQuery<\n const Id extends string,\n Query extends FunctionReference<\"query\">,\n>(\n idOrQuery: Id | Query,\n maybeQuery?: Query,\n): ConvexRouteQuery<Query, Id | string> {\n const query = (maybeQuery ?? idOrQuery) as Query;\n const id =\n typeof idOrQuery === \"string\"\n ? idOrQuery\n : getFunctionName(idOrQuery as Query);\n const loaderDataKey =\n `${routeDataKeyPrefix}${id}` as ConvexRouteQueryLoaderKey<Id | string>;\n const createOptions =\n convexQuery as unknown as CreateConvexQueryOptions<Query>;\n const options = (...args: OptionalRestArgs<Query>) =>\n createOptions(query, ...args);\n const createLoaderData = (args: FunctionArgs<Query>) =>\n Object.fromEntries([\n [loaderDataKey, args],\n ]) as unknown as ConvexRouteQueryLoaderData<Id | string, Query>;\n const getRouteArgs = (\n routeContext:\n | ConvexRouteQueryClientContext<Query>\n | ConvexRouteQueryRouteContext<Query>,\n args: OptionalRestArgs<Query>,\n ) =>\n (args.length > 0\n ? args[0]\n : \"deps\" in routeContext && routeContext.deps !== undefined\n ? routeContext.deps\n : {}) as FunctionArgs<Query>;\n const getLoaderDataArgs = (\n loaderData: ConvexRouteQueryLoaderData<Id, Query>,\n ) => {\n if (\n typeof loaderData !== \"object\" ||\n loaderData === null ||\n !(loaderDataKey in loaderData)\n ) {\n throw new Error(\n `Missing convex-route-query loader data for \"${String(id)}\". Return the result of prefetchRoute(...) from this route's loader.`,\n );\n }\n\n return loaderData[\n loaderDataKey as keyof typeof loaderData\n ] as FunctionArgs<Query>;\n };\n\n return {\n options,\n fetchQuery(queryClient, ...args) {\n return queryClient.fetchQuery(options(...args)) as Promise<\n FunctionReturnType<Query>\n >;\n },\n prefetchQuery(queryClient, ...args) {\n return queryClient.prefetchQuery(options(...args));\n },\n async fetchRoute(routeContext, ...args) {\n const routeArgs = args as OptionalRestArgs<Query>;\n const queryArgs = getRouteArgs(routeContext, routeArgs);\n const data = await routeContext.context.queryClient.fetchQuery(\n options(...([queryArgs] as OptionalRestArgs<Query>)),\n );\n\n return {\n data: data as FunctionReturnType<Query>,\n routeData: createLoaderData(queryArgs),\n };\n },\n async prefetchRoute(routeContext, ...args) {\n const routeArgs = args as OptionalRestArgs<Query>;\n const queryArgs = getRouteArgs(routeContext, routeArgs);\n\n await routeContext.context.queryClient.prefetchQuery(\n options(...([queryArgs] as OptionalRestArgs<Query>)),\n );\n\n return createLoaderData(queryArgs);\n },\n useQuery(...args) {\n const [queryArgs, queryOptions] = args;\n\n return useTanStackQuery({\n ...queryOptions,\n ...options(...([queryArgs] as OptionalRestArgs<Query>)),\n });\n },\n useSuspenseRouteQuery(route) {\n const loaderData = route.useLoaderData();\n const queryArgs = getLoaderDataArgs(loaderData);\n\n return useTanStackSuspenseQuery(\n options(...([queryArgs] as OptionalRestArgs<Query>)),\n );\n },\n useSuspenseQuery(...args) {\n return useTanStackSuspenseQuery(options(...args));\n },\n };\n}\n\nexport function createConvexRouteQueries<\n const Queries extends Record<string, FunctionReference<\"query\">>,\n>(\n queries: Queries,\n): {\n [Id in keyof Queries & string]: ConvexRouteQuery<Queries[Id], Id>;\n} {\n return Object.fromEntries(\n Object.entries(queries).map(([id, query]) => [\n id,\n createConvexRouteQuery(id, query),\n ]),\n ) as unknown as {\n [Id in keyof Queries & string]: ConvexRouteQuery<Queries[Id], Id>;\n };\n}\n"],"mappings":";;;;AAiBA,MAAM,qBAAqB;AA4H3B,SAAgB,uBAId,WACA,YACsC;CACtC,MAAM,QAAS,cAAc;CAC7B,MAAM,KACJ,OAAO,cAAc,WACjB,YACA,gBAAgB,SAAkB;CACxC,MAAM,gBACJ,GAAG,qBAAqB;CAC1B,MAAM,gBACJ;CACF,MAAM,WAAW,GAAG,SAClB,cAAc,OAAO,GAAG,IAAI;CAC9B,MAAM,oBAAoB,SACxB,OAAO,YAAY,CACjB,CAAC,eAAe,IAAI,CACtB,CAAC;CACH,MAAM,gBACJ,cAGA,SAEC,KAAK,SAAS,IACX,KAAK,KACL,UAAU,gBAAgB,aAAa,SAAS,KAAA,IAC9C,aAAa,OACb,CAAC;CACT,MAAM,qBACJ,eACG;EACH,IACE,OAAO,eAAe,YACtB,eAAe,QACf,EAAE,iBAAiB,aAEnB,MAAM,IAAI,MACR,+CAA+C,OAAO,EAAE,EAAE,qEAC5D;EAGF,OAAO,WACL;CAEJ;CAEA,OAAO;EACL;EACA,WAAW,aAAa,GAAG,MAAM;GAC/B,OAAO,YAAY,WAAW,QAAQ,GAAG,IAAI,CAAC;EAGhD;EACA,cAAc,aAAa,GAAG,MAAM;GAClC,OAAO,YAAY,cAAc,QAAQ,GAAG,IAAI,CAAC;EACnD;EACA,MAAM,WAAW,cAAc,GAAG,MAAM;GAEtC,MAAM,YAAY,aAAa,cAAcA,IAAS;GAKtD,OAAO;IACL,MAAM,MALW,aAAa,QAAQ,YAAY,WAClD,QAAQ,GAAI,CAAC,SAAS,CAA6B,CACrD;IAIE,WAAW,iBAAiB,SAAS;GACvC;EACF;EACA,MAAM,cAAc,cAAc,GAAG,MAAM;GAEzC,MAAM,YAAY,aAAa,cAAcA,IAAS;GAEtD,MAAM,aAAa,QAAQ,YAAY,cACrC,QAAQ,GAAI,CAAC,SAAS,CAA6B,CACrD;GAEA,OAAO,iBAAiB,SAAS;EACnC;EACA,SAAS,GAAG,MAAM;GAChB,MAAM,CAAC,WAAW,gBAAgB;GAElC,OAAOC,SAAiB;IACtB,GAAG;IACH,GAAG,QAAQ,GAAI,CAAC,SAAS,CAA6B;GACxD,CAAC;EACH;EACA,sBAAsB,OAAO;GAI3B,OAAOC,iBACL,QAAQ,GAAI,CAHI,kBADC,MAAM,cACoB,CAGtB,CAAC,CAA6B,CACrD;EACF;EACA,iBAAiB,GAAG,MAAM;GACxB,OAAOA,iBAAyB,QAAQ,GAAG,IAAI,CAAC;EAClD;CACF;AACF;AAEA,SAAgB,yBAGd,SAGA;CACA,OAAO,OAAO,YACZ,OAAO,QAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,WAAW,CAC3C,IACA,uBAAuB,IAAI,KAAK,CAClC,CAAC,CACH;AAGF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "convex-route-query",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "Type-safe Convex query helpers for TanStack Router loaders and React Query Suspense.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -26,7 +26,8 @@
26
26
  "build": "concurrently --raw --names tsdown \"bun run build:tsdown\"",
27
27
  "build:tsdown": "tsdown",
28
28
  "ci": "bun run ci:test && bun run build && bun run lint:pkg",
29
- "ci:test": "concurrently --raw --names runtime,types,xo \"bun run ci:test:runtime\" \"bun run ci:test:types\" \"bun run ci:test:xo\"",
29
+ "ci:test": "concurrently --raw --names runtime,types,e2e,xo \"bun run ci:test:runtime\" \"bun run ci:test:types\" \"bun run ci:test:e2e\" \"bun run ci:test:xo\"",
30
+ "ci:test:e2e": "bun run test:e2e:tanstack-start",
30
31
  "ci:test:runtime": "vitest run",
31
32
  "ci:test:types": "tsc --noEmit",
32
33
  "ci:test:xo": "xo",
@@ -37,7 +38,8 @@
37
38
  "lint:pkg:publint": "publint",
38
39
  "prepublishOnly": "bun run ci",
39
40
  "release": "bun run build && changeset publish",
40
- "test": "concurrently --raw --names runtime,types,xo \"bun run test:runtime\" \"bun run test:types\" \"bun run test:xo\"",
41
+ "test": "concurrently --raw --names runtime,types,e2e,xo \"bun run test:runtime\" \"bun run test:types\" \"bun run test:e2e:tanstack-start\" \"bun run test:xo\"",
42
+ "test:e2e:tanstack-start": "tsc -p e2e/tanstack-start/tsconfig.json --noEmit",
41
43
  "test:runtime": "vitest run",
42
44
  "test:types": "tsc --noEmit",
43
45
  "test:xo": "xo",
@@ -63,7 +65,8 @@
63
65
  "url": "https://github.com/ludicroushq/convex-route-query/issues"
64
66
  },
65
67
  "publishConfig": {
66
- "access": "public"
68
+ "access": "public",
69
+ "provenance": true
67
70
  },
68
71
  "engines": {
69
72
  "node": ">=20.0.0"
@@ -80,7 +83,11 @@
80
83
  "@changesets/cli": "^2.31.0",
81
84
  "@convex-dev/react-query": "^0.1.0",
82
85
  "@tanstack/react-query": "^5.101.0",
86
+ "@tanstack/react-router": "^1.170.17",
87
+ "@tanstack/react-start": "^1.168.27",
83
88
  "@types/react": "^19.2.7",
89
+ "@types/react-dom": "^19.2.3",
90
+ "@vitejs/plugin-react": "^6.0.3",
84
91
  "concurrently": "^10.0.3",
85
92
  "convex": "^1.41.0",
86
93
  "expect-type": "^1.3.0",
@@ -88,9 +95,12 @@
88
95
  "prettier": "^3.8.4",
89
96
  "publint": "^0.3.21",
90
97
  "react": "^19.2.7",
98
+ "react-dom": "^19.2.7",
91
99
  "tsdown": "^0.22.2",
92
100
  "typescript": "^6.0.3",
101
+ "vite": "^8.1.4",
93
102
  "vitest": "^4.1.8",
94
- "xo": "^2.0.2"
103
+ "xo": "^2.0.2",
104
+ "zod": "^4.4.3"
95
105
  }
96
106
  }