@questpie/tanstack-query 2.0.0 → 3.0.1
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 +97 -95
- package/dist/index.d.mts +62 -38
- package/dist/index.mjs +139 -29
- package/package.json +26 -20
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# @questpie/tanstack-query
|
|
2
2
|
|
|
3
|
-
Type-safe TanStack Query option builders for QUESTPIE — collections, globals,
|
|
3
|
+
Type-safe TanStack Query option builders for QUESTPIE — collections, globals, app routes, and realtime streaming.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Query Options Factory** — Pre-built `queryOptions()` and `mutationOptions()` for all CRUD operations
|
|
8
|
-
- **
|
|
8
|
+
- **Route Query Options** — Typed `query()` / `mutation()` builders for app routes with nested path support
|
|
9
9
|
- **Realtime Streaming** — `streamedQuery`-based options for SSE live updates on collections and globals
|
|
10
10
|
- **Batch Operations** — `updateMany` and `deleteMany` mutation builders
|
|
11
11
|
- **SSR Ready** — Prefetch data on the server, hydrate on the client
|
|
12
|
-
- **Full Type Inference** — Types flow from your
|
|
12
|
+
- **Full Type Inference** — Types flow from your app schema through to query results
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
@@ -24,43 +24,45 @@ bun add @questpie/tanstack-query questpie @tanstack/react-query
|
|
|
24
24
|
```ts
|
|
25
25
|
import { createClient } from "questpie/client";
|
|
26
26
|
import { createQuestpieQueryOptions } from "@questpie/tanstack-query";
|
|
27
|
-
import type {
|
|
27
|
+
import type { AppConfig } from "#questpie";
|
|
28
28
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
const appClient = createClient<AppConfig>({
|
|
30
|
+
baseURL: "http://localhost:3000",
|
|
31
|
+
basePath: "/api",
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
export const
|
|
34
|
+
export const appQueries = createQuestpieQueryOptions(appClient);
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
### 2. Use in Components
|
|
38
38
|
|
|
39
39
|
```tsx
|
|
40
40
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
41
|
-
import {
|
|
41
|
+
import { appQueries } from "@/lib/queries";
|
|
42
42
|
|
|
43
43
|
function PostsList() {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
44
|
+
const { data } = useQuery(appQueries.collections.posts.find({ limit: 10 }));
|
|
45
|
+
|
|
46
|
+
const queryClient = useQueryClient();
|
|
47
|
+
const createPost = useMutation({
|
|
48
|
+
...appQueries.collections.posts.create(),
|
|
49
|
+
onSuccess: () => {
|
|
50
|
+
queryClient.invalidateQueries({
|
|
51
|
+
queryKey: appQueries.collections.posts.key(),
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div>
|
|
58
|
+
{data?.docs.map((post) => (
|
|
59
|
+
<div key={post.id}>{post.title}</div>
|
|
60
|
+
))}
|
|
61
|
+
<button onClick={() => createPost.mutate({ title: "New Post" })}>
|
|
62
|
+
Create
|
|
63
|
+
</button>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
64
66
|
}
|
|
65
67
|
```
|
|
66
68
|
|
|
@@ -68,79 +70,77 @@ function PostsList() {
|
|
|
68
70
|
|
|
69
71
|
```ts
|
|
70
72
|
// Find many (paginated)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
})
|
|
73
|
+
appQueries.collections.posts.find({
|
|
74
|
+
where: { published: { eq: true } },
|
|
75
|
+
orderBy: { createdAt: "desc" },
|
|
76
|
+
limit: 10,
|
|
77
|
+
offset: 0,
|
|
78
|
+
with: { author: true },
|
|
79
|
+
});
|
|
78
80
|
|
|
79
81
|
// Find one
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
})
|
|
82
|
+
appQueries.collections.posts.findOne({
|
|
83
|
+
where: { id: "post-id" },
|
|
84
|
+
with: { author: true },
|
|
85
|
+
});
|
|
84
86
|
|
|
85
87
|
// Count
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
})
|
|
88
|
+
appQueries.collections.posts.count({
|
|
89
|
+
where: { published: { eq: true } },
|
|
90
|
+
});
|
|
89
91
|
|
|
90
92
|
// Create (mutation)
|
|
91
|
-
|
|
93
|
+
appQueries.collections.posts.create();
|
|
92
94
|
|
|
93
95
|
// Update (mutation)
|
|
94
|
-
|
|
96
|
+
appQueries.collections.posts.update();
|
|
95
97
|
|
|
96
98
|
// Delete (mutation)
|
|
97
|
-
|
|
99
|
+
appQueries.collections.posts.delete();
|
|
98
100
|
|
|
99
101
|
// Update many (mutation)
|
|
100
|
-
|
|
102
|
+
appQueries.collections.posts.updateMany();
|
|
101
103
|
|
|
102
104
|
// Delete many (mutation)
|
|
103
|
-
|
|
105
|
+
appQueries.collections.posts.deleteMany();
|
|
104
106
|
|
|
105
107
|
// Restore soft-deleted (mutation)
|
|
106
|
-
|
|
108
|
+
appQueries.collections.posts.restore();
|
|
107
109
|
|
|
108
110
|
// Query key for invalidation
|
|
109
|
-
|
|
111
|
+
appQueries.collections.posts.key();
|
|
110
112
|
```
|
|
111
113
|
|
|
112
114
|
## Globals
|
|
113
115
|
|
|
114
116
|
```ts
|
|
115
117
|
// Get global value
|
|
116
|
-
|
|
118
|
+
appQueries.globals.siteSettings.get();
|
|
117
119
|
|
|
118
120
|
// Update global (mutation)
|
|
119
|
-
|
|
121
|
+
appQueries.globals.siteSettings.update();
|
|
120
122
|
|
|
121
123
|
// Query key
|
|
122
|
-
|
|
124
|
+
appQueries.globals.siteSettings.key();
|
|
123
125
|
```
|
|
124
126
|
|
|
125
|
-
##
|
|
127
|
+
## Routes
|
|
126
128
|
|
|
127
|
-
Full type-safe query/mutation options for
|
|
129
|
+
Full type-safe query/mutation options for app routes:
|
|
128
130
|
|
|
129
131
|
```ts
|
|
130
|
-
// Query options from
|
|
132
|
+
// Query options from route
|
|
131
133
|
const { data } = useQuery(
|
|
132
|
-
|
|
134
|
+
appQueries.routes.dashboard.getStats.query({ period: "week" }),
|
|
133
135
|
);
|
|
134
136
|
|
|
135
|
-
// Mutation options from
|
|
136
|
-
const publish = useMutation(
|
|
137
|
-
cmsQueries.rpc.posts.publish.mutation()
|
|
138
|
-
);
|
|
137
|
+
// Mutation options from route
|
|
138
|
+
const publish = useMutation(appQueries.routes.posts.publish.mutation());
|
|
139
139
|
publish.mutate({ id: "post_123" });
|
|
140
140
|
|
|
141
141
|
// Query key for invalidation/prefetch
|
|
142
142
|
queryClient.invalidateQueries({
|
|
143
|
-
|
|
143
|
+
queryKey: appQueries.routes.dashboard.getStats.key({ period: "week" }),
|
|
144
144
|
});
|
|
145
145
|
```
|
|
146
146
|
|
|
@@ -151,17 +151,17 @@ Collection queries support SSE-based live updates via `streamedQuery`:
|
|
|
151
151
|
```ts
|
|
152
152
|
// Enable realtime on a query
|
|
153
153
|
const { data } = useQuery(
|
|
154
|
-
|
|
155
|
-
{ limit: 10 },
|
|
156
|
-
{ realtime: true }
|
|
157
|
-
)
|
|
154
|
+
appQueries.collections.posts.find({ limit: 10 }, { realtime: true }),
|
|
158
155
|
);
|
|
159
156
|
```
|
|
160
157
|
|
|
161
158
|
Topic helpers for manual subscription:
|
|
162
159
|
|
|
163
160
|
```ts
|
|
164
|
-
import {
|
|
161
|
+
import {
|
|
162
|
+
buildCollectionTopic,
|
|
163
|
+
buildGlobalTopic,
|
|
164
|
+
} from "@questpie/tanstack-query";
|
|
165
165
|
|
|
166
166
|
const postsTopic = buildCollectionTopic("posts");
|
|
167
167
|
const settingsTopic = buildGlobalTopic("siteSettings");
|
|
@@ -174,26 +174,28 @@ const settingsTopic = buildGlobalTopic("siteSettings");
|
|
|
174
174
|
```tsx
|
|
175
175
|
import { createFileRoute } from "@tanstack/react-router";
|
|
176
176
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
|
177
|
-
import {
|
|
177
|
+
import { appQueries } from "@/lib/queries";
|
|
178
178
|
|
|
179
179
|
export const Route = createFileRoute("/posts")({
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
180
|
+
loader: async ({ context }) => {
|
|
181
|
+
await context.queryClient.ensureQueryData(
|
|
182
|
+
appQueries.collections.posts.find({ limit: 10 }),
|
|
183
|
+
);
|
|
184
|
+
},
|
|
185
|
+
component: PostsPage,
|
|
186
186
|
});
|
|
187
187
|
|
|
188
188
|
function PostsPage() {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
189
|
+
const { data } = useSuspenseQuery(
|
|
190
|
+
appQueries.collections.posts.find({ limit: 10 }),
|
|
191
|
+
);
|
|
192
|
+
return (
|
|
193
|
+
<ul>
|
|
194
|
+
{data.docs.map((post) => (
|
|
195
|
+
<li key={post.id}>{post.title}</li>
|
|
196
|
+
))}
|
|
197
|
+
</ul>
|
|
198
|
+
);
|
|
197
199
|
}
|
|
198
200
|
```
|
|
199
201
|
|
|
@@ -202,18 +204,18 @@ function PostsPage() {
|
|
|
202
204
|
```tsx
|
|
203
205
|
import { HydrationBoundary, dehydrate } from "@tanstack/react-query";
|
|
204
206
|
import { getQueryClient } from "@/lib/query-client";
|
|
205
|
-
import {
|
|
207
|
+
import { appQueries } from "@/lib/queries";
|
|
206
208
|
|
|
207
209
|
export default async function PostsPage() {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
210
|
+
const queryClient = getQueryClient();
|
|
211
|
+
await queryClient.prefetchQuery(
|
|
212
|
+
appQueries.collections.posts.find({ limit: 10 }),
|
|
213
|
+
);
|
|
214
|
+
return (
|
|
215
|
+
<HydrationBoundary state={dehydrate(queryClient)}>
|
|
216
|
+
<PostsList />
|
|
217
|
+
</HydrationBoundary>
|
|
218
|
+
);
|
|
217
219
|
}
|
|
218
220
|
```
|
|
219
221
|
|
|
@@ -228,9 +230,9 @@ export default async function PostsPage() {
|
|
|
228
230
|
// Globals
|
|
229
231
|
["globals", globalName, "get"]
|
|
230
232
|
|
|
231
|
-
//
|
|
232
|
-
["
|
|
233
|
-
["
|
|
233
|
+
// Routes
|
|
234
|
+
["routes", ...segments, "query", input]
|
|
235
|
+
["routes", ...segments, "mutation"]
|
|
234
236
|
```
|
|
235
237
|
|
|
236
238
|
## Documentation
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { DefaultError, QueryKey, UseMutationOptions, UseQueryOptions } from "@tanstack/react-query";
|
|
2
|
-
import { QuestpieClient, RealtimeAPI, TopicConfig, buildCollectionTopic, buildGlobalTopic } from "questpie/client";
|
|
3
|
-
import { Questpie } from "questpie";
|
|
2
|
+
import { QuestpieApp, QuestpieClient, RealtimeAPI, TopicConfig, buildCollectionTopic, buildGlobalTopic } from "questpie/client";
|
|
4
3
|
|
|
5
4
|
//#region src/index.d.ts
|
|
6
5
|
type QuestpieQueryErrorMap = (error: unknown) => unknown;
|
|
@@ -8,6 +7,7 @@ type QuestpieQueryOptionsConfig = {
|
|
|
8
7
|
keyPrefix?: QueryKey;
|
|
9
8
|
errorMap?: QuestpieQueryErrorMap;
|
|
10
9
|
locale?: string;
|
|
10
|
+
stage?: string;
|
|
11
11
|
};
|
|
12
12
|
type AnyAsyncFn = (...args: any[]) => Promise<any>;
|
|
13
13
|
type QueryData<TFn extends AnyAsyncFn> = Awaited<ReturnType<TFn>>;
|
|
@@ -18,40 +18,55 @@ type KeyBuilder<TFn extends AnyAsyncFn> = HasArgs<TFn> extends false ? () => Que
|
|
|
18
18
|
type MutationVariables<TFn extends AnyAsyncFn> = HasArgs<TFn> extends false ? void : undefined extends FirstArg<TFn> ? FirstArg<TFn> | void : FirstArg<TFn>;
|
|
19
19
|
type MutationBuilder<TVariables, TData> = () => UseMutationOptions<TData, DefaultError, TVariables>;
|
|
20
20
|
/** Extract collection keys from QuestpieClient */
|
|
21
|
-
type CollectionKeys<
|
|
21
|
+
type CollectionKeys<TApp extends QuestpieApp> = Extract<keyof QuestpieClient<TApp>["collections"], string>;
|
|
22
22
|
/** Extract global keys from QuestpieClient */
|
|
23
|
-
type GlobalKeys<
|
|
24
|
-
type CollectionFind<
|
|
25
|
-
type CollectionCount<
|
|
26
|
-
type CollectionFindOne<
|
|
27
|
-
type CollectionCreate<
|
|
28
|
-
type CollectionUpdate<
|
|
29
|
-
type CollectionDelete<
|
|
30
|
-
type CollectionRestore<
|
|
31
|
-
type
|
|
23
|
+
type GlobalKeys<TApp extends QuestpieApp> = Extract<keyof QuestpieClient<TApp>["globals"], string>;
|
|
24
|
+
type CollectionFind<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["find"];
|
|
25
|
+
type CollectionCount<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["count"];
|
|
26
|
+
type CollectionFindOne<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["findOne"];
|
|
27
|
+
type CollectionCreate<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["create"];
|
|
28
|
+
type CollectionUpdate<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["update"];
|
|
29
|
+
type CollectionDelete<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["delete"];
|
|
30
|
+
type CollectionRestore<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["restore"];
|
|
31
|
+
type CollectionFindVersions<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["findVersions"];
|
|
32
|
+
type CollectionRevertToVersion<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["revertToVersion"];
|
|
33
|
+
type CollectionTransitionStage<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = QuestpieClient<TApp>["collections"][K$1]["transitionStage"];
|
|
34
|
+
type GlobalGet<TApp extends QuestpieApp, K$1 extends GlobalKeys<TApp>> = QuestpieClient<TApp>["globals"][K$1] extends {
|
|
32
35
|
get: infer TGet;
|
|
33
36
|
} ? TGet extends AnyAsyncFn ? TGet : never : never;
|
|
34
|
-
type GlobalUpdate<
|
|
37
|
+
type GlobalUpdate<TApp extends QuestpieApp, K$1 extends GlobalKeys<TApp>> = QuestpieClient<TApp>["globals"][K$1] extends {
|
|
35
38
|
update: infer TUpdate;
|
|
36
39
|
} ? TUpdate extends AnyAsyncFn ? TUpdate : never : never;
|
|
37
|
-
type
|
|
40
|
+
type GlobalFindVersions<TApp extends QuestpieApp, K$1 extends GlobalKeys<TApp>> = QuestpieClient<TApp>["globals"][K$1] extends {
|
|
41
|
+
findVersions: infer TFindVersions;
|
|
42
|
+
} ? TFindVersions extends AnyAsyncFn ? TFindVersions : never : never;
|
|
43
|
+
type GlobalRevertToVersion<TApp extends QuestpieApp, K$1 extends GlobalKeys<TApp>> = QuestpieClient<TApp>["globals"][K$1] extends {
|
|
44
|
+
revertToVersion: infer TRevert;
|
|
45
|
+
} ? TRevert extends AnyAsyncFn ? TRevert : never : never;
|
|
46
|
+
type GlobalTransitionStage<TApp extends QuestpieApp, K$1 extends GlobalKeys<TApp>> = QuestpieClient<TApp>["globals"][K$1] extends {
|
|
47
|
+
transitionStage: infer TTransition;
|
|
48
|
+
} ? TTransition extends AnyAsyncFn ? TTransition : never : never;
|
|
49
|
+
type RouteLeafQueryOptionsAPI<TFn extends AnyAsyncFn> = {
|
|
38
50
|
query: QueryBuilder<TFn>;
|
|
39
51
|
mutation: MutationBuilder<MutationVariables<TFn>, QueryData<TFn>>;
|
|
40
52
|
key: KeyBuilder<TFn>;
|
|
41
53
|
};
|
|
42
|
-
type
|
|
43
|
-
type CollectionQueryOptionsAPI<
|
|
44
|
-
find: QueryBuilder<CollectionFind<
|
|
45
|
-
count: QueryBuilder<CollectionCount<
|
|
46
|
-
findOne: QueryBuilder<CollectionFindOne<
|
|
47
|
-
create: MutationBuilder<FirstArg<CollectionCreate<
|
|
48
|
-
update: MutationBuilder<FirstArg<CollectionUpdate<
|
|
49
|
-
delete: MutationBuilder<FirstArg<CollectionDelete<
|
|
50
|
-
restore: MutationBuilder<FirstArg<CollectionRestore<
|
|
54
|
+
type RoutesQueryOptionsAPI<TNode> = TNode extends AnyAsyncFn ? RouteLeafQueryOptionsAPI<TNode> : TNode extends Record<string, any> ? { [K in keyof TNode]: RoutesQueryOptionsAPI<TNode[K]> } : never;
|
|
55
|
+
type CollectionQueryOptionsAPI<TApp extends QuestpieApp, K$1 extends CollectionKeys<TApp>> = {
|
|
56
|
+
find: QueryBuilder<CollectionFind<TApp, K$1>>;
|
|
57
|
+
count: QueryBuilder<CollectionCount<TApp, K$1>>;
|
|
58
|
+
findOne: QueryBuilder<CollectionFindOne<TApp, K$1>>;
|
|
59
|
+
create: MutationBuilder<FirstArg<CollectionCreate<TApp, K$1>>, QueryData<CollectionCreate<TApp, K$1>>>;
|
|
60
|
+
update: MutationBuilder<FirstArg<CollectionUpdate<TApp, K$1>>, QueryData<CollectionUpdate<TApp, K$1>>>;
|
|
61
|
+
delete: MutationBuilder<FirstArg<CollectionDelete<TApp, K$1>>, QueryData<CollectionDelete<TApp, K$1>>>;
|
|
62
|
+
restore: MutationBuilder<FirstArg<CollectionRestore<TApp, K$1>>, QueryData<CollectionRestore<TApp, K$1>>>;
|
|
63
|
+
findVersions: QueryBuilder<CollectionFindVersions<TApp, K$1>>;
|
|
64
|
+
revertToVersion: MutationBuilder<FirstArg<CollectionRevertToVersion<TApp, K$1>>, QueryData<CollectionRevertToVersion<TApp, K$1>>>;
|
|
65
|
+
transitionStage: MutationBuilder<FirstArg<CollectionTransitionStage<TApp, K$1>>, QueryData<CollectionTransitionStage<TApp, K$1>>>;
|
|
51
66
|
updateMany: MutationBuilder<{
|
|
52
67
|
where: any;
|
|
53
68
|
data: any;
|
|
54
|
-
}, QueryData<CollectionUpdate<
|
|
69
|
+
}, QueryData<CollectionUpdate<TApp, K$1>>>;
|
|
55
70
|
deleteMany: MutationBuilder<{
|
|
56
71
|
where: any;
|
|
57
72
|
}, {
|
|
@@ -59,17 +74,26 @@ type CollectionQueryOptionsAPI<TCMS extends Questpie<any>, TRPC extends Record<s
|
|
|
59
74
|
count: number;
|
|
60
75
|
}>;
|
|
61
76
|
};
|
|
62
|
-
type GlobalQueryOptionsAPI<
|
|
63
|
-
get: QueryBuilder<GlobalGet<
|
|
77
|
+
type GlobalQueryOptionsAPI<TApp extends QuestpieApp, K$1 extends GlobalKeys<TApp>> = {
|
|
78
|
+
get: QueryBuilder<GlobalGet<TApp, K$1>>;
|
|
64
79
|
update: MutationBuilder<{
|
|
65
|
-
data: Parameters<GlobalUpdate<
|
|
66
|
-
options?: Parameters<GlobalUpdate<
|
|
67
|
-
}, QueryData<GlobalUpdate<
|
|
80
|
+
data: Parameters<GlobalUpdate<TApp, K$1>>[0];
|
|
81
|
+
options?: Parameters<GlobalUpdate<TApp, K$1>>[1];
|
|
82
|
+
}, QueryData<GlobalUpdate<TApp, K$1>>>;
|
|
83
|
+
findVersions: QueryBuilder<GlobalFindVersions<TApp, K$1>>;
|
|
84
|
+
revertToVersion: MutationBuilder<{
|
|
85
|
+
params: Parameters<GlobalRevertToVersion<TApp, K$1>>[0];
|
|
86
|
+
options?: Parameters<GlobalRevertToVersion<TApp, K$1>>[1];
|
|
87
|
+
}, QueryData<GlobalRevertToVersion<TApp, K$1>>>;
|
|
88
|
+
transitionStage: MutationBuilder<{
|
|
89
|
+
params: Parameters<GlobalTransitionStage<TApp, K$1>>[0];
|
|
90
|
+
options?: Parameters<GlobalTransitionStage<TApp, K$1>>[1];
|
|
91
|
+
}, QueryData<GlobalTransitionStage<TApp, K$1>>>;
|
|
68
92
|
};
|
|
69
|
-
type QuestpieQueryOptionsProxy<
|
|
70
|
-
collections: { [K in CollectionKeys<
|
|
71
|
-
globals: { [K in GlobalKeys<
|
|
72
|
-
|
|
93
|
+
type QuestpieQueryOptionsProxy<TApp extends QuestpieApp = QuestpieApp> = {
|
|
94
|
+
collections: { [K in CollectionKeys<TApp>]: CollectionQueryOptionsAPI<TApp, K> };
|
|
95
|
+
globals: { [K in GlobalKeys<TApp>]: GlobalQueryOptionsAPI<TApp, K> };
|
|
96
|
+
routes: RoutesQueryOptionsAPI<QuestpieClient<TApp>["routes"]>;
|
|
73
97
|
custom: {
|
|
74
98
|
query: <TData>(config: {
|
|
75
99
|
key: QueryKey;
|
|
@@ -89,9 +113,9 @@ type QuestpieQueryOptionsProxy<TCMS extends Questpie<any>, TRPC extends Record<s
|
|
|
89
113
|
* ```ts
|
|
90
114
|
* import { createQuestpieQueryOptions } from "@questpie/tanstack-query"
|
|
91
115
|
* import { createClient } from "questpie/client"
|
|
92
|
-
* import type {
|
|
116
|
+
* import type { App, AppRpc } from "@/app"
|
|
93
117
|
*
|
|
94
|
-
* const client = createClient<
|
|
118
|
+
* const client = createClient<App, AppRpc>({ baseURL: "http://localhost:3000" })
|
|
95
119
|
* const cmsQueries = createQuestpieQueryOptions(client)
|
|
96
120
|
*
|
|
97
121
|
* // Use with useQuery
|
|
@@ -100,10 +124,10 @@ type QuestpieQueryOptionsProxy<TCMS extends Questpie<any>, TRPC extends Record<s
|
|
|
100
124
|
* // Use with useMutation
|
|
101
125
|
* const mutation = useMutation(cmsQueries.collections.posts.create())
|
|
102
126
|
*
|
|
103
|
-
* // Use with
|
|
104
|
-
* const stats = useQuery(cmsQueries.
|
|
127
|
+
* // Use with routes
|
|
128
|
+
* const stats = useQuery(cmsQueries.routes.dashboard.getStats.query({ period: "week" }))
|
|
105
129
|
* ```
|
|
106
130
|
*/
|
|
107
|
-
declare function createQuestpieQueryOptions<
|
|
131
|
+
declare function createQuestpieQueryOptions<TApp extends QuestpieApp = QuestpieApp>(client: QuestpieClient<TApp>, config?: QuestpieQueryOptionsConfig): QuestpieQueryOptionsProxy<TApp>;
|
|
108
132
|
//#endregion
|
|
109
133
|
export { type DefaultError, type QueryKey, QuestpieQueryErrorMap, QuestpieQueryOptionsConfig, QuestpieQueryOptionsProxy, type RealtimeAPI, type TopicConfig, type UseMutationOptions, type UseQueryOptions, buildCollectionTopic, buildGlobalTopic, createQuestpieQueryOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -45,9 +45,9 @@ const wrapMutationFn = (mutationFn, errorMap) => {
|
|
|
45
45
|
* ```ts
|
|
46
46
|
* import { createQuestpieQueryOptions } from "@questpie/tanstack-query"
|
|
47
47
|
* import { createClient } from "questpie/client"
|
|
48
|
-
* import type {
|
|
48
|
+
* import type { App, AppRpc } from "@/app"
|
|
49
49
|
*
|
|
50
|
-
* const client = createClient<
|
|
50
|
+
* const client = createClient<App, AppRpc>({ baseURL: "http://localhost:3000" })
|
|
51
51
|
* const cmsQueries = createQuestpieQueryOptions(client)
|
|
52
52
|
*
|
|
53
53
|
* // Use with useQuery
|
|
@@ -56,14 +56,15 @@ const wrapMutationFn = (mutationFn, errorMap) => {
|
|
|
56
56
|
* // Use with useMutation
|
|
57
57
|
* const mutation = useMutation(cmsQueries.collections.posts.create())
|
|
58
58
|
*
|
|
59
|
-
* // Use with
|
|
60
|
-
* const stats = useQuery(cmsQueries.
|
|
59
|
+
* // Use with routes
|
|
60
|
+
* const stats = useQuery(cmsQueries.routes.dashboard.getStats.query({ period: "week" }))
|
|
61
61
|
* ```
|
|
62
62
|
*/
|
|
63
63
|
function createQuestpieQueryOptions(client, config = {}) {
|
|
64
64
|
const keyPrefix = config.keyPrefix ?? ["questpie"];
|
|
65
65
|
const errorMap = config.errorMap ?? defaultErrorMap;
|
|
66
66
|
const locale = config.locale;
|
|
67
|
+
const stage = config.stage;
|
|
67
68
|
const collections = new Proxy({}, { get: (_target, collectionName) => {
|
|
68
69
|
if (typeof collectionName !== "string") return void 0;
|
|
69
70
|
const collection = client.collections[collectionName];
|
|
@@ -74,6 +75,7 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
74
75
|
...baseKey,
|
|
75
76
|
"find",
|
|
76
77
|
locale,
|
|
78
|
+
stage,
|
|
77
79
|
normalizeQueryKeyOptions(options)
|
|
78
80
|
]);
|
|
79
81
|
if (queryConfig?.realtime && client.realtime) {
|
|
@@ -98,6 +100,7 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
98
100
|
...baseKey,
|
|
99
101
|
"count",
|
|
100
102
|
locale,
|
|
103
|
+
stage,
|
|
101
104
|
normalizeQueryKeyOptions(options)
|
|
102
105
|
]);
|
|
103
106
|
if (queryConfig?.realtime && client.realtime) {
|
|
@@ -122,6 +125,7 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
122
125
|
...baseKey,
|
|
123
126
|
"findOne",
|
|
124
127
|
locale,
|
|
128
|
+
stage,
|
|
125
129
|
normalizeQueryKeyOptions(options)
|
|
126
130
|
]),
|
|
127
131
|
queryFn: wrapQueryFn(() => collection.findOne(options), errorMap)
|
|
@@ -130,49 +134,110 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
130
134
|
mutationKey: buildKey(keyPrefix, [
|
|
131
135
|
...baseKey,
|
|
132
136
|
"create",
|
|
133
|
-
locale
|
|
137
|
+
locale,
|
|
138
|
+
stage
|
|
134
139
|
]),
|
|
135
|
-
mutationFn: wrapMutationFn((data) => collection.create(data, locale ? {
|
|
140
|
+
mutationFn: wrapMutationFn((data) => collection.create(data, locale || stage ? {
|
|
141
|
+
...locale ? { locale } : {},
|
|
142
|
+
...stage ? { stage } : {}
|
|
143
|
+
} : void 0), errorMap)
|
|
136
144
|
}),
|
|
137
145
|
update: () => mutationOptions({
|
|
138
146
|
mutationKey: buildKey(keyPrefix, [
|
|
139
147
|
...baseKey,
|
|
140
148
|
"update",
|
|
141
|
-
locale
|
|
149
|
+
locale,
|
|
150
|
+
stage
|
|
142
151
|
]),
|
|
143
|
-
mutationFn: wrapMutationFn((variables) => collection.update(variables, locale ? {
|
|
152
|
+
mutationFn: wrapMutationFn((variables) => collection.update(variables, locale || stage ? {
|
|
153
|
+
...locale ? { locale } : {},
|
|
154
|
+
...stage ? { stage } : {}
|
|
155
|
+
} : void 0), errorMap)
|
|
144
156
|
}),
|
|
145
157
|
delete: () => mutationOptions({
|
|
146
158
|
mutationKey: buildKey(keyPrefix, [
|
|
147
159
|
...baseKey,
|
|
148
160
|
"delete",
|
|
149
|
-
locale
|
|
161
|
+
locale,
|
|
162
|
+
stage
|
|
150
163
|
]),
|
|
151
|
-
mutationFn: wrapMutationFn((variables) => collection.delete(variables, locale ? {
|
|
164
|
+
mutationFn: wrapMutationFn((variables) => collection.delete(variables, locale || stage ? {
|
|
165
|
+
...locale ? { locale } : {},
|
|
166
|
+
...stage ? { stage } : {}
|
|
167
|
+
} : void 0), errorMap)
|
|
152
168
|
}),
|
|
153
169
|
restore: () => mutationOptions({
|
|
154
170
|
mutationKey: buildKey(keyPrefix, [
|
|
155
171
|
...baseKey,
|
|
156
172
|
"restore",
|
|
157
|
-
locale
|
|
173
|
+
locale,
|
|
174
|
+
stage
|
|
175
|
+
]),
|
|
176
|
+
mutationFn: wrapMutationFn((variables) => collection.restore(variables, locale || stage ? {
|
|
177
|
+
...locale ? { locale } : {},
|
|
178
|
+
...stage ? { stage } : {}
|
|
179
|
+
} : void 0), errorMap)
|
|
180
|
+
}),
|
|
181
|
+
findVersions: (params) => queryOptions({
|
|
182
|
+
queryKey: buildKey(keyPrefix, [
|
|
183
|
+
...baseKey,
|
|
184
|
+
"findVersions",
|
|
185
|
+
locale,
|
|
186
|
+
stage,
|
|
187
|
+
normalizeQueryKeyOptions(params)
|
|
158
188
|
]),
|
|
159
|
-
|
|
189
|
+
queryFn: wrapQueryFn(() => collection.findVersions(params, locale || stage ? {
|
|
190
|
+
...locale ? { locale } : {},
|
|
191
|
+
...stage ? { stage } : {}
|
|
192
|
+
} : void 0), errorMap)
|
|
193
|
+
}),
|
|
194
|
+
revertToVersion: () => mutationOptions({
|
|
195
|
+
mutationKey: buildKey(keyPrefix, [
|
|
196
|
+
...baseKey,
|
|
197
|
+
"revertToVersion",
|
|
198
|
+
locale,
|
|
199
|
+
stage
|
|
200
|
+
]),
|
|
201
|
+
mutationFn: wrapMutationFn((variables) => collection.revertToVersion(variables, locale || stage ? {
|
|
202
|
+
...locale ? { locale } : {},
|
|
203
|
+
...stage ? { stage } : {}
|
|
204
|
+
} : void 0), errorMap)
|
|
205
|
+
}),
|
|
206
|
+
transitionStage: () => mutationOptions({
|
|
207
|
+
mutationKey: buildKey(keyPrefix, [
|
|
208
|
+
...baseKey,
|
|
209
|
+
"transitionStage",
|
|
210
|
+
locale,
|
|
211
|
+
stage
|
|
212
|
+
]),
|
|
213
|
+
mutationFn: wrapMutationFn((variables) => collection.transitionStage(variables, locale || stage ? {
|
|
214
|
+
...locale ? { locale } : {},
|
|
215
|
+
...stage ? { stage } : {}
|
|
216
|
+
} : void 0), errorMap)
|
|
160
217
|
}),
|
|
161
218
|
updateMany: () => mutationOptions({
|
|
162
219
|
mutationKey: buildKey(keyPrefix, [
|
|
163
220
|
...baseKey,
|
|
164
221
|
"updateMany",
|
|
165
|
-
locale
|
|
222
|
+
locale,
|
|
223
|
+
stage
|
|
166
224
|
]),
|
|
167
|
-
mutationFn: wrapMutationFn((variables) => collection.updateMany(variables, locale ? {
|
|
225
|
+
mutationFn: wrapMutationFn((variables) => collection.updateMany(variables, locale || stage ? {
|
|
226
|
+
...locale ? { locale } : {},
|
|
227
|
+
...stage ? { stage } : {}
|
|
228
|
+
} : void 0), errorMap)
|
|
168
229
|
}),
|
|
169
230
|
deleteMany: () => mutationOptions({
|
|
170
231
|
mutationKey: buildKey(keyPrefix, [
|
|
171
232
|
...baseKey,
|
|
172
233
|
"deleteMany",
|
|
173
|
-
locale
|
|
234
|
+
locale,
|
|
235
|
+
stage
|
|
174
236
|
]),
|
|
175
|
-
mutationFn: wrapMutationFn((variables) => collection.deleteMany(variables, locale ? {
|
|
237
|
+
mutationFn: wrapMutationFn((variables) => collection.deleteMany(variables, locale || stage ? {
|
|
238
|
+
...locale ? { locale } : {},
|
|
239
|
+
...stage ? { stage } : {}
|
|
240
|
+
} : void 0), errorMap)
|
|
176
241
|
})
|
|
177
242
|
};
|
|
178
243
|
} });
|
|
@@ -186,6 +251,7 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
186
251
|
...baseKey,
|
|
187
252
|
"get",
|
|
188
253
|
locale,
|
|
254
|
+
stage,
|
|
189
255
|
normalizeQueryKeyOptions(options)
|
|
190
256
|
]);
|
|
191
257
|
if (queryConfig?.realtime && client.realtime) {
|
|
@@ -209,60 +275,104 @@ function createQuestpieQueryOptions(client, config = {}) {
|
|
|
209
275
|
mutationKey: buildKey(keyPrefix, [
|
|
210
276
|
...baseKey,
|
|
211
277
|
"update",
|
|
212
|
-
locale
|
|
278
|
+
locale,
|
|
279
|
+
stage
|
|
213
280
|
]),
|
|
214
281
|
mutationFn: wrapMutationFn((variables) => global.update(variables.data, {
|
|
282
|
+
...variables.options,
|
|
283
|
+
...locale ? { locale } : void 0,
|
|
284
|
+
...stage ? { stage } : void 0
|
|
285
|
+
}), errorMap)
|
|
286
|
+
}),
|
|
287
|
+
findVersions: (options) => queryOptions({
|
|
288
|
+
queryKey: buildKey(keyPrefix, [
|
|
289
|
+
...baseKey,
|
|
290
|
+
"findVersions",
|
|
291
|
+
locale,
|
|
292
|
+
stage,
|
|
293
|
+
normalizeQueryKeyOptions(options)
|
|
294
|
+
]),
|
|
295
|
+
queryFn: wrapQueryFn(() => global.findVersions({
|
|
296
|
+
...options,
|
|
297
|
+
...locale ? { locale } : void 0,
|
|
298
|
+
...stage ? { stage } : void 0
|
|
299
|
+
}), errorMap)
|
|
300
|
+
}),
|
|
301
|
+
revertToVersion: () => mutationOptions({
|
|
302
|
+
mutationKey: buildKey(keyPrefix, [
|
|
303
|
+
...baseKey,
|
|
304
|
+
"revertToVersion",
|
|
305
|
+
locale,
|
|
306
|
+
stage
|
|
307
|
+
]),
|
|
308
|
+
mutationFn: wrapMutationFn((variables) => global.revertToVersion(variables.params, {
|
|
309
|
+
...variables.options,
|
|
310
|
+
...locale ? { locale } : void 0,
|
|
311
|
+
...stage ? { stage } : void 0
|
|
312
|
+
}), errorMap)
|
|
313
|
+
}),
|
|
314
|
+
transitionStage: () => mutationOptions({
|
|
315
|
+
mutationKey: buildKey(keyPrefix, [
|
|
316
|
+
...baseKey,
|
|
317
|
+
"transitionStage",
|
|
318
|
+
locale,
|
|
319
|
+
stage
|
|
320
|
+
]),
|
|
321
|
+
mutationFn: wrapMutationFn((variables) => global.transitionStage(variables.params, {
|
|
215
322
|
...variables.options,
|
|
216
323
|
...locale ? { locale } : void 0
|
|
217
324
|
}), errorMap)
|
|
218
325
|
})
|
|
219
326
|
};
|
|
220
327
|
} });
|
|
221
|
-
|
|
222
|
-
|
|
328
|
+
/**
|
|
329
|
+
* Resolve a nested route caller from the client by traversing dot segments.
|
|
330
|
+
*/
|
|
331
|
+
const callRoute = async (segments, input) => {
|
|
332
|
+
let current = client.routes;
|
|
223
333
|
for (const segment of segments) current = current?.[segment];
|
|
224
|
-
if (typeof current !== "function") throw new Error(`
|
|
334
|
+
if (typeof current !== "function") throw new Error(`Route not found at path: ${segments.join(".") || "<root>"}`);
|
|
225
335
|
if (input === void 0) return current();
|
|
226
336
|
return current(input);
|
|
227
337
|
};
|
|
228
|
-
const
|
|
338
|
+
const createRouteNodeProxy = (segments) => {
|
|
229
339
|
return new Proxy({}, { get: (_target, prop) => {
|
|
230
340
|
if (prop === "query") return (input) => queryOptions({
|
|
231
341
|
queryKey: buildKey(keyPrefix, [
|
|
232
|
-
"
|
|
342
|
+
"routes",
|
|
233
343
|
...segments,
|
|
234
344
|
"query",
|
|
235
345
|
locale,
|
|
236
346
|
normalizeQueryKeyOptions(input)
|
|
237
347
|
]),
|
|
238
|
-
queryFn: wrapQueryFn(() =>
|
|
348
|
+
queryFn: wrapQueryFn(() => callRoute(segments, input), errorMap)
|
|
239
349
|
});
|
|
240
350
|
if (prop === "mutation") return () => mutationOptions({
|
|
241
351
|
mutationKey: buildKey(keyPrefix, [
|
|
242
|
-
"
|
|
352
|
+
"routes",
|
|
243
353
|
...segments,
|
|
244
354
|
"mutation",
|
|
245
355
|
locale
|
|
246
356
|
]),
|
|
247
|
-
mutationFn: wrapMutationFn((variables) =>
|
|
357
|
+
mutationFn: wrapMutationFn((variables) => callRoute(segments, variables), errorMap)
|
|
248
358
|
});
|
|
249
359
|
if (prop === "key") return (input) => buildKey(keyPrefix, [
|
|
250
|
-
"
|
|
360
|
+
"routes",
|
|
251
361
|
...segments,
|
|
252
362
|
"query",
|
|
253
363
|
locale,
|
|
254
364
|
normalizeQueryKeyOptions(input)
|
|
255
365
|
]);
|
|
256
366
|
if (typeof prop !== "string") return void 0;
|
|
257
|
-
return
|
|
367
|
+
return createRouteNodeProxy([...segments, prop]);
|
|
258
368
|
} });
|
|
259
369
|
};
|
|
260
370
|
return {
|
|
261
371
|
collections,
|
|
262
372
|
globals,
|
|
263
|
-
|
|
373
|
+
routes: new Proxy({}, { get: (_target, prop) => {
|
|
264
374
|
if (typeof prop !== "string") return void 0;
|
|
265
|
-
return
|
|
375
|
+
return createRouteNodeProxy([prop]);
|
|
266
376
|
} }),
|
|
267
377
|
custom: {
|
|
268
378
|
query: (customConfig) => queryOptions({
|
package/package.json
CHANGED
|
@@ -1,39 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@questpie/tanstack-query",
|
|
3
|
-
"version": "
|
|
4
|
-
"type": "module",
|
|
3
|
+
"version": "3.0.1",
|
|
5
4
|
"repository": {
|
|
6
5
|
"type": "git",
|
|
7
|
-
"url": "https://github.com/questpie/questpie
|
|
6
|
+
"url": "https://github.com/questpie/questpie.git",
|
|
8
7
|
"directory": "packages/tanstack-query"
|
|
9
8
|
},
|
|
10
9
|
"files": [
|
|
11
10
|
"dist"
|
|
12
11
|
],
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"devDependencies": {
|
|
18
|
-
"bun-types": "latest",
|
|
19
|
-
"tsdown": "^0.18.3"
|
|
20
|
-
},
|
|
21
|
-
"peerDependencies": {
|
|
22
|
-
"questpie": "^2.0.0",
|
|
23
|
-
"@tanstack/react-query": "^5.0.0"
|
|
24
|
-
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "./dist/index.mjs",
|
|
14
|
+
"module": "./dist/index.mjs",
|
|
15
|
+
"types": "./dist/index.d.mts",
|
|
25
16
|
"exports": {
|
|
26
|
-
".":
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.mts",
|
|
19
|
+
"default": "./dist/index.mjs"
|
|
20
|
+
},
|
|
27
21
|
"./package.json": "./package.json"
|
|
28
22
|
},
|
|
29
23
|
"publishConfig": {
|
|
30
24
|
"access": "public",
|
|
31
25
|
"exports": {
|
|
32
|
-
".":
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.mts",
|
|
28
|
+
"default": "./dist/index.mjs"
|
|
29
|
+
},
|
|
33
30
|
"./package.json": "./package.json"
|
|
34
31
|
}
|
|
35
32
|
},
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsdown",
|
|
35
|
+
"check-types": "tsc --noEmit"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"bun-types": "latest",
|
|
39
|
+
"tsdown": "^0.18.3"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@tanstack/react-query": "^5.0.0",
|
|
43
|
+
"questpie": "^3.0.0"
|
|
44
|
+
}
|
|
39
45
|
}
|