@questpie/tanstack-query 1.0.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 ADDED
@@ -0,0 +1,303 @@
1
+ # @questpie/tanstack-query
2
+
3
+ Type-safe TanStack React Query integration for QUESTPIE.
4
+
5
+ ## Features
6
+
7
+ - **Query Options Factory** - Pre-built query/mutation options using `queryOptions()` and `mutationOptions()` from TanStack Query
8
+ - **SSR Ready** - Prefetch data on server, hydrate on client
9
+ - **Type-Safe** - Full TypeScript inference from your CMS schema
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ bun add @questpie/tanstack-query questpie @tanstack/react-query
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ### 1. Create Query Options
20
+
21
+ ```typescript
22
+ // src/lib/queries.ts
23
+ import { createClient } from "questpie/client";
24
+ import { createQuestpieQueryOptions } from "@questpie/tanstack-query";
25
+ import type { AppCMS } from "@/cms";
26
+
27
+ const cmsClient = createClient<AppCMS>({
28
+ baseURL: "http://localhost:3000",
29
+ basePath: "/api/cms",
30
+ });
31
+
32
+ export const q = createQuestpieQueryOptions(cmsClient, {
33
+ keyPrefix: ["cms"], // Optional: prefix for all query keys
34
+ });
35
+ ```
36
+
37
+ ### 2. Use in Components
38
+
39
+ ```typescript
40
+ import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
41
+ import { q } from "@/lib/queries"
42
+
43
+ function PostsList() {
44
+ // Queries
45
+ const { data: posts } = useQuery(q.collections.posts.find({ limit: 10 }))
46
+
47
+ // Mutations
48
+ const queryClient = useQueryClient()
49
+
50
+ const createPost = useMutation({
51
+ ...q.collections.posts.create(),
52
+ onSuccess: () => {
53
+ queryClient.invalidateQueries({ queryKey: ["cms", "collections", "posts"] })
54
+ },
55
+ })
56
+
57
+ return (
58
+ <div>
59
+ {posts?.docs.map((post) => (
60
+ <div key={post.id}>{post.title}</div>
61
+ ))}
62
+ <button onClick={() => createPost.mutate({ title: "New Post" })}>
63
+ Create Post
64
+ </button>
65
+ </div>
66
+ )
67
+ }
68
+ ```
69
+
70
+ ## Query Options API
71
+
72
+ ### Collections
73
+
74
+ ```typescript
75
+ // Find many
76
+ q.collections.posts.find({
77
+ where: { published: { eq: true } },
78
+ orderBy: { createdAt: "desc" },
79
+ limit: 10,
80
+ offset: 0,
81
+ with: { author: true },
82
+ });
83
+
84
+ // Find one
85
+ q.collections.posts.findOne({
86
+ where: { id: "post-id" },
87
+ with: { author: true, comments: true },
88
+ });
89
+
90
+ // Create
91
+ q.collections.posts.create();
92
+ // Usage: mutation.mutate({ title: "...", content: "..." })
93
+
94
+ // Update
95
+ q.collections.posts.update();
96
+ // Usage: mutation.mutate({ id: "...", data: { title: "..." } })
97
+
98
+ // Delete
99
+ q.collections.posts.delete();
100
+ // Usage: mutation.mutate({ id: "..." })
101
+
102
+ // Restore (soft delete)
103
+ q.collections.posts.restore();
104
+ // Usage: mutation.mutate({ id: "..." })
105
+ ```
106
+
107
+ ### Globals
108
+
109
+ ```typescript
110
+ // Get
111
+ q.globals.siteSettings.get();
112
+
113
+ // Update
114
+ q.globals.siteSettings.update();
115
+ // Usage: mutation.mutate({ data: { siteName: "..." } })
116
+ ```
117
+
118
+ ### Custom Queries
119
+
120
+ ```typescript
121
+ const searchQuery = q.custom.query({
122
+ key: ["search", query],
123
+ queryFn: () => fetch(`/api/search?q=${query}`).then((r) => r.json()),
124
+ });
125
+
126
+ useQuery(searchQuery);
127
+ ```
128
+
129
+ ## SSR Prefetching
130
+
131
+ ### TanStack Start
132
+
133
+ ```typescript
134
+ // src/routes/posts.tsx
135
+ import { createFileRoute } from "@tanstack/react-router"
136
+ import { useSuspenseQuery } from "@tanstack/react-query"
137
+ import { q } from "@/lib/queries"
138
+
139
+ export const Route = createFileRoute("/posts")({
140
+ loader: async ({ context }) => {
141
+ await context.queryClient.ensureQueryData(
142
+ q.collections.posts.find({ limit: 10 })
143
+ )
144
+ },
145
+ component: PostsPage,
146
+ })
147
+
148
+ function PostsPage() {
149
+ const { data: posts } = useSuspenseQuery(
150
+ q.collections.posts.find({ limit: 10 })
151
+ )
152
+
153
+ return (
154
+ <ul>
155
+ {posts.docs.map((post) => (
156
+ <li key={post.id}>{post.title}</li>
157
+ ))}
158
+ </ul>
159
+ )
160
+ }
161
+ ```
162
+
163
+ ### Next.js
164
+
165
+ ```typescript
166
+ // app/posts/page.tsx
167
+ import { HydrationBoundary, dehydrate } from "@tanstack/react-query"
168
+ import { getQueryClient } from "@/lib/query-client"
169
+ import { q } from "@/lib/queries"
170
+ import { PostsList } from "./posts-list"
171
+
172
+ export default async function PostsPage() {
173
+ const queryClient = getQueryClient()
174
+
175
+ await queryClient.prefetchQuery(
176
+ q.collections.posts.find({ limit: 10 })
177
+ )
178
+
179
+ return (
180
+ <HydrationBoundary state={dehydrate(queryClient)}>
181
+ <PostsList />
182
+ </HydrationBoundary>
183
+ )
184
+ }
185
+ ```
186
+
187
+ ## Optimistic Updates
188
+
189
+ ```typescript
190
+ const queryClient = useQueryClient();
191
+
192
+ const updatePost = useMutation({
193
+ ...q.collections.posts.update(),
194
+ onMutate: async ({ id, data }) => {
195
+ await queryClient.cancelQueries({
196
+ queryKey: ["cms", "collections", "posts"],
197
+ });
198
+
199
+ const previousPosts = queryClient.getQueryData([
200
+ "cms",
201
+ "collections",
202
+ "posts",
203
+ ]);
204
+
205
+ queryClient.setQueryData(["cms", "collections", "posts"], (old) => ({
206
+ ...old,
207
+ docs: old.docs.map((post) =>
208
+ post.id === id ? { ...post, ...data } : post,
209
+ ),
210
+ }));
211
+
212
+ return { previousPosts };
213
+ },
214
+ onError: (err, variables, context) => {
215
+ queryClient.setQueryData(
216
+ ["cms", "collections", "posts"],
217
+ context?.previousPosts,
218
+ );
219
+ },
220
+ onSettled: () => {
221
+ queryClient.invalidateQueries({
222
+ queryKey: ["cms", "collections", "posts"],
223
+ });
224
+ },
225
+ });
226
+ ```
227
+
228
+ ## Infinite Queries
229
+
230
+ ```typescript
231
+ import { useInfiniteQuery } from "@tanstack/react-query"
232
+ import { cmsClient } from "@/lib/cms-client"
233
+
234
+ function InfinitePosts() {
235
+ const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
236
+ queryKey: ["cms", "collections", "posts", "infinite"],
237
+ queryFn: ({ pageParam = 0 }) =>
238
+ cmsClient.collections.posts.find({
239
+ limit: 10,
240
+ offset: pageParam,
241
+ }),
242
+ getNextPageParam: (lastPage, allPages) => {
243
+ const totalFetched = allPages.flatMap((p) => p.docs).length
244
+ return lastPage.docs.length === 10 ? totalFetched : undefined
245
+ },
246
+ initialPageParam: 0,
247
+ })
248
+
249
+ return (
250
+ <div>
251
+ {data?.pages.flatMap((page) =>
252
+ page.docs.map((post) => <div key={post.id}>{post.title}</div>)
253
+ )}
254
+ {hasNextPage && (
255
+ <button onClick={() => fetchNextPage()}>Load More</button>
256
+ )}
257
+ </div>
258
+ )
259
+ }
260
+ ```
261
+
262
+ ## Query Key Structure
263
+
264
+ All query keys follow this structure:
265
+
266
+ ```typescript
267
+ // Collections
268
+ [...keyPrefix, "collections", collectionName, "find", options]
269
+ [...keyPrefix, "collections", collectionName, "findOne", options]
270
+
271
+ // Globals
272
+ [...keyPrefix, "globals", globalName, "get", options]
273
+
274
+ // Custom
275
+ [...keyPrefix, ...customKey]
276
+ ```
277
+
278
+ ## TypeScript
279
+
280
+ Full type inference from your CMS schema:
281
+
282
+ ```typescript
283
+ import type { CollectionSelect } from "questpie";
284
+ import type { AppCMS } from "@/cms";
285
+
286
+ // Collection item type
287
+ type Post = CollectionSelect<AppCMS["config"]["collections"]["posts"]>;
288
+
289
+ // Query result types are automatically inferred
290
+ const { data } = useQuery(q.collections.posts.find({ limit: 10 }));
291
+ // ^? { docs: Post[], totalDocs: number, ... }
292
+ ```
293
+
294
+ ## Related Packages
295
+
296
+ - [`questpie`](../questpie) - Core CMS engine
297
+ - [`@questpie/hono`](../hono) - Hono adapter
298
+ - [`@questpie/elysia`](../elysia) - Elysia adapter
299
+ - [`@questpie/next`](../next) - Next.js adapter
300
+
301
+ ## License
302
+
303
+ MIT
@@ -0,0 +1,93 @@
1
+ import { DefaultError, QueryKey, UseMutationOptions, UseQueryOptions } from "@tanstack/react-query";
2
+ import { Questpie } from "questpie";
3
+ import { QuestpieClient } from "questpie/client";
4
+
5
+ //#region src/index.d.ts
6
+ type QuestpieQueryErrorMap = (error: unknown) => unknown;
7
+ type QuestpieQueryOptionsConfig = {
8
+ keyPrefix?: QueryKey;
9
+ errorMap?: QuestpieQueryErrorMap;
10
+ locale?: string;
11
+ };
12
+ type AnyAsyncFn = (...args: any[]) => Promise<any>;
13
+ type QueryData<TFn extends AnyAsyncFn> = Awaited<ReturnType<TFn>>;
14
+ type FirstArg<TFn extends AnyAsyncFn> = Parameters<TFn> extends [infer TFirst, ...any[]] ? TFirst : never;
15
+ type HasArgs<TFn extends AnyAsyncFn> = Parameters<TFn> extends [] ? false : true;
16
+ type QueryBuilder<TFn extends AnyAsyncFn> = HasArgs<TFn> extends false ? () => UseQueryOptions<QueryData<TFn>> : undefined extends FirstArg<TFn> ? (options?: FirstArg<TFn>) => UseQueryOptions<QueryData<TFn>> : (options: FirstArg<TFn>) => UseQueryOptions<QueryData<TFn>>;
17
+ type MutationBuilder<TVariables, TData> = () => UseMutationOptions<TData, DefaultError, TVariables>;
18
+ /** Extract collection keys from QuestpieClient */
19
+ type CollectionKeys<T extends Questpie<any>> = Extract<keyof QuestpieClient<T>["collections"], string>;
20
+ /** Extract global keys from QuestpieClient */
21
+ type GlobalKeys<T extends Questpie<any>> = Extract<keyof QuestpieClient<T>["globals"], string>;
22
+ type CollectionFind<T extends Questpie<any>, K$1 extends CollectionKeys<T>> = QuestpieClient<T>["collections"][K$1]["find"];
23
+ type CollectionCount<T extends Questpie<any>, K$1 extends CollectionKeys<T>> = QuestpieClient<T>["collections"][K$1]["count"];
24
+ type CollectionFindOne<T extends Questpie<any>, K$1 extends CollectionKeys<T>> = QuestpieClient<T>["collections"][K$1]["findOne"];
25
+ type CollectionCreate<T extends Questpie<any>, K$1 extends CollectionKeys<T>> = QuestpieClient<T>["collections"][K$1]["create"];
26
+ type CollectionUpdate<T extends Questpie<any>, K$1 extends CollectionKeys<T>> = QuestpieClient<T>["collections"][K$1]["update"];
27
+ type CollectionDelete<T extends Questpie<any>, K$1 extends CollectionKeys<T>> = QuestpieClient<T>["collections"][K$1]["delete"];
28
+ type CollectionRestore<T extends Questpie<any>, K$1 extends CollectionKeys<T>> = QuestpieClient<T>["collections"][K$1]["restore"];
29
+ type GlobalGet<T extends Questpie<any>, K$1 extends GlobalKeys<T>> = QuestpieClient<T>["globals"][K$1] extends {
30
+ get: infer TGet;
31
+ } ? TGet extends AnyAsyncFn ? TGet : never : never;
32
+ type GlobalUpdate<T extends Questpie<any>, K$1 extends GlobalKeys<T>> = QuestpieClient<T>["globals"][K$1] extends {
33
+ update: infer TUpdate;
34
+ } ? TUpdate extends AnyAsyncFn ? TUpdate : never : never;
35
+ type CollectionQueryOptionsAPI<T extends Questpie<any>, K$1 extends CollectionKeys<T>> = {
36
+ find: QueryBuilder<CollectionFind<T, K$1>>;
37
+ count: QueryBuilder<CollectionCount<T, K$1>>;
38
+ findOne: QueryBuilder<CollectionFindOne<T, K$1>>;
39
+ create: MutationBuilder<FirstArg<CollectionCreate<T, K$1>>, QueryData<CollectionCreate<T, K$1>>>;
40
+ update: MutationBuilder<{
41
+ id: Parameters<CollectionUpdate<T, K$1>>[0];
42
+ data: Parameters<CollectionUpdate<T, K$1>>[1];
43
+ }, QueryData<CollectionUpdate<T, K$1>>>;
44
+ delete: MutationBuilder<{
45
+ id: Parameters<CollectionDelete<T, K$1>>[0];
46
+ }, QueryData<CollectionDelete<T, K$1>>>;
47
+ restore: MutationBuilder<{
48
+ id: Parameters<CollectionRestore<T, K$1>>[0];
49
+ }, QueryData<CollectionRestore<T, K$1>>>;
50
+ };
51
+ type GlobalQueryOptionsAPI<T extends Questpie<any>, K$1 extends GlobalKeys<T>> = {
52
+ get: QueryBuilder<GlobalGet<T, K$1>>;
53
+ update: MutationBuilder<{
54
+ data: Parameters<GlobalUpdate<T, K$1>>[0];
55
+ options?: Parameters<GlobalUpdate<T, K$1>>[1];
56
+ }, QueryData<GlobalUpdate<T, K$1>>>;
57
+ };
58
+ type QuestpieQueryOptionsProxy<T extends Questpie<any>> = {
59
+ collections: { [K in CollectionKeys<T>]: CollectionQueryOptionsAPI<T, K> };
60
+ globals: { [K in GlobalKeys<T>]: GlobalQueryOptionsAPI<T, K> };
61
+ custom: {
62
+ query: <TData>(config: {
63
+ key: QueryKey;
64
+ queryFn: () => Promise<TData>;
65
+ }) => UseQueryOptions<TData>;
66
+ mutation: <TVariables, TData>(config: {
67
+ key: QueryKey;
68
+ mutationFn: (variables: TVariables) => Promise<TData>;
69
+ }) => UseMutationOptions<TData, DefaultError, TVariables>;
70
+ };
71
+ key: (parts: QueryKey) => QueryKey;
72
+ };
73
+ /**
74
+ * Create type-safe query options proxy for TanStack Query
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * import { createQuestpieQueryOptions } from "@questpie/tanstack-query"
79
+ * import { createClient } from "questpie/client"
80
+ *
81
+ * const client = createClient<typeof cms>({ baseURL: "http://localhost:3000" })
82
+ * const qpo = createQuestpieQueryOptions(client)
83
+ *
84
+ * // Use with useQuery
85
+ * const { data } = useQuery(qpo.collections.posts.find({ limit: 10 }))
86
+ *
87
+ * // Use with useMutation
88
+ * const mutation = useMutation(qpo.collections.posts.create())
89
+ * ```
90
+ */
91
+ declare function createQuestpieQueryOptions<T extends Questpie<any>>(client: QuestpieClient<T>, config?: QuestpieQueryOptionsConfig): QuestpieQueryOptionsProxy<T>;
92
+ //#endregion
93
+ export { type DefaultError, type QueryKey, QuestpieQueryErrorMap, QuestpieQueryOptionsConfig, QuestpieQueryOptionsProxy, type UseMutationOptions, type UseQueryOptions, createQuestpieQueryOptions };
package/dist/index.mjs ADDED
@@ -0,0 +1,171 @@
1
+ import { mutationOptions, queryOptions } from "@tanstack/react-query";
2
+
3
+ //#region src/index.ts
4
+ const defaultErrorMap = (error) => error instanceof Error ? error : new Error(typeof error === "string" ? error : "Unknown error");
5
+ const buildKey = (prefix, parts) => prefix.length ? [...prefix, ...parts] : parts;
6
+ const sanitizeKeyPart = (value) => {
7
+ if (value === null || value === void 0) return value;
8
+ if (typeof value === "function") return void 0;
9
+ if (Array.isArray(value)) return value.map((item) => sanitizeKeyPart(item));
10
+ if (typeof value === "object") {
11
+ const sanitized = {};
12
+ for (const [key, entry] of Object.entries(value)) {
13
+ if (typeof entry === "function") continue;
14
+ const nextValue = sanitizeKeyPart(entry);
15
+ if (nextValue !== void 0) sanitized[key] = nextValue;
16
+ }
17
+ return sanitized;
18
+ }
19
+ return value;
20
+ };
21
+ const normalizeQueryKeyOptions = (options) => sanitizeKeyPart(options ?? {});
22
+ const wrapQueryFn = (queryFn, errorMap) => {
23
+ return async () => {
24
+ try {
25
+ return await queryFn();
26
+ } catch (error) {
27
+ throw errorMap(error);
28
+ }
29
+ };
30
+ };
31
+ const wrapMutationFn = (mutationFn, errorMap) => {
32
+ return async (variables) => {
33
+ try {
34
+ return await mutationFn(variables);
35
+ } catch (error) {
36
+ throw errorMap(error);
37
+ }
38
+ };
39
+ };
40
+ /**
41
+ * Create type-safe query options proxy for TanStack Query
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * import { createQuestpieQueryOptions } from "@questpie/tanstack-query"
46
+ * import { createClient } from "questpie/client"
47
+ *
48
+ * const client = createClient<typeof cms>({ baseURL: "http://localhost:3000" })
49
+ * const qpo = createQuestpieQueryOptions(client)
50
+ *
51
+ * // Use with useQuery
52
+ * const { data } = useQuery(qpo.collections.posts.find({ limit: 10 }))
53
+ *
54
+ * // Use with useMutation
55
+ * const mutation = useMutation(qpo.collections.posts.create())
56
+ * ```
57
+ */
58
+ function createQuestpieQueryOptions(client, config = {}) {
59
+ const keyPrefix = config.keyPrefix ?? ["questpie"];
60
+ const errorMap = config.errorMap ?? defaultErrorMap;
61
+ const locale = config.locale;
62
+ return {
63
+ collections: new Proxy({}, { get: (_target, collectionName) => {
64
+ if (typeof collectionName !== "string") return void 0;
65
+ const collection = client.collections[collectionName];
66
+ const baseKey = ["collections", collectionName];
67
+ return {
68
+ find: (options) => queryOptions({
69
+ queryKey: buildKey(keyPrefix, [
70
+ ...baseKey,
71
+ "find",
72
+ locale,
73
+ normalizeQueryKeyOptions(options)
74
+ ]),
75
+ queryFn: wrapQueryFn(() => collection.find(options), errorMap)
76
+ }),
77
+ count: (options) => queryOptions({
78
+ queryKey: buildKey(keyPrefix, [
79
+ ...baseKey,
80
+ "count",
81
+ locale,
82
+ normalizeQueryKeyOptions(options)
83
+ ]),
84
+ queryFn: wrapQueryFn(() => collection.count(options), errorMap)
85
+ }),
86
+ findOne: (options) => queryOptions({
87
+ queryKey: buildKey(keyPrefix, [
88
+ ...baseKey,
89
+ "findOne",
90
+ locale,
91
+ normalizeQueryKeyOptions(options)
92
+ ]),
93
+ queryFn: wrapQueryFn(() => collection.findOne(options), errorMap)
94
+ }),
95
+ create: () => mutationOptions({
96
+ mutationKey: buildKey(keyPrefix, [
97
+ ...baseKey,
98
+ "create",
99
+ locale
100
+ ]),
101
+ mutationFn: wrapMutationFn((data) => collection.create(data, locale ? { locale } : void 0), errorMap)
102
+ }),
103
+ update: () => mutationOptions({
104
+ mutationKey: buildKey(keyPrefix, [
105
+ ...baseKey,
106
+ "update",
107
+ locale
108
+ ]),
109
+ mutationFn: wrapMutationFn((variables) => collection.update(variables.id, variables.data, locale ? { locale } : void 0), errorMap)
110
+ }),
111
+ delete: () => mutationOptions({
112
+ mutationKey: buildKey(keyPrefix, [
113
+ ...baseKey,
114
+ "delete",
115
+ locale
116
+ ]),
117
+ mutationFn: wrapMutationFn((variables) => collection.delete(variables.id, locale ? { locale } : void 0), errorMap)
118
+ }),
119
+ restore: () => mutationOptions({
120
+ mutationKey: buildKey(keyPrefix, [
121
+ ...baseKey,
122
+ "restore",
123
+ locale
124
+ ]),
125
+ mutationFn: wrapMutationFn((variables) => collection.restore(variables.id, locale ? { locale } : void 0), errorMap)
126
+ })
127
+ };
128
+ } }),
129
+ globals: new Proxy({}, { get: (_target, globalName) => {
130
+ if (typeof globalName !== "string") return void 0;
131
+ const global = client.globals[globalName];
132
+ const baseKey = ["globals", globalName];
133
+ return {
134
+ get: (options) => queryOptions({
135
+ queryKey: buildKey(keyPrefix, [
136
+ ...baseKey,
137
+ "get",
138
+ locale,
139
+ normalizeQueryKeyOptions(options)
140
+ ]),
141
+ queryFn: wrapQueryFn(() => global.get(options), errorMap)
142
+ }),
143
+ update: () => mutationOptions({
144
+ mutationKey: buildKey(keyPrefix, [
145
+ ...baseKey,
146
+ "update",
147
+ locale
148
+ ]),
149
+ mutationFn: wrapMutationFn((variables) => global.update(variables.data, {
150
+ ...variables.options,
151
+ ...locale ? { locale } : void 0
152
+ }), errorMap)
153
+ })
154
+ };
155
+ } }),
156
+ custom: {
157
+ query: (customConfig) => queryOptions({
158
+ queryKey: buildKey(keyPrefix, customConfig.key),
159
+ queryFn: wrapQueryFn(customConfig.queryFn, errorMap)
160
+ }),
161
+ mutation: (customConfig) => mutationOptions({
162
+ mutationKey: buildKey(keyPrefix, customConfig.key),
163
+ mutationFn: wrapMutationFn(customConfig.mutationFn, errorMap)
164
+ })
165
+ },
166
+ key: (parts) => buildKey(keyPrefix, parts)
167
+ };
168
+ }
169
+
170
+ //#endregion
171
+ export { createQuestpieQueryOptions };
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@questpie/tanstack-query",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/questpie/questpie-cms.git",
8
+ "directory": "packages/tanstack-query"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsdown",
15
+ "check-types": "tsc --noEmit"
16
+ },
17
+ "devDependencies": {
18
+ "@questpie/typescript-config": "workspace:*",
19
+ "bun-types": "latest",
20
+ "tsdown": "^0.18.3"
21
+ },
22
+ "peerDependencies": {
23
+ "questpie": "workspace:*",
24
+ "@tanstack/react-query": "^5.0.0"
25
+ },
26
+ "exports": {
27
+ ".": {
28
+ "import": "./dist/index.mjs",
29
+ "types": "./dist/index.d.mts"
30
+ }
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ }
35
+ }