Skip to content

Commit 882d8a5

Browse files
committed
oxfmt
1 parent 80d1a76 commit 882d8a5

18 files changed

Lines changed: 3034 additions & 2909 deletions

README.md

Lines changed: 145 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -19,87 +19,142 @@ npm install eden-tanstack-query @elysiajs/eden @tanstack/query-core elysia
1919
## Usage
2020

2121
```ts
22-
import { createEdenTQ } from 'eden-tanstack-query'
23-
import type { App } from './server' // Your Elysia app type
22+
import { createEdenTQ } from "eden-tanstack-query";
23+
import type { App } from "./server"; // Your Elysia app type
2424

25-
const eden = createEdenTQ<App>('http://localhost:3000')
25+
const eden = createEdenTQ<App>("http://localhost:3000");
2626
```
2727

2828
### Route Schema Mode (No Direct Elysia Type Import)
2929

3030
For large codebases, you can avoid pulling full app types into every client file:
3131

3232
```ts
33-
import { createEdenTQFromSchema } from 'eden-tanstack-query'
34-
import type { App } from './server'
33+
import { createEdenTQFromSchema } from "eden-tanstack-query";
34+
import type { App } from "./server";
3535

36-
type Routes = App['~Routes']
37-
const eden = createEdenTQFromSchema<Routes>('http://localhost:3000')
36+
type Routes = App["~Routes"];
37+
const eden = createEdenTQFromSchema<Routes>("http://localhost:3000");
3838
```
3939

4040
This keeps the client typed while reducing type-checker pressure compared with importing a full `Elysia` app type everywhere.
4141

4242
### Queries
4343

4444
```ts
45-
import { createQuery } from '@tanstack/svelte-query' // or react-query, vue-query, etc.
45+
import { createQuery } from "@tanstack/svelte-query"; // or react-query, vue-query, etc.
4646

4747
// Fully type-safe, auto-generated query key
48-
const query = createQuery(() =>
49-
eden.users({ id: '123' }).get.queryOptions({
50-
params: { id: '123' }
51-
})
52-
)
48+
const query = createQuery(() =>
49+
eden.users({ id: "123" }).get.queryOptions({
50+
params: { id: "123" },
51+
}),
52+
);
5353

5454
// query.data is typed as your Elysia response type!
5555
```
5656

5757
React example:
5858

5959
```ts
60-
import { useQuery } from '@tanstack/react-query'
60+
import { useQuery } from "@tanstack/react-query";
6161

6262
const query = useQuery(
63-
eden.users({ id: '123' }).get.queryOptions({
64-
params: { id: '123' }
65-
})
66-
)
63+
eden.users({ id: "123" }).get.queryOptions({
64+
params: { id: "123" },
65+
}),
66+
);
6767
```
6868

6969
### Infinite Queries
7070

7171
```ts
72-
import { createInfiniteQuery } from '@tanstack/svelte-query'
72+
import { createInfiniteQuery } from "@tanstack/svelte-query";
7373

7474
const infiniteQuery = createInfiniteQuery(() =>
7575
eden.posts.get.infiniteQueryOptions(
76-
{ query: { limit: '10' } },
76+
{ query: { limit: "10" } },
7777
{
7878
initialPageParam: 0,
7979
getNextPageParam: (lastPage) => lastPage.nextCursor,
8080
// cursorKey: 'cursor' // optional, defaults to 'cursor'
81-
}
82-
)
83-
)
81+
},
82+
),
83+
);
8484
```
8585

8686
### Mutations
8787

8888
```ts
89-
import { createMutation } from '@tanstack/svelte-query'
89+
import { createMutation } from "@tanstack/svelte-query";
9090

9191
const mutation = createMutation(
9292
eden.users.post.mutation({
9393
onSuccess: (data) => {
94-
console.log('Created user:', data.id)
95-
}
96-
})
97-
)
94+
console.log("Created user:", data.id);
95+
},
96+
}),
97+
);
9898

9999
// Type-safe variables
100100
mutation.mutate({
101-
body: { name: 'Alice', email: 'alice@example.com' }
102-
})
101+
body: { name: "Alice", email: "alice@example.com" },
102+
});
103+
```
104+
105+
### Svelte / Solid Inference Note
106+
107+
When using `@tanstack/svelte-query` or `@tanstack/solid-query`, TypeScript can
108+
sometimes widen mutation `TData` to `undefined` if `mutationOptions(...)` is
109+
fully inlined inside `createMutation(() => ...)` / `useMutation(() => ...)`.
110+
111+
Use one of these stable patterns:
112+
113+
```ts
114+
import { createQuery, createMutation } from "@tanstack/svelte-query";
115+
116+
// Query: hoist options first
117+
const userQueryOptions = eden.users({ id: "123" }).get.queryOptions({
118+
params: { id: "123" },
119+
});
120+
const userQuery = createQuery(() => userQueryOptions);
121+
122+
// Mutation: prefer the built-in accessor helper
123+
const createUserMutation = createMutation(
124+
eden.users.post.mutation({
125+
onSuccess: (data) => {
126+
console.log(data.id);
127+
},
128+
}),
129+
);
130+
```
131+
132+
Solid example:
133+
134+
```ts
135+
import { useMutation } from "@tanstack/solid-query";
136+
137+
const createUserMutation = useMutation(
138+
eden.users.post.mutation({
139+
onSuccess: (data) => {
140+
console.log(data.id);
141+
},
142+
}),
143+
);
144+
```
145+
146+
If you need fully inline calls, you can also pin the generic:
147+
148+
```ts
149+
type CreateUserResponse = App["~Routes"]["users"]["post"]["response"][200];
150+
151+
const mutation = createMutation(() =>
152+
eden.users.post.mutationOptions<CreateUserResponse>({
153+
onSuccess: (data) => {
154+
console.log(data.id);
155+
},
156+
}),
157+
);
103158
```
104159

105160
### Path Params: Inline vs Deferred
@@ -109,29 +164,29 @@ For routes like `/cases/:id/workflow`, you can now choose either pattern:
109164
Inline param (known when building options):
110165

111166
```ts
112-
const query = eden.cases({ id: 'case-123' }).workflow.get.queryOptions({
113-
params: { id: 'case-123' }
114-
})
167+
const query = eden.cases({ id: "case-123" }).workflow.get.queryOptions({
168+
params: { id: "case-123" },
169+
});
115170

116-
const mutation = eden.cases({ id: 'case-123' }).workflow.patch.mutationOptions()
171+
const mutation = eden.cases({ id: "case-123" }).workflow.patch.mutationOptions();
117172
await mutation.mutationFn({
118-
params: { id: 'case-123' },
119-
body: { status: 'active' }
120-
})
173+
params: { id: "case-123" },
174+
body: { status: "active" },
175+
});
121176
```
122177

123178
Deferred param (ID known later at call time):
124179

125180
```ts
126-
const query = eden.cases({ id: '' }).workflow.get.queryOptions({
127-
params: { id: caseId }
128-
})
181+
const query = eden.cases({ id: "" }).workflow.get.queryOptions({
182+
params: { id: caseId },
183+
});
129184

130-
const mutation = eden.cases({ id: '' }).workflow.patch.mutationOptions()
185+
const mutation = eden.cases({ id: "" }).workflow.patch.mutationOptions();
131186
await mutation.mutationFn({
132187
params: { id: caseId },
133-
body: { status: 'active' }
134-
})
188+
body: { status: "active" },
189+
});
135190
```
136191

137192
Recommendation:
@@ -142,38 +197,38 @@ Recommendation:
142197
### Invalidation
143198

144199
```ts
145-
import { useQueryClient } from '@tanstack/svelte-query'
200+
import { useQueryClient } from "@tanstack/svelte-query";
146201

147-
const queryClient = useQueryClient()
202+
const queryClient = useQueryClient();
148203

149204
// Invalidate specific query
150-
await eden.users({ id: '123' }).get.invalidate(queryClient, {
151-
params: { id: '123' }
152-
})
205+
await eden.users({ id: "123" }).get.invalidate(queryClient, {
206+
params: { id: "123" },
207+
});
153208

154209
// Invalidate all queries for a route
155-
await eden.users({ id: '123' }).get.invalidate(queryClient)
210+
await eden.users({ id: "123" }).get.invalidate(queryClient);
156211
```
157212

158213
### Utils (Bound QueryClient)
159214

160215
For tRPC-like ergonomics, use `createEdenTQUtils` to bind a QueryClient once:
161216

162217
```ts
163-
import { createEdenTQ, createEdenTQUtils } from 'eden-tanstack-query'
218+
import { createEdenTQ, createEdenTQUtils } from "eden-tanstack-query";
164219

165-
const eden = createEdenTQ<App>('http://localhost:3000')
166-
const utils = createEdenTQUtils(eden, queryClient)
220+
const eden = createEdenTQ<App>("http://localhost:3000");
221+
const utils = createEdenTQUtils(eden, queryClient);
167222

168223
// No need to pass queryClient every time!
169-
await utils.users({ id: '123' }).get.invalidate({ params: { id: '123' } })
170-
await utils.posts.get.prefetch({ query: { limit: '10' } })
171-
await utils.posts.get.cancel()
172-
await utils.posts.get.refetch()
224+
await utils.users({ id: "123" }).get.invalidate({ params: { id: "123" } });
225+
await utils.posts.get.prefetch({ query: { limit: "10" } });
226+
await utils.posts.get.cancel();
227+
await utils.posts.get.refetch();
173228

174229
// Cache manipulation
175-
utils.users({ id: '123' }).get.setData({ params: { id: '123' } }, { id: '123', name: 'Updated' })
176-
const cached = utils.users({ id: '123' }).get.getData({ params: { id: '123' } })
230+
utils.users({ id: "123" }).get.setData({ params: { id: "123" } }, { id: "123", name: "Updated" });
231+
const cached = utils.users({ id: "123" }).get.getData({ params: { id: "123" } });
177232
```
178233

179234
### Error Handling
@@ -182,12 +237,12 @@ const cached = utils.users({ id: '123' }).get.getData({ params: { id: '123' } })
182237
Query error states are populated automatically:
183238

184239
```ts
185-
const options = eden.users({ id: '123' }).get.queryOptions({
186-
params: { id: '123' }
187-
})
240+
const options = eden.users({ id: "123" }).get.queryOptions({
241+
params: { id: "123" },
242+
});
188243

189244
try {
190-
const data = await options.queryFn()
245+
const data = await options.queryFn();
191246
} catch (error) {
192247
// error is typed from your Elysia response map
193248
}
@@ -219,19 +274,19 @@ Creates a utils object with a bound QueryClient for tRPC-like ergonomics.
219274

220275
Each HTTP method (`get`, `post`, `put`, `delete`, `patch`) has:
221276

222-
| Method | Description |
223-
|--------|-------------|
224-
| `.queryOptions(input, overrides?)` | Returns `{ queryKey, queryFn, ...options }` for `createQuery` |
225-
| `.infiniteQueryOptions(input, opts, overrides?)` | Returns options for `createInfiniteQuery` |
226-
| `.mutationOptions(overrides?)` | Returns `{ mutationKey, mutationFn, ...options }` for `createMutation` |
227-
| `.mutation(overrides?)` | Returns a stable `() => mutationOptions` accessor for adapters expecting an options factory |
228-
| `.queryKey(input?)` | Returns the query key |
229-
| `.mutationKey(input?)` | Returns the mutation key |
230-
| `.invalidate(queryClient, input?, exact?)` | Invalidates matching queries |
231-
| `.prefetch(queryClient, input)` | Prefetch a query |
232-
| `.ensureData(queryClient, input)` | Ensure data exists or fetch it |
233-
| `.setData(queryClient, input, updater)` | Manually set cache data |
234-
| `.getData(queryClient, input)` | Read from cache |
277+
| Method | Description |
278+
| ------------------------------------------------ | ------------------------------------------------------------------------------------------- |
279+
| `.queryOptions(input, overrides?)` | Returns `{ queryKey, queryFn, ...options }` for `createQuery` |
280+
| `.infiniteQueryOptions(input, opts, overrides?)` | Returns options for `createInfiniteQuery` |
281+
| `.mutationOptions(overrides?)` | Returns `{ mutationKey, mutationFn, ...options }` for `createMutation` |
282+
| `.mutation(overrides?)` | Returns a stable `() => mutationOptions` accessor for adapters expecting an options factory |
283+
| `.queryKey(input?)` | Returns the query key |
284+
| `.mutationKey(input?)` | Returns the mutation key |
285+
| `.invalidate(queryClient, input?, exact?)` | Invalidates matching queries |
286+
| `.prefetch(queryClient, input)` | Prefetch a query |
287+
| `.ensureData(queryClient, input)` | Ensure data exists or fetch it |
288+
| `.setData(queryClient, input, updater)` | Manually set cache data |
289+
| `.getData(queryClient, input)` | Read from cache |
235290

236291
### Query Key Shape
237292

@@ -253,15 +308,15 @@ You can pass standard TanStack Query options as overrides:
253308

254309
```ts
255310
eden.posts.get.queryOptions(
256-
{ query: { limit: '10' } },
311+
{ query: { limit: "10" } },
257312
{
258313
staleTime: 5000,
259314
gcTime: 10000,
260315
enabled: isReady,
261316
refetchOnMount: false,
262-
retry: 3
263-
}
264-
)
317+
retry: 3,
318+
},
319+
);
265320
```
266321

267322
### Mutation Options Overrides
@@ -276,8 +331,8 @@ eden.users.post.mutationOptions({
276331
},
277332
onError: (error, variables, context) => {
278333
// Rollback
279-
}
280-
})
334+
},
335+
});
281336
```
282337

283338
`mutationOptions()` and `mutation()` are equivalent in typing.
@@ -299,25 +354,25 @@ If your API has many routes:
299354
```ts
300355
export function createUserQuery(userId: string) {
301356
return createQuery<User>(() => ({
302-
queryKey: ['users', userId],
357+
queryKey: ["users", userId],
303358
queryFn: async () => {
304-
const { data, error } = await api.users({ id: userId }).get()
305-
if (error) throw error
306-
return data as User // Manual cast!
359+
const { data, error } = await api.users({ id: userId }).get();
360+
if (error) throw error;
361+
return data as User; // Manual cast!
307362
},
308-
}))
363+
}));
309364
}
310365
```
311366

312367
### After (with eden-tanstack-query)
313368

314369
```ts
315370
export function createUserQuery(userId: string) {
316-
return createQuery(() =>
371+
return createQuery(() =>
317372
eden.users({ id: userId }).get.queryOptions({
318-
params: { id: userId }
319-
})
320-
)
373+
params: { id: userId },
374+
}),
375+
);
321376
}
322377
// Types are inferred from your Elysia server!
323378
```

0 commit comments

Comments
 (0)