@nxgt/httpyz-query 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 +614 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +11 -0
- package/dist/key/key.d.ts +10 -0
- package/dist/key/key.d.ts.map +1 -0
- package/dist/openapi/create-openapi-queries.d.ts +15 -0
- package/dist/openapi/create-openapi-queries.d.ts.map +1 -0
- package/dist/openapi/types.d.ts +42 -0
- package/dist/openapi/types.d.ts.map +1 -0
- package/dist/openapi.d.ts +3 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +105 -0
- package/dist/openapi.js.map +11 -0
- package/dist/queries/create-queries.d.ts +19 -0
- package/dist/queries/create-queries.d.ts.map +1 -0
- package/dist/queries/types.d.ts +89 -0
- package/dist/queries/types.d.ts.map +1 -0
- package/package.json +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
# @nxgt/httpyz-query
|
|
2
|
+
|
|
3
|
+
[TanStack Query](https://tanstack.com/query) options for the calls of an
|
|
4
|
+
[`@nxgt/httpyz`](https://www.npmjs.com/package/@nxgt/httpyz) client. Each
|
|
5
|
+
function returns a plain options object, with a key that tells calls apart by
|
|
6
|
+
what they send, and a `queryFn` that sends the call with the query's
|
|
7
|
+
`signal`: a query TanStack cancels aborts its request.
|
|
8
|
+
|
|
9
|
+
It adds no runtime of TanStack's, so any adapter takes the objects:
|
|
10
|
+
`useQuery` in React or Vue, `createQuery` in Solid or Svelte, `injectQuery`
|
|
11
|
+
in Angular.
|
|
12
|
+
|
|
13
|
+
> **0.x.** The API is still settling.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
bun add @nxgt/httpyz @nxgt/httpyz-query @tanstack/react-query
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
| Peer | | |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| `@nxgt/httpyz` | required | the client whose calls the queries send |
|
|
24
|
+
| `@tanstack/query-core` | required | TanStack's types. Every adapter depends on it, so installing yours is enough |
|
|
25
|
+
| `typescript` | required | `^6.0.3` |
|
|
26
|
+
| `@nxgt/openapi-httpyz` | optional | only for [`@nxgt/httpyz-query/openapi`](#with-an-openapi-spec) |
|
|
27
|
+
|
|
28
|
+
## Setup
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { createHttpClient } from '@nxgt/httpyz';
|
|
32
|
+
import { createQueries } from '@nxgt/httpyz-query';
|
|
33
|
+
|
|
34
|
+
export const http = createHttpClient({ baseUrl: 'https://api.example.com' });
|
|
35
|
+
export const queries = createQueries(http);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| Option | Default | |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| `scope` | none | put first in every key: two clients whose paths are the same keep their queries apart |
|
|
41
|
+
|
|
42
|
+
## Subpaths
|
|
43
|
+
|
|
44
|
+
| Import | What it has |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `@nxgt/httpyz-query` | `createQueries`, for a client of `createHttpClient`, and the types |
|
|
47
|
+
| `@nxgt/httpyz-query/openapi` | `createOpenApiQueries`, for a client bound to a spec by `@nxgt/openapi-httpyz` |
|
|
48
|
+
|
|
49
|
+
## Queries
|
|
50
|
+
|
|
51
|
+
`queryOptions` takes a call as the client's `request` does: the method, the
|
|
52
|
+
path, then its options. The query resolves to the data of a 2xx reply, and
|
|
53
|
+
fails with the client's `ReplyStatusError` on any other:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { useQuery } from '@tanstack/react-query';
|
|
57
|
+
import { z } from 'zod';
|
|
58
|
+
import { queries } from './queries.js';
|
|
59
|
+
|
|
60
|
+
const Employee = z.object({ id: z.int(), name: z.string() });
|
|
61
|
+
const Problem = z.object({ title: z.string() });
|
|
62
|
+
|
|
63
|
+
const { data } = useQuery({
|
|
64
|
+
...queries.queryOptions('get', '/employees/{id}', {
|
|
65
|
+
param: { id },
|
|
66
|
+
responses: { 200: Employee, 404: Problem },
|
|
67
|
+
}),
|
|
68
|
+
enabled: id !== undefined,
|
|
69
|
+
});
|
|
70
|
+
data?.name; // Employee: the 404 is the query's error
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The key is `[method, path, input]`, after the `scope` when there is one.
|
|
74
|
+
`input` holds what the call sends, `param`, `query`, `header` and its body, and
|
|
75
|
+
`decode: false`, since that changes the data; it is left out when empty. The
|
|
76
|
+
call options, `headers`, `timeout`, `signal`, are never in it. The key is
|
|
77
|
+
tagged with the data, so `queryClient.getQueryData(options.queryKey)` is
|
|
78
|
+
typed.
|
|
79
|
+
|
|
80
|
+
## Cancelling
|
|
81
|
+
|
|
82
|
+
TanStack aborts a query's `signal` when the query is cancelled, and when its
|
|
83
|
+
last observer unmounts while it still runs. The call is sent with that
|
|
84
|
+
signal, so it is aborted too: its request stops, not only its result. A
|
|
85
|
+
`signal` in the call's own options still ends it, as does its `latest`.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
await queryClient.cancelQueries({ queryKey: queries.queryKey('get', '/search') });
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Infinite queries
|
|
92
|
+
|
|
93
|
+
`infiniteQueryOptions` takes the call's options, then how it pages:
|
|
94
|
+
TanStack's own `initialPageParam` and `getNextPageParam`, and
|
|
95
|
+
`pageParamName`, the query parameter each page's param is sent as. A `null`
|
|
96
|
+
page param is left out, so the first page goes without it:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { useInfiniteQuery } from '@tanstack/react-query';
|
|
100
|
+
|
|
101
|
+
const { data, fetchNextPage } = useInfiniteQuery(
|
|
102
|
+
queries.infiniteQueryOptions(
|
|
103
|
+
'post',
|
|
104
|
+
'/employees/search',
|
|
105
|
+
{ json: { sort }, query: { first: 20 }, responses: { 200: EmployeePage } },
|
|
106
|
+
{
|
|
107
|
+
pageParamName: 'after',
|
|
108
|
+
initialPageParam: null as string | null,
|
|
109
|
+
getNextPageParam: (last) => last.cursor,
|
|
110
|
+
},
|
|
111
|
+
),
|
|
112
|
+
);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Its key ends with `'infinite'`, apart from the plain query of the same call,
|
|
116
|
+
whose data is one page rather than all of them.
|
|
117
|
+
|
|
118
|
+
## Mutations
|
|
119
|
+
|
|
120
|
+
`mutationOptions` takes the method and the path, and what every call shares,
|
|
121
|
+
such as `responses`. Its `mutate()` takes what each call sends:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { useMutation } from '@tanstack/react-query';
|
|
125
|
+
|
|
126
|
+
const remove = useMutation({
|
|
127
|
+
...queries.mutationOptions('delete', '/employees/{id}', {
|
|
128
|
+
responses: { 204: null },
|
|
129
|
+
}),
|
|
130
|
+
onSuccess: () =>
|
|
131
|
+
queryClient.invalidateQueries({ queryKey: queries.queryKey('get', '/employees') }),
|
|
132
|
+
});
|
|
133
|
+
remove.mutate({ param: { id } });
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`mutate()` takes nothing when the path has no `{name}`s to fill.
|
|
137
|
+
|
|
138
|
+
## Keys and filters
|
|
139
|
+
|
|
140
|
+
`queryKey(method, path?, input?)` is a key, or the start of one: TanStack
|
|
141
|
+
matches a filter's key as a prefix, so every query of a path matches,
|
|
142
|
+
whatever its `param`:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
queryClient.invalidateQueries({ queryKey: queries.queryKey('get', '/employees/{id}') });
|
|
146
|
+
queryClient.removeQueries({ queryKey: queries.queryKey('get') }); // every GET
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## With an OpenAPI spec
|
|
150
|
+
|
|
151
|
+
`@nxgt/httpyz-query/openapi` does the same for a client bound to a
|
|
152
|
+
generated spec by
|
|
153
|
+
[`@nxgt/openapi-httpyz`](https://www.npmjs.com/package/@nxgt/openapi-httpyz),
|
|
154
|
+
an optional peer. It takes the bound client, and reads the spec from the
|
|
155
|
+
`operations` the client was bound to, as the client does:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import { createOpenApiQueries } from '@nxgt/httpyz-query/openapi';
|
|
159
|
+
import { api } from './api.js'; // createOpenApiClient(http, operations)
|
|
160
|
+
|
|
161
|
+
export const queries = createOpenApiQueries(api);
|
|
162
|
+
|
|
163
|
+
// As api.get() takes it: the path, the input, then the init
|
|
164
|
+
useQuery(queries.queryOptions('get', '/employees/{id}', { param: { id } }));
|
|
165
|
+
useQuery(queries.queryOptions('get', '/health'));
|
|
166
|
+
|
|
167
|
+
useInfiniteQuery(
|
|
168
|
+
queries.infiniteQueryOptions(
|
|
169
|
+
'post',
|
|
170
|
+
'/employees/search',
|
|
171
|
+
{ json: { sort }, query: { first: 20 } },
|
|
172
|
+
{
|
|
173
|
+
pageParamName: 'after',
|
|
174
|
+
initialPageParam: null as string | null,
|
|
175
|
+
getNextPageParam: (last) => last.cursor,
|
|
176
|
+
},
|
|
177
|
+
),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const remove = useMutation(queries.mutationOptions('delete', '/employees/{id}'));
|
|
181
|
+
remove.mutate({ param: { id } });
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
- Every call is typed by the spec, as the bound client's are: the method, one
|
|
185
|
+
the spec has an operation for, the path, the input, and the data, a 2xx
|
|
186
|
+
reply's, decoded when the client decodes.
|
|
187
|
+
- The key holds the input, header parameters included, and never the init.
|
|
188
|
+
- `pageParamName` is one of the operation's query parameters.
|
|
189
|
+
- `mutate()` takes the operation's input; `mutationOptions`' third argument
|
|
190
|
+
is the init every call shares.
|
|
191
|
+
|
|
192
|
+
Coming from `openapi-react-query`: `$api.queryOptions('get', path, { params:
|
|
193
|
+
{ path, query }, body })` becomes `queries.queryOptions('get', path, { param,
|
|
194
|
+
query, json })`, and `$api.useQuery(...)` becomes
|
|
195
|
+
`useQuery(queries.queryOptions(...))`.
|
|
196
|
+
|
|
197
|
+
## API
|
|
198
|
+
|
|
199
|
+
### `@nxgt/httpyz-query`
|
|
200
|
+
|
|
201
|
+
#### Functions
|
|
202
|
+
|
|
203
|
+
##### `createQueries`
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
function createQueries(http: HttpClient, options?: QueriesOptions): HttpQueries;
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The options objects for the calls of `http`, a client of `createHttpClient`.
|
|
210
|
+
Its calls go through `http.request`, so the client's middleware, retries and
|
|
211
|
+
timeouts apply. See [Setup](#setup).
|
|
212
|
+
|
|
213
|
+
| Option | Type | Default | Description |
|
|
214
|
+
| --- | --- | --- | --- |
|
|
215
|
+
| `http` | `HttpClient` | | the client whose calls the queries send |
|
|
216
|
+
| `options.scope` | `string` | none | put first in every key |
|
|
217
|
+
|
|
218
|
+
Returns an [`HttpQueries`](#httpqueries). Throws nothing.
|
|
219
|
+
|
|
220
|
+
#### The queries object
|
|
221
|
+
|
|
222
|
+
##### `queryOptions`
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
queryOptions<Path extends string, R extends Responses | undefined = undefined, Decoded extends boolean = true>(
|
|
226
|
+
method: Method,
|
|
227
|
+
path: Path,
|
|
228
|
+
...args: RequestArgs<Path, R, Decoded> // [options?], or [options] when the path has {name}s
|
|
229
|
+
): HttpQueryOptions<QueryData<R, Decoded>>;
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
The options of a query of one call. See [Queries](#queries).
|
|
233
|
+
|
|
234
|
+
| Option | Type | Default | Description |
|
|
235
|
+
| --- | --- | --- | --- |
|
|
236
|
+
| `method` | `Method` | | `'get'`, `'post'`, `'query'`… |
|
|
237
|
+
| `path` | `Path` | | the path, `{name}`s unfilled: `'/employees/{id}'` |
|
|
238
|
+
| `options` | `RequestOptions<Path, R, Decoded>` | | what the client's `request` takes: `param`, `query`, a body, `responses`, `decode`, and call options such as `signal` or `latest`. Required when the path has `{name}`s |
|
|
239
|
+
|
|
240
|
+
| Field | Type | Description |
|
|
241
|
+
| --- | --- | --- |
|
|
242
|
+
| `queryKey` | `HttpQueryKey<Data>` | `[scope?, method, path, input?]`, tagged with the data |
|
|
243
|
+
| `queryFn` | `({ signal }) => Promise<Data>` | sends the call with the query's `signal`, joined with the options' own |
|
|
244
|
+
|
|
245
|
+
The `queryFn` resolves to the data of a 2xx reply, and rejects with a
|
|
246
|
+
`ReplyStatusError` on any other, or with whatever the call throws:
|
|
247
|
+
`UndeclaredStatusError`, `ValidationError`, `TimeoutError`, an abort.
|
|
248
|
+
|
|
249
|
+
##### `infiniteQueryOptions`
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
infiniteQueryOptions<Path extends string, PageParam, R extends Responses | undefined = undefined, Decoded extends boolean = true>(
|
|
253
|
+
method: Method,
|
|
254
|
+
path: Path,
|
|
255
|
+
options: RequestOptions<Path, R, Decoded>,
|
|
256
|
+
paging: Paging<QueryData<R, Decoded>, PageParam>,
|
|
257
|
+
): HttpInfiniteQueryOptions<QueryData<R, Decoded>, PageParam>;
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
The options of an infinite query: each page is the call sent with its
|
|
261
|
+
`pageParam` as the query parameter `pageParamName`, left out when `null` or
|
|
262
|
+
`undefined`. See [Infinite queries](#infinite-queries).
|
|
263
|
+
|
|
264
|
+
| Option | Type | Default | Description |
|
|
265
|
+
| --- | --- | --- | --- |
|
|
266
|
+
| `method` | `Method` | | as `queryOptions` |
|
|
267
|
+
| `path` | `Path` | | as `queryOptions` |
|
|
268
|
+
| `options` | `RequestOptions<Path, R, Decoded>` | | as `queryOptions`, always given. Its `query` may be an object or a `URLSearchParams` |
|
|
269
|
+
| `paging` | [`Paging`](#paging) | | `pageParamName`, and TanStack's paging options |
|
|
270
|
+
|
|
271
|
+
| Field | Type | Description |
|
|
272
|
+
| --- | --- | --- |
|
|
273
|
+
| `queryKey` | `HttpQueryKey<InfiniteData<Data, PageParam>>` | the call's key, then `'infinite'` |
|
|
274
|
+
| `queryFn` | `({ signal, pageParam }) => Promise<Data>` | sends one page |
|
|
275
|
+
| `initialPageParam` | `PageParam` | from `paging` |
|
|
276
|
+
| `getNextPageParam` | `GetNextPageParamFunction<PageParam, Data>` | from `paging` |
|
|
277
|
+
| `getPreviousPageParam` | `GetPreviousPageParamFunction<PageParam, Data>` | from `paging`, when given |
|
|
278
|
+
| `maxPages` | `number` | from `paging`, when given |
|
|
279
|
+
|
|
280
|
+
Each page rejects as a `queryOptions` query does.
|
|
281
|
+
|
|
282
|
+
##### `mutationOptions`
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
mutationOptions<Path extends string, R extends Responses | undefined = undefined, Decoded extends boolean = true>(
|
|
286
|
+
method: Method,
|
|
287
|
+
path: Path,
|
|
288
|
+
options?: CallOptions & ReplyOptions<R, Decoded>,
|
|
289
|
+
): HttpMutationOptions<Path, QueryData<R, Decoded>>;
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The options of a mutation of one call, whose `mutate()` takes what each call
|
|
293
|
+
sends. See [Mutations](#mutations).
|
|
294
|
+
|
|
295
|
+
| Option | Type | Default | Description |
|
|
296
|
+
| --- | --- | --- | --- |
|
|
297
|
+
| `method` | `Method` | | as `queryOptions` |
|
|
298
|
+
| `path` | `Path` | | as `queryOptions` |
|
|
299
|
+
| `options` | `CallOptions & ReplyOptions<R, Decoded>` | none | what every call shares: `responses`, `validate`, `decode`, `headers`, `timeout`… |
|
|
300
|
+
|
|
301
|
+
| Field | Type | Description |
|
|
302
|
+
| --- | --- | --- |
|
|
303
|
+
| `mutationKey` | `readonly unknown[]` | `[scope?, method, path]` |
|
|
304
|
+
| `mutationFn` | `(variables: MutationVariables<Path>) => Promise<Data>` | sends the call with `options`, then `variables` over them. `variables` may be left out when the path has no `{name}`s |
|
|
305
|
+
|
|
306
|
+
The `mutationFn` rejects as a `queryOptions` query does. It is sent with no
|
|
307
|
+
signal of TanStack's: a mutation is not cancelled.
|
|
308
|
+
|
|
309
|
+
##### `queryKey`
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
queryKey(method: Method, path?: string, input?: KeyInput): readonly unknown[];
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
A key, or the start of one, for a filter: `[scope?, method, path?, input?]`,
|
|
316
|
+
built as the options' keys are. It is not tagged with any data. See
|
|
317
|
+
[Keys and filters](#keys-and-filters).
|
|
318
|
+
|
|
319
|
+
| Option | Type | Default | Description |
|
|
320
|
+
| --- | --- | --- | --- |
|
|
321
|
+
| `method` | `Method` | | the method |
|
|
322
|
+
| `path` | `string` | none | the path, `{name}`s unfilled |
|
|
323
|
+
| `input` | [`KeyInput`](#keyinput) | none | what the calls send: `param`, `query`, a body |
|
|
324
|
+
|
|
325
|
+
#### Types
|
|
326
|
+
|
|
327
|
+
##### `HttpQueries`
|
|
328
|
+
|
|
329
|
+
What `createQueries` returns: [`queryOptions`](#queryoptions),
|
|
330
|
+
[`infiniteQueryOptions`](#infinitequeryoptions),
|
|
331
|
+
[`mutationOptions`](#mutationoptions) and [`queryKey`](#querykey).
|
|
332
|
+
|
|
333
|
+
##### `QueriesOptions`
|
|
334
|
+
|
|
335
|
+
| Field | Type | Description |
|
|
336
|
+
| --- | --- | --- |
|
|
337
|
+
| `scope` | `string` | optional: put first in every key, `'catalog'` |
|
|
338
|
+
|
|
339
|
+
The second argument of `createQueries` and `createOpenApiQueries`.
|
|
340
|
+
|
|
341
|
+
##### `HttpQueryOptions`
|
|
342
|
+
|
|
343
|
+
```ts
|
|
344
|
+
interface HttpQueryOptions<Data> {
|
|
345
|
+
readonly queryKey: HttpQueryKey<Data>;
|
|
346
|
+
readonly queryFn: (context: { readonly signal: AbortSignal }) => Promise<Data>;
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
What `queryOptions` returns, in both entry points.
|
|
351
|
+
|
|
352
|
+
##### `HttpInfiniteQueryOptions`
|
|
353
|
+
|
|
354
|
+
```ts
|
|
355
|
+
interface HttpInfiniteQueryOptions<Data, PageParam> extends Omit<Paging<Data, PageParam>, 'pageParamName'> {
|
|
356
|
+
readonly queryKey: HttpQueryKey<InfiniteData<Data, PageParam>>;
|
|
357
|
+
readonly queryFn: (context: { readonly signal: AbortSignal; readonly pageParam: PageParam }) => Promise<Data>;
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
What `infiniteQueryOptions` returns, in both entry points.
|
|
362
|
+
|
|
363
|
+
##### `HttpMutationOptions`
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
interface HttpMutationOptions<Path extends string, Data> {
|
|
367
|
+
readonly mutationKey: readonly unknown[];
|
|
368
|
+
// MutationVariables<Path> | void when the path has no {name}s
|
|
369
|
+
readonly mutationFn: (variables: MutationVariables<Path>) => Promise<Data>;
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
What `mutationOptions` of `createQueries` returns.
|
|
374
|
+
|
|
375
|
+
##### `Paging`
|
|
376
|
+
|
|
377
|
+
| Field | Type | Description |
|
|
378
|
+
| --- | --- | --- |
|
|
379
|
+
| `pageParamName` | `string` | the query parameter each page's `pageParam` is sent as: `'after'`, `'page'` |
|
|
380
|
+
| `initialPageParam` | `PageParam` | the first page's param |
|
|
381
|
+
| `getNextPageParam` | `GetNextPageParamFunction<PageParam, Data>` | the next page's param, from the last page |
|
|
382
|
+
| `getPreviousPageParam` | `GetPreviousPageParamFunction<PageParam, Data>` | optional: the previous page's param |
|
|
383
|
+
| `maxPages` | `number` | optional: how many pages TanStack keeps |
|
|
384
|
+
|
|
385
|
+
The fourth argument of `infiniteQueryOptions`. In `./openapi`,
|
|
386
|
+
`pageParamName` is narrowed to the operation's query parameters.
|
|
387
|
+
|
|
388
|
+
##### `KeyInput`
|
|
389
|
+
|
|
390
|
+
| Field | Type | Description |
|
|
391
|
+
| --- | --- | --- |
|
|
392
|
+
| `param` | `{ readonly [name: string]: unknown }` | the path's parameters |
|
|
393
|
+
| `query` | `QueryInput` | the query: an object, or a `URLSearchParams` |
|
|
394
|
+
| `json` | `unknown` | a JSON body |
|
|
395
|
+
| `form` | `unknown` | a form body |
|
|
396
|
+
| `text` | `string` | a text body |
|
|
397
|
+
| `body` | `unknown` | a raw body |
|
|
398
|
+
|
|
399
|
+
What `queryKey` takes as its `input`, every field optional.
|
|
400
|
+
|
|
401
|
+
##### `HttpQueryKey`
|
|
402
|
+
|
|
403
|
+
A key tagged with its data, `DataTag<readonly unknown[], Data>`, which is
|
|
404
|
+
what types `queryClient.getQueryData(key)`.
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
const key: HttpQueryKey<Employee> = queries.queryOptions('get', '/employees/{id}', options).queryKey;
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
##### `QueryData`
|
|
411
|
+
|
|
412
|
+
The data of a call's 2xx replies, from its `responses` and whether it
|
|
413
|
+
decodes.
|
|
414
|
+
|
|
415
|
+
```ts
|
|
416
|
+
type Data = QueryData<{ 200: typeof Employee; 404: typeof Problem }, true>; // z.output<typeof Employee>
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
##### `MutationVariables`
|
|
420
|
+
|
|
421
|
+
What `mutate()` takes: what the call to `Path` sends, `RequestInput<Path>`,
|
|
422
|
+
and its `CallOptions`.
|
|
423
|
+
|
|
424
|
+
```ts
|
|
425
|
+
type Variables = MutationVariables<'/employees/{id}'>; // { param: { id }, query?, json?… } & CallOptions
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### `@nxgt/httpyz-query/openapi`
|
|
429
|
+
|
|
430
|
+
#### Functions
|
|
431
|
+
|
|
432
|
+
##### `createOpenApiQueries`
|
|
433
|
+
|
|
434
|
+
```ts
|
|
435
|
+
function createOpenApiQueries<Ops extends OperationsShape<Ops>, Routes, Decoded extends boolean>(
|
|
436
|
+
api: OpenApiClient<Ops, Routes, Decoded>,
|
|
437
|
+
options?: QueriesOptions,
|
|
438
|
+
): OpenApiQueries<Ops, Routes, Decoded>;
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
The options objects for the operations of `api`, a client of
|
|
442
|
+
`createOpenApiClient`, whose types it infers. It reads `api.operations` to
|
|
443
|
+
tell an operation's input from its init, as the client does: an operation
|
|
444
|
+
that takes nothing is called with its init alone. The calls are the client's
|
|
445
|
+
own, `api.get(path, …)` and the other methods. See
|
|
446
|
+
[With an OpenAPI spec](#with-an-openapi-spec).
|
|
447
|
+
|
|
448
|
+
| Option | Type | Default | Description |
|
|
449
|
+
| --- | --- | --- | --- |
|
|
450
|
+
| `api` | `OpenApiClient<Ops, Routes, Decoded>` | | the bound client |
|
|
451
|
+
| `options.scope` | `string` | none | put first in every key |
|
|
452
|
+
|
|
453
|
+
Returns an [`OpenApiQueries`](#openapiqueries). Throws nothing itself; its
|
|
454
|
+
members throw an `Error`, `The spec has no GET /x operation`, for a method
|
|
455
|
+
and path the spec has no operation at, which the types already refuse.
|
|
456
|
+
|
|
457
|
+
#### The queries object
|
|
458
|
+
|
|
459
|
+
##### `queryOptions`
|
|
460
|
+
|
|
461
|
+
```ts
|
|
462
|
+
queryOptions<M extends MethodsOf<Routes>, P extends PathsOf<Routes, M>>(
|
|
463
|
+
method: M,
|
|
464
|
+
path: P,
|
|
465
|
+
...args: Args<Ops, IdOf<Ops, Routes, M, P>> // [input, init?], or [init?] for an operation that takes nothing
|
|
466
|
+
): HttpQueryOptions<OperationData<Ops, IdOf<Ops, Routes, M, P>, Decoded>>;
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
The options of a query of the operation at `method` and `path`, taking what
|
|
470
|
+
`api[method](path, …)` takes.
|
|
471
|
+
|
|
472
|
+
| Option | Type | Default | Description |
|
|
473
|
+
| --- | --- | --- | --- |
|
|
474
|
+
| `method` | `MethodsOf<Routes>` | | a method the spec has an operation for |
|
|
475
|
+
| `path` | `PathsOf<Routes, M>` | | a path with an operation for that method |
|
|
476
|
+
| `input` | the operation's input | | `param`, `query`, `header`, a body. Absent for an operation that takes nothing |
|
|
477
|
+
| `init` | `OperationInit` | none | the core client's call options: `signal`, `timeout`, `headers`, `latest`… |
|
|
478
|
+
|
|
479
|
+
| Field | Type | Description |
|
|
480
|
+
| --- | --- | --- |
|
|
481
|
+
| `queryKey` | `HttpQueryKey<Data>` | `[scope?, method, path, input?]`: the input, never the init |
|
|
482
|
+
| `queryFn` | `({ signal }) => Promise<Data>` | calls the operation with the query's `signal`, joined with the init's own |
|
|
483
|
+
|
|
484
|
+
The `queryFn` resolves to the data of a 2xx reply, and rejects with a
|
|
485
|
+
`ReplyStatusError` on any other, or with whatever the call throws.
|
|
486
|
+
`queryOptions` throws at once for an operation the spec does not have.
|
|
487
|
+
|
|
488
|
+
##### `infiniteQueryOptions`
|
|
489
|
+
|
|
490
|
+
```ts
|
|
491
|
+
infiniteQueryOptions<M extends MethodsOf<Routes>, P extends PathsOf<Routes, M>, PageParam>(
|
|
492
|
+
method: M,
|
|
493
|
+
path: P,
|
|
494
|
+
input: Ops[IdOf<Ops, Routes, M, P>]['args'][0],
|
|
495
|
+
paging: Omit<Paging<Data, PageParam>, 'pageParamName'> & { readonly pageParamName: QueryNames<Input> },
|
|
496
|
+
init?: OperationInit,
|
|
497
|
+
): HttpInfiniteQueryOptions<Data, PageParam>;
|
|
498
|
+
// Input: Ops[IdOf<Ops, Routes, M, P>]['args'][0]; Data: OperationData<Ops, IdOf<Ops, Routes, M, P>, Decoded>
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
The options of an infinite query of an operation, each page sent with its
|
|
502
|
+
`pageParam` as one of the operation's query parameters.
|
|
503
|
+
|
|
504
|
+
| Option | Type | Default | Description |
|
|
505
|
+
| --- | --- | --- | --- |
|
|
506
|
+
| `method` | `MethodsOf<Routes>` | | as `queryOptions` |
|
|
507
|
+
| `path` | `PathsOf<Routes, M>` | | as `queryOptions` |
|
|
508
|
+
| `input` | the operation's input | | as `queryOptions`, always given |
|
|
509
|
+
| `paging` | [`Paging`](#paging) | | `pageParamName` is one of the input's query parameters |
|
|
510
|
+
| `init` | `OperationInit` | none | the call options every page is sent with |
|
|
511
|
+
|
|
512
|
+
Returns the fields of [`infiniteQueryOptions`](#infinitequeryoptions) above.
|
|
513
|
+
A page of an operation the spec does not have rejects when it is fetched.
|
|
514
|
+
|
|
515
|
+
##### `mutationOptions`
|
|
516
|
+
|
|
517
|
+
```ts
|
|
518
|
+
mutationOptions<M extends MethodsOf<Routes>, P extends PathsOf<Routes, M>>(
|
|
519
|
+
method: M,
|
|
520
|
+
path: P,
|
|
521
|
+
init?: OperationInit,
|
|
522
|
+
): OpenApiMutationOptions<
|
|
523
|
+
OperationVariables<Ops[IdOf<Ops, Routes, M, P>]['args']>,
|
|
524
|
+
OperationData<Ops, IdOf<Ops, Routes, M, P>, Decoded>
|
|
525
|
+
>;
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
The options of a mutation of an operation, whose `mutate()` takes its input.
|
|
529
|
+
|
|
530
|
+
| Option | Type | Default | Description |
|
|
531
|
+
| --- | --- | --- | --- |
|
|
532
|
+
| `method` | `MethodsOf<Routes>` | | as `queryOptions` |
|
|
533
|
+
| `path` | `PathsOf<Routes, M>` | | as `queryOptions` |
|
|
534
|
+
| `init` | `OperationInit` | none | the call options every call shares |
|
|
535
|
+
|
|
536
|
+
| Field | Type | Description |
|
|
537
|
+
| --- | --- | --- |
|
|
538
|
+
| `mutationKey` | `readonly unknown[]` | `[scope?, method, path]` |
|
|
539
|
+
| `mutationFn` | `(variables: OperationVariables<Args>) => Promise<Data>` | calls the operation with `variables` as its input, and `init` |
|
|
540
|
+
|
|
541
|
+
The `mutationFn` rejects as a query does, and is sent with no signal of
|
|
542
|
+
TanStack's. `mutationOptions` throws at once for an operation the spec does
|
|
543
|
+
not have.
|
|
544
|
+
|
|
545
|
+
##### `queryKey`
|
|
546
|
+
|
|
547
|
+
```ts
|
|
548
|
+
queryKey(method: Method, path?: string, input?: KeyInput): readonly unknown[];
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
As [`queryKey`](#querykey) of `createQueries`: any method and path, untyped
|
|
552
|
+
by the spec.
|
|
553
|
+
|
|
554
|
+
#### Types
|
|
555
|
+
|
|
556
|
+
`QueriesOptions`, `HttpQueryOptions`, `HttpInfiniteQueryOptions`, `Paging`
|
|
557
|
+
and `KeyInput` are exported from `@nxgt/httpyz-query`.
|
|
558
|
+
|
|
559
|
+
##### `OpenApiQueries`
|
|
560
|
+
|
|
561
|
+
What `createOpenApiQueries` returns: [`queryOptions`](#queryoptions-1),
|
|
562
|
+
[`infiniteQueryOptions`](#infinitequeryoptions-1),
|
|
563
|
+
[`mutationOptions`](#mutationoptions-1) and [`queryKey`](#querykey-1), typed
|
|
564
|
+
by the client's `Ops`, `Routes` and `Decoded`.
|
|
565
|
+
|
|
566
|
+
##### `OpenApiMutationOptions`
|
|
567
|
+
|
|
568
|
+
```ts
|
|
569
|
+
interface OpenApiMutationOptions<Variables, Data> {
|
|
570
|
+
readonly mutationKey: readonly unknown[];
|
|
571
|
+
readonly mutationFn: (variables: Variables) => Promise<Data>;
|
|
572
|
+
}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
What `mutationOptions` of `createOpenApiQueries` returns.
|
|
576
|
+
|
|
577
|
+
##### `OperationData`
|
|
578
|
+
|
|
579
|
+
The data of an operation's 2xx replies, decoded when `Decoded` is `true`.
|
|
580
|
+
|
|
581
|
+
```ts
|
|
582
|
+
type Employee = OperationData<ClientOperations, 'getEmployee', false>;
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
##### `OperationVariables`
|
|
586
|
+
|
|
587
|
+
What `mutate()` takes, from an operation's arguments: `void` when it takes
|
|
588
|
+
nothing, its input, or its input or nothing when none of it is required.
|
|
589
|
+
|
|
590
|
+
```ts
|
|
591
|
+
type Variables = OperationVariables<ClientOperations['deleteEmployee']['args']>; // { param: { id: number } }
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
##### `QueryNames`
|
|
595
|
+
|
|
596
|
+
The names of the query parameters of an operation's input: what
|
|
597
|
+
`pageParamName` may be.
|
|
598
|
+
|
|
599
|
+
```ts
|
|
600
|
+
type Names = QueryNames<{ query?: { first?: number; after?: string } }>; // 'first' | 'after'
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
## Traps
|
|
604
|
+
|
|
605
|
+
- **A binary body is not told apart in a key.** A `Blob` or a stream hashes
|
|
606
|
+
as `{}`: give such a query a `queryKey` of your own after the spread.
|
|
607
|
+
- **A status the call does not declare fails differently.** A declared
|
|
608
|
+
non-2xx reply fails the query with a `ReplyStatusError`, but one missing
|
|
609
|
+
from `responses` throws the client's `UndeclaredStatusError` first: declare
|
|
610
|
+
every status the API replies with.
|
|
611
|
+
- **`queryKey()` is not tagged.** `queryClient.getQueryData(queries.queryKey(...))`
|
|
612
|
+
is `unknown`: read the cache with the options' own `queryKey`.
|
|
613
|
+
- **Set `initialPageParam`'s type.** `null` alone types every page param as
|
|
614
|
+
`null`: `null as string | null`.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { createQueries } from './queries/create-queries';
|
|
2
|
+
export type { HttpInfiniteQueryOptions, HttpMutationOptions, HttpQueries, HttpQueryKey, HttpQueryOptions, KeyInput, MutationVariables, Paging, QueriesOptions, QueryData, } from './queries/types';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,YAAY,EACX,wBAAwB,EACxB,mBAAmB,EACnB,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,QAAQ,EACR,iBAAiB,EACjB,MAAM,EACN,cAAc,EACd,SAAS,GACT,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// src/queries/create-queries.ts
|
|
2
|
+
import { ok } from "@nxgt/httpyz";
|
|
3
|
+
|
|
4
|
+
// src/key/key.ts
|
|
5
|
+
var joined = (given, query) => given ? AbortSignal.any([given, query]) : query;
|
|
6
|
+
var hashable = (value) => value instanceof URLSearchParams || typeof FormData !== "undefined" && value instanceof FormData ? [...value.entries()] : value;
|
|
7
|
+
var PARTS = [
|
|
8
|
+
"param",
|
|
9
|
+
"query",
|
|
10
|
+
"header",
|
|
11
|
+
"json",
|
|
12
|
+
"form",
|
|
13
|
+
"text",
|
|
14
|
+
"body"
|
|
15
|
+
];
|
|
16
|
+
function keyed(input) {
|
|
17
|
+
if (!input)
|
|
18
|
+
return;
|
|
19
|
+
const given = input;
|
|
20
|
+
const key = {};
|
|
21
|
+
for (const part of PARTS) {
|
|
22
|
+
if (given[part] !== undefined)
|
|
23
|
+
key[part] = hashable(given[part]);
|
|
24
|
+
}
|
|
25
|
+
if (given.decode === false)
|
|
26
|
+
key.decode = false;
|
|
27
|
+
return Object.keys(key).length > 0 ? key : undefined;
|
|
28
|
+
}
|
|
29
|
+
function keyOf(scope, method, path, input) {
|
|
30
|
+
const key = scope === undefined ? [method] : [scope, method];
|
|
31
|
+
if (path !== undefined)
|
|
32
|
+
key.push(path);
|
|
33
|
+
const rest = keyed(input);
|
|
34
|
+
if (rest !== undefined)
|
|
35
|
+
key.push(rest);
|
|
36
|
+
return key;
|
|
37
|
+
}
|
|
38
|
+
function paged(input, name, pageParam) {
|
|
39
|
+
const given = input?.query;
|
|
40
|
+
if (given instanceof URLSearchParams) {
|
|
41
|
+
const query = new URLSearchParams(given);
|
|
42
|
+
if (pageParam === null || pageParam === undefined)
|
|
43
|
+
query.delete(name);
|
|
44
|
+
else
|
|
45
|
+
query.set(name, String(pageParam));
|
|
46
|
+
return { ...input, query };
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
...input,
|
|
50
|
+
query: { ...given, [name]: pageParam }
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/queries/create-queries.ts
|
|
55
|
+
function createQueries(http, { scope } = {}) {
|
|
56
|
+
const send = http.request;
|
|
57
|
+
const queryKey = (method, path, input) => keyOf(scope, method, path, input);
|
|
58
|
+
const call = (method, path, options, signal) => send(method, path, {
|
|
59
|
+
...options,
|
|
60
|
+
signal: joined(options?.signal, signal)
|
|
61
|
+
}).then(ok);
|
|
62
|
+
return {
|
|
63
|
+
queryKey,
|
|
64
|
+
queryOptions: (method, path, options) => ({
|
|
65
|
+
queryKey: queryKey(method, path, options),
|
|
66
|
+
queryFn: ({ signal }) => call(method, path, options, signal)
|
|
67
|
+
}),
|
|
68
|
+
infiniteQueryOptions: (method, path, options, { pageParamName, ...paging }) => ({
|
|
69
|
+
...paging,
|
|
70
|
+
queryKey: [...queryKey(method, path, options), "infinite"],
|
|
71
|
+
queryFn: ({
|
|
72
|
+
signal,
|
|
73
|
+
pageParam
|
|
74
|
+
}) => call(method, path, paged(options, pageParamName, pageParam), signal)
|
|
75
|
+
}),
|
|
76
|
+
mutationOptions: (method, path, options) => ({
|
|
77
|
+
mutationKey: queryKey(method, path),
|
|
78
|
+
mutationFn: (variables) => send(method, path, { ...options, ...variables || {} }).then(ok)
|
|
79
|
+
})
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
createQueries
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
//# debugId=E5A4FC415731130364756E2164756E21
|
|
87
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/queries/create-queries.ts", "../src/key/key.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * `createQueries`: TanStack Query options for the calls of a client of\n * `createHttpClient`. It adds no runtime of TanStack's: each function returns\n * a plain object, whose `queryFn` sends the call with the query's `signal`.\n */\nimport { type HttpClient, type Method, ok } from '@nxgt/httpyz';\nimport { joined, keyOf, paged } from '../key/key';\nimport type { HttpQueries, KeyInput, Paging, QueriesOptions } from './types';\n\ntype Send = (\n\tmethod: Method,\n\tpath: string,\n\toptions: object,\n) => Promise<{ readonly status: number; readonly data: unknown }>;\n\ntype Options = KeyInput & { readonly signal?: AbortSignal | null };\n\n/**\n * TanStack Query options for the calls of `http`.\n *\n * ```ts\n * const queries = createQueries(http);\n * const { data } = useQuery(\n * queries.queryOptions('get', '/items/{id}', { param: { id }, responses: { 200: Item } }),\n * );\n * ```\n */\nexport function createQueries(\n\thttp: HttpClient,\n\t{ scope }: QueriesOptions = {},\n): HttpQueries {\n\tconst send = http.request as unknown as Send;\n\tconst queryKey = (method: Method, path?: string, input?: KeyInput) =>\n\t\tkeyOf(scope, method, path, input);\n\tconst call = (\n\t\tmethod: Method,\n\t\tpath: string,\n\t\toptions: Options | undefined,\n\t\tsignal: AbortSignal,\n\t) =>\n\t\tsend(method, path, {\n\t\t\t...options,\n\t\t\tsignal: joined(options?.signal, signal),\n\t\t}).then(ok);\n\n\treturn {\n\t\tqueryKey,\n\t\tqueryOptions: (method: Method, path: string, options?: Options) => ({\n\t\t\tqueryKey: queryKey(method, path, options),\n\t\t\tqueryFn: ({ signal }: { signal: AbortSignal }) =>\n\t\t\t\tcall(method, path, options, signal),\n\t\t}),\n\t\tinfiniteQueryOptions: (\n\t\t\tmethod: Method,\n\t\t\tpath: string,\n\t\t\toptions: Options,\n\t\t\t{ pageParamName, ...paging }: Paging<unknown, unknown>,\n\t\t) => ({\n\t\t\t...paging,\n\t\t\t// Apart from the query of the same call, whose data is one page, not all of them.\n\t\t\tqueryKey: [...queryKey(method, path, options), 'infinite'],\n\t\t\tqueryFn: ({\n\t\t\t\tsignal,\n\t\t\t\tpageParam,\n\t\t\t}: {\n\t\t\t\tsignal: AbortSignal;\n\t\t\t\tpageParam: unknown;\n\t\t\t}) =>\n\t\t\t\tcall(method, path, paged(options, pageParamName, pageParam), signal),\n\t\t}),\n\t\tmutationOptions: (method: Method, path: string, options?: object) => ({\n\t\t\tmutationKey: queryKey(method, path),\n\t\t\tmutationFn: (variables: object | undefined) =>\n\t\t\t\tsend(method, path, { ...options, ...(variables || {}) }).then(ok),\n\t\t}),\n\t} as unknown as HttpQueries;\n}\n",
|
|
6
|
+
"/** What the keys and calls of both entry points share. */\n\n/** Both signals: the call ends on either. */\nexport const joined = (\n\tgiven: AbortSignal | null | undefined,\n\tquery: AbortSignal,\n): AbortSignal => (given ? AbortSignal.any([given, query]) : query);\n\n/** A value TanStack hashes as it is: a `URLSearchParams` or `FormData` as its entries. */\nconst hashable = (value: unknown): unknown =>\n\tvalue instanceof URLSearchParams ||\n\t(typeof FormData !== 'undefined' && value instanceof FormData)\n\t\t? [...value.entries()]\n\t\t: value;\n\n/** The parts of an input that tell two calls to one path apart. */\nconst PARTS = [\n\t'param',\n\t'query',\n\t'header',\n\t'json',\n\t'form',\n\t'text',\n\t'body',\n] as const;\n\n/** What tells two calls to one path apart: what they send, and `decode: false`. */\nfunction keyed(input: object | undefined): object | undefined {\n\tif (!input) return undefined;\n\tconst given = input as { readonly [part: string]: unknown };\n\tconst key: Record<string, unknown> = {};\n\tfor (const part of PARTS) {\n\t\tif (given[part] !== undefined) key[part] = hashable(given[part]);\n\t}\n\tif (given.decode === false) key.decode = false;\n\treturn Object.keys(key).length > 0 ? key : undefined;\n}\n\n/** A key, or the start of one: `[scope?, method, path?, input?]`. */\nexport function keyOf(\n\tscope: string | undefined,\n\tmethod: string,\n\tpath?: string,\n\tinput?: object,\n): unknown[] {\n\tconst key: unknown[] = scope === undefined ? [method] : [scope, method];\n\tif (path !== undefined) key.push(path);\n\tconst rest = keyed(input);\n\tif (rest !== undefined) key.push(rest);\n\treturn key;\n}\n\n/** `input` with `pageParam` as its query parameter `name`: left out when `null`. */\nexport function paged<Input extends { readonly query?: unknown }>(\n\tinput: Input | undefined,\n\tname: string,\n\tpageParam: unknown,\n): Input {\n\tconst given = input?.query;\n\tif (given instanceof URLSearchParams) {\n\t\tconst query = new URLSearchParams(given);\n\t\tif (pageParam === null || pageParam === undefined) query.delete(name);\n\t\telse query.set(name, String(pageParam));\n\t\treturn { ...input, query } as Input;\n\t}\n\treturn {\n\t\t...input,\n\t\tquery: { ...(given as object | undefined), [name]: pageParam },\n\t} as Input;\n}\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "E5A4FC415731130364756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** What the keys and calls of both entry points share. */
|
|
2
|
+
/** Both signals: the call ends on either. */
|
|
3
|
+
export declare const joined: (given: AbortSignal | null | undefined, query: AbortSignal) => AbortSignal;
|
|
4
|
+
/** A key, or the start of one: `[scope?, method, path?, input?]`. */
|
|
5
|
+
export declare function keyOf(scope: string | undefined, method: string, path?: string, input?: object): unknown[];
|
|
6
|
+
/** `input` with `pageParam` as its query parameter `name`: left out when `null`. */
|
|
7
|
+
export declare function paged<Input extends {
|
|
8
|
+
readonly query?: unknown;
|
|
9
|
+
}>(input: Input | undefined, name: string, pageParam: unknown): Input;
|
|
10
|
+
//# sourceMappingURL=key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key.d.ts","sourceRoot":"","sources":["../../src/key/key.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAE1D,6CAA6C;AAC7C,eAAO,MAAM,MAAM,GAClB,OAAO,WAAW,GAAG,IAAI,GAAG,SAAS,EACrC,OAAO,WAAW,KAChB,WAAgE,CAAC;AAgCpE,qEAAqE;AACrE,wBAAgB,KAAK,CACpB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,MAAM,GACZ,OAAO,EAAE,CAMX;AAED,oFAAoF;AACpF,wBAAgB,KAAK,CAAC,KAAK,SAAS;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,EAC/D,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,OAAO,GAChB,KAAK,CAYP"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { OpenApiClient, OperationsShape } from '@nxgt/openapi-httpyz';
|
|
2
|
+
import type { QueriesOptions } from '../queries/types';
|
|
3
|
+
import type { OpenApiQueries } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* TanStack Query options for the operations of `api`. The client's own
|
|
6
|
+
* `operations` tell an operation's input from its init, as they do for its
|
|
7
|
+
* calls: one that takes nothing is called with its init alone.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* const queries = createOpenApiQueries(api);
|
|
11
|
+
* const { data } = useQuery(queries.queryOptions('get', '/employees/{id}', { param: { id } }));
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare function createOpenApiQueries<Ops extends OperationsShape<Ops>, Routes, Decoded extends boolean>(api: OpenApiClient<Ops, Routes, Decoded>, { scope }?: QueriesOptions): OpenApiQueries<Ops, Routes, Decoded>;
|
|
15
|
+
//# sourceMappingURL=create-openapi-queries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-openapi-queries.d.ts","sourceRoot":"","sources":["../../src/openapi/create-openapi-queries.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACX,aAAa,EAEb,eAAe,EAEf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAO9C;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CACnC,GAAG,SAAS,eAAe,CAAC,GAAG,CAAC,EAChC,MAAM,EACN,OAAO,SAAS,OAAO,EAEvB,GAAG,EAAE,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EACxC,EAAE,KAAK,EAAE,GAAE,cAAmB,GAC5B,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAwFtC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** The options `createOpenApiQueries()` returns, typed by the generated spec. */
|
|
2
|
+
import type { Method, Success } from '@nxgt/httpyz';
|
|
3
|
+
import type { Args, IdOf, MethodsOf, OperationInit, OperationReply, OperationsShape, PathsOf } from '@nxgt/openapi-httpyz';
|
|
4
|
+
import type { HttpInfiniteQueryOptions, HttpQueryOptions, KeyInput, Paging } from '../queries/types';
|
|
5
|
+
/** Each reply's `data`. */
|
|
6
|
+
type DataOf<Reply> = Reply extends {
|
|
7
|
+
readonly data: infer Data;
|
|
8
|
+
} ? Data : never;
|
|
9
|
+
/** What a query of an operation resolves to: the data of its 2xx replies. */
|
|
10
|
+
export type OperationData<Ops extends OperationsShape<Ops>, K extends keyof Ops, Decoded extends boolean> = DataOf<Success<OperationReply<Ops, K, Decoded>>>;
|
|
11
|
+
/** An operation's input: `void` when it takes none, and may be left out when nothing in it is required. */
|
|
12
|
+
export type OperationVariables<Args> = Args extends readonly [] ? void : Args extends readonly [infer Input] ? Input : Args extends readonly [(infer Input)?] ? // biome-ignore lint/suspicious/noConfusingVoidType: void, not undefined, is what lets `mutate()` be called with nothing
|
|
13
|
+
Input | void : never;
|
|
14
|
+
/** The query parameters of an operation's input. */
|
|
15
|
+
export type QueryNames<Input> = Input extends {
|
|
16
|
+
readonly query?: infer Query;
|
|
17
|
+
} ? keyof NonNullable<Query> & string : never;
|
|
18
|
+
export interface OpenApiMutationOptions<Variables, Data> {
|
|
19
|
+
readonly mutationKey: readonly unknown[];
|
|
20
|
+
readonly mutationFn: (variables: Variables) => Promise<Data>;
|
|
21
|
+
}
|
|
22
|
+
export type OpenApiQueries<Ops extends OperationsShape<Ops>, Routes, Decoded extends boolean> = {
|
|
23
|
+
/**
|
|
24
|
+
* A query of the operation at a path, taking what `api.get(path, ...)`
|
|
25
|
+
* takes. It resolves to the data of a 2xx reply, and throws a
|
|
26
|
+
* `ReplyStatusError` for any other.
|
|
27
|
+
*/
|
|
28
|
+
queryOptions<M extends MethodsOf<Routes>, P extends PathsOf<Routes, M>>(method: M, path: P, ...args: Args<Ops, IdOf<Ops, Routes, M, P>>): HttpQueryOptions<OperationData<Ops, IdOf<Ops, Routes, M, P>, Decoded>>;
|
|
29
|
+
/** An infinite query of an operation: each page sent with its `pageParam` as one of its query parameters. */
|
|
30
|
+
infiniteQueryOptions<M extends MethodsOf<Routes>, P extends PathsOf<Routes, M>, PageParam>(method: M, path: P, input: Ops[IdOf<Ops, Routes, M, P>]['args'][0], paging: Omit<Paging<OperationData<Ops, IdOf<Ops, Routes, M, P>, Decoded>, PageParam>, 'pageParamName'> & {
|
|
31
|
+
readonly pageParamName: QueryNames<Ops[IdOf<Ops, Routes, M, P>]['args'][0]>;
|
|
32
|
+
}, init?: OperationInit): HttpInfiniteQueryOptions<OperationData<Ops, IdOf<Ops, Routes, M, P>, Decoded>, PageParam>;
|
|
33
|
+
/**
|
|
34
|
+
* A mutation of the operation at a path, whose `mutate()` takes its input.
|
|
35
|
+
* `init` holds what every call shares.
|
|
36
|
+
*/
|
|
37
|
+
mutationOptions<M extends MethodsOf<Routes>, P extends PathsOf<Routes, M>>(method: M, path: P, init?: OperationInit): OpenApiMutationOptions<OperationVariables<Ops[IdOf<Ops, Routes, M, P>]['args']>, OperationData<Ops, IdOf<Ops, Routes, M, P>, Decoded>>;
|
|
38
|
+
/** A key, or the start of one, for a filter: `queries.queryKey('get', '/items')`. */
|
|
39
|
+
queryKey(method: Method, path?: string, input?: KeyInput): readonly unknown[];
|
|
40
|
+
};
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/openapi/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,YAAY,EACX,sBAAsB,EACtB,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,UAAU,GACV,MAAM,iBAAiB,CAAC"}
|
package/dist/openapi.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// src/openapi/create-openapi-queries.ts
|
|
2
|
+
import { ok } from "@nxgt/httpyz";
|
|
3
|
+
|
|
4
|
+
// src/key/key.ts
|
|
5
|
+
var joined = (given, query) => given ? AbortSignal.any([given, query]) : query;
|
|
6
|
+
var hashable = (value) => value instanceof URLSearchParams || typeof FormData !== "undefined" && value instanceof FormData ? [...value.entries()] : value;
|
|
7
|
+
var PARTS = [
|
|
8
|
+
"param",
|
|
9
|
+
"query",
|
|
10
|
+
"header",
|
|
11
|
+
"json",
|
|
12
|
+
"form",
|
|
13
|
+
"text",
|
|
14
|
+
"body"
|
|
15
|
+
];
|
|
16
|
+
function keyed(input) {
|
|
17
|
+
if (!input)
|
|
18
|
+
return;
|
|
19
|
+
const given = input;
|
|
20
|
+
const key = {};
|
|
21
|
+
for (const part of PARTS) {
|
|
22
|
+
if (given[part] !== undefined)
|
|
23
|
+
key[part] = hashable(given[part]);
|
|
24
|
+
}
|
|
25
|
+
if (given.decode === false)
|
|
26
|
+
key.decode = false;
|
|
27
|
+
return Object.keys(key).length > 0 ? key : undefined;
|
|
28
|
+
}
|
|
29
|
+
function keyOf(scope, method, path, input) {
|
|
30
|
+
const key = scope === undefined ? [method] : [scope, method];
|
|
31
|
+
if (path !== undefined)
|
|
32
|
+
key.push(path);
|
|
33
|
+
const rest = keyed(input);
|
|
34
|
+
if (rest !== undefined)
|
|
35
|
+
key.push(rest);
|
|
36
|
+
return key;
|
|
37
|
+
}
|
|
38
|
+
function paged(input, name, pageParam) {
|
|
39
|
+
const given = input?.query;
|
|
40
|
+
if (given instanceof URLSearchParams) {
|
|
41
|
+
const query = new URLSearchParams(given);
|
|
42
|
+
if (pageParam === null || pageParam === undefined)
|
|
43
|
+
query.delete(name);
|
|
44
|
+
else
|
|
45
|
+
query.set(name, String(pageParam));
|
|
46
|
+
return { ...input, query };
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
...input,
|
|
50
|
+
query: { ...given, [name]: pageParam }
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/openapi/create-openapi-queries.ts
|
|
55
|
+
function createOpenApiQueries(api, { scope } = {}) {
|
|
56
|
+
const takes = new Map;
|
|
57
|
+
for (const operation of Object.values(api.operations)) {
|
|
58
|
+
takes.set(`${operation.method} ${operation.path}`, operation.parameters.length > 0 || Object.keys(operation.body?.content ?? {}).length > 0);
|
|
59
|
+
}
|
|
60
|
+
const takesInput = (method, path) => {
|
|
61
|
+
const found = takes.get(`${method} ${path}`);
|
|
62
|
+
if (found === undefined) {
|
|
63
|
+
throw new Error(`The spec has no ${method.toUpperCase()} ${path} operation`);
|
|
64
|
+
}
|
|
65
|
+
return found;
|
|
66
|
+
};
|
|
67
|
+
const split = (method, path, args) => takesInput(method, path) ? { input: args[0], init: args[1] } : { input: undefined, init: args[0] };
|
|
68
|
+
const call = (method, path, input, init, signal) => {
|
|
69
|
+
const sent = signal ? { ...init, signal: joined(init?.signal, signal) } : init;
|
|
70
|
+
const at = api[method];
|
|
71
|
+
return (takesInput(method, path) ? at(path, input, sent) : at(path, sent)).then(ok);
|
|
72
|
+
};
|
|
73
|
+
const queryKey = (method, path, input) => keyOf(scope, method, path, input);
|
|
74
|
+
return {
|
|
75
|
+
queryKey,
|
|
76
|
+
queryOptions: (method, path, ...args) => {
|
|
77
|
+
const { input, init } = split(method, path, args);
|
|
78
|
+
return {
|
|
79
|
+
queryKey: queryKey(method, path, input),
|
|
80
|
+
queryFn: ({ signal }) => call(method, path, input, init, signal)
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
infiniteQueryOptions: (method, path, input, { pageParamName, ...paging }, init) => ({
|
|
84
|
+
...paging,
|
|
85
|
+
queryKey: [...queryKey(method, path, input), "infinite"],
|
|
86
|
+
queryFn: ({
|
|
87
|
+
signal,
|
|
88
|
+
pageParam
|
|
89
|
+
}) => call(method, path, paged(input, pageParamName, pageParam), init, signal)
|
|
90
|
+
}),
|
|
91
|
+
mutationOptions: (method, path, init) => {
|
|
92
|
+
takesInput(method, path);
|
|
93
|
+
return {
|
|
94
|
+
mutationKey: queryKey(method, path),
|
|
95
|
+
mutationFn: (input) => call(method, path, input || undefined, init)
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export {
|
|
101
|
+
createOpenApiQueries
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
//# debugId=21510642E24588C464756E2164756E21
|
|
105
|
+
//# sourceMappingURL=openapi.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/openapi/create-openapi-queries.ts", "../src/key/key.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * `createOpenApiQueries`: TanStack Query options for the operations of a\n * client bound to a generated spec by `@nxgt/openapi-httpyz`. It imports that\n * package's types only: the calls are the bound client's own.\n */\nimport { type Method, ok } from '@nxgt/httpyz';\nimport type {\n\tOpenApiClient,\n\tOperationInit,\n\tOperationsShape,\n\tRuntimeOperation,\n} from '@nxgt/openapi-httpyz';\nimport { joined, keyOf, paged } from '../key/key';\nimport type { KeyInput, Paging, QueriesOptions } from '../queries/types';\nimport type { OpenApiQueries } from './types';\n\ntype Call = (\n\tpath: string,\n\t...args: unknown[]\n) => Promise<{ readonly status: number; readonly data: unknown }>;\n\n/**\n * TanStack Query options for the operations of `api`. The client's own\n * `operations` tell an operation's input from its init, as they do for its\n * calls: one that takes nothing is called with its init alone.\n *\n * ```ts\n * const queries = createOpenApiQueries(api);\n * const { data } = useQuery(queries.queryOptions('get', '/employees/{id}', { param: { id } }));\n * ```\n */\nexport function createOpenApiQueries<\n\tOps extends OperationsShape<Ops>,\n\tRoutes,\n\tDecoded extends boolean,\n>(\n\tapi: OpenApiClient<Ops, Routes, Decoded>,\n\t{ scope }: QueriesOptions = {},\n): OpenApiQueries<Ops, Routes, Decoded> {\n\t// As the bound client reads its arguments: an operation that takes nothing has no input.\n\tconst takes = new Map<string, boolean>();\n\tfor (const operation of Object.values<RuntimeOperation>(\n\t\tapi.operations as unknown as { readonly [id: string]: RuntimeOperation },\n\t)) {\n\t\ttakes.set(\n\t\t\t`${operation.method} ${operation.path}`,\n\t\t\toperation.parameters.length > 0 ||\n\t\t\t\tObject.keys(operation.body?.content ?? {}).length > 0,\n\t\t);\n\t}\n\tconst takesInput = (method: Method, path: string): boolean => {\n\t\tconst found = takes.get(`${method} ${path}`);\n\t\tif (found === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`The spec has no ${method.toUpperCase()} ${path} operation`,\n\t\t\t);\n\t\t}\n\t\treturn found;\n\t};\n\t/** The input and the init of a call's arguments. */\n\tconst split = (method: Method, path: string, args: readonly unknown[]) =>\n\t\ttakesInput(method, path)\n\t\t\t? { input: args[0] as object | undefined, init: args[1] as OperationInit }\n\t\t\t: { input: undefined, init: args[0] as OperationInit };\n\tconst call = (\n\t\tmethod: Method,\n\t\tpath: string,\n\t\tinput: object | undefined,\n\t\tinit: OperationInit | undefined,\n\t\tsignal?: AbortSignal,\n\t) => {\n\t\tconst sent = signal\n\t\t\t? { ...init, signal: joined(init?.signal, signal) }\n\t\t\t: init;\n\t\tconst at = (api as unknown as Record<Method, Call>)[method];\n\t\treturn (\n\t\t\ttakesInput(method, path) ? at(path, input, sent) : at(path, sent)\n\t\t).then(ok);\n\t};\n\tconst queryKey = (method: Method, path?: string, input?: KeyInput) =>\n\t\tkeyOf(scope, method, path, input);\n\n\treturn {\n\t\tqueryKey,\n\t\tqueryOptions: (method: Method, path: string, ...args: unknown[]) => {\n\t\t\tconst { input, init } = split(method, path, args);\n\t\t\treturn {\n\t\t\t\tqueryKey: queryKey(method, path, input),\n\t\t\t\tqueryFn: ({ signal }: { signal: AbortSignal }) =>\n\t\t\t\t\tcall(method, path, input, init, signal),\n\t\t\t};\n\t\t},\n\t\tinfiniteQueryOptions: (\n\t\t\tmethod: Method,\n\t\t\tpath: string,\n\t\t\tinput: object | undefined,\n\t\t\t{ pageParamName, ...paging }: Paging<unknown, unknown>,\n\t\t\tinit?: OperationInit,\n\t\t) => ({\n\t\t\t...paging,\n\t\t\t// Apart from the query of the same call, whose data is one page, not all of them.\n\t\t\tqueryKey: [...queryKey(method, path, input), 'infinite'],\n\t\t\tqueryFn: ({\n\t\t\t\tsignal,\n\t\t\t\tpageParam,\n\t\t\t}: {\n\t\t\t\tsignal: AbortSignal;\n\t\t\t\tpageParam: unknown;\n\t\t\t}) =>\n\t\t\t\tcall(\n\t\t\t\t\tmethod,\n\t\t\t\t\tpath,\n\t\t\t\t\tpaged(input, pageParamName, pageParam),\n\t\t\t\t\tinit,\n\t\t\t\t\tsignal,\n\t\t\t\t),\n\t\t}),\n\t\tmutationOptions: (method: Method, path: string, init?: OperationInit) => {\n\t\t\ttakesInput(method, path);\n\t\t\treturn {\n\t\t\t\tmutationKey: queryKey(method, path),\n\t\t\t\tmutationFn: (input: object | undefined) =>\n\t\t\t\t\tcall(method, path, input || undefined, init),\n\t\t\t};\n\t\t},\n\t} as unknown as OpenApiQueries<Ops, Routes, Decoded>;\n}\n",
|
|
6
|
+
"/** What the keys and calls of both entry points share. */\n\n/** Both signals: the call ends on either. */\nexport const joined = (\n\tgiven: AbortSignal | null | undefined,\n\tquery: AbortSignal,\n): AbortSignal => (given ? AbortSignal.any([given, query]) : query);\n\n/** A value TanStack hashes as it is: a `URLSearchParams` or `FormData` as its entries. */\nconst hashable = (value: unknown): unknown =>\n\tvalue instanceof URLSearchParams ||\n\t(typeof FormData !== 'undefined' && value instanceof FormData)\n\t\t? [...value.entries()]\n\t\t: value;\n\n/** The parts of an input that tell two calls to one path apart. */\nconst PARTS = [\n\t'param',\n\t'query',\n\t'header',\n\t'json',\n\t'form',\n\t'text',\n\t'body',\n] as const;\n\n/** What tells two calls to one path apart: what they send, and `decode: false`. */\nfunction keyed(input: object | undefined): object | undefined {\n\tif (!input) return undefined;\n\tconst given = input as { readonly [part: string]: unknown };\n\tconst key: Record<string, unknown> = {};\n\tfor (const part of PARTS) {\n\t\tif (given[part] !== undefined) key[part] = hashable(given[part]);\n\t}\n\tif (given.decode === false) key.decode = false;\n\treturn Object.keys(key).length > 0 ? key : undefined;\n}\n\n/** A key, or the start of one: `[scope?, method, path?, input?]`. */\nexport function keyOf(\n\tscope: string | undefined,\n\tmethod: string,\n\tpath?: string,\n\tinput?: object,\n): unknown[] {\n\tconst key: unknown[] = scope === undefined ? [method] : [scope, method];\n\tif (path !== undefined) key.push(path);\n\tconst rest = keyed(input);\n\tif (rest !== undefined) key.push(rest);\n\treturn key;\n}\n\n/** `input` with `pageParam` as its query parameter `name`: left out when `null`. */\nexport function paged<Input extends { readonly query?: unknown }>(\n\tinput: Input | undefined,\n\tname: string,\n\tpageParam: unknown,\n): Input {\n\tconst given = input?.query;\n\tif (given instanceof URLSearchParams) {\n\t\tconst query = new URLSearchParams(given);\n\t\tif (pageParam === null || pageParam === undefined) query.delete(name);\n\t\telse query.set(name, String(pageParam));\n\t\treturn { ...input, query } as Input;\n\t}\n\treturn {\n\t\t...input,\n\t\tquery: { ...(given as object | undefined), [name]: pageParam },\n\t} as Input;\n}\n"
|
|
7
|
+
],
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "21510642E24588C464756E2164756E21",
|
|
10
|
+
"names": []
|
|
11
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createQueries`: TanStack Query options for the calls of a client of
|
|
3
|
+
* `createHttpClient`. It adds no runtime of TanStack's: each function returns
|
|
4
|
+
* a plain object, whose `queryFn` sends the call with the query's `signal`.
|
|
5
|
+
*/
|
|
6
|
+
import { type HttpClient } from '@nxgt/httpyz';
|
|
7
|
+
import type { HttpQueries, QueriesOptions } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* TanStack Query options for the calls of `http`.
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* const queries = createQueries(http);
|
|
13
|
+
* const { data } = useQuery(
|
|
14
|
+
* queries.queryOptions('get', '/items/{id}', { param: { id }, responses: { 200: Item } }),
|
|
15
|
+
* );
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function createQueries(http: HttpClient, { scope }?: QueriesOptions): HttpQueries;
|
|
19
|
+
//# sourceMappingURL=create-queries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-queries.d.ts","sourceRoot":"","sources":["../../src/queries/create-queries.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,KAAK,UAAU,EAAmB,MAAM,cAAc,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAoB,cAAc,EAAE,MAAM,SAAS,CAAC;AAU7E;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC5B,IAAI,EAAE,UAAU,EAChB,EAAE,KAAK,EAAE,GAAE,cAAmB,GAC5B,WAAW,CA8Cb"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The options objects `createQueries()` returns. They are plain objects, so
|
|
3
|
+
* any TanStack Query adapter takes them: `useQuery(queries.queryOptions(...))`
|
|
4
|
+
* in React, `createQuery` in Solid, `injectQuery` in Angular.
|
|
5
|
+
*/
|
|
6
|
+
import type { CallOptions, HttpReply, Method, PathParamNames, QueryInput, ReplyOptions, RequestArgs, RequestInput, RequestOptions, Responses, Success } from '@nxgt/httpyz';
|
|
7
|
+
import type { DataTag, GetNextPageParamFunction, GetPreviousPageParamFunction, InfiniteData } from '@tanstack/query-core';
|
|
8
|
+
/** What a query resolves to: the data of the call's 2xx replies. */
|
|
9
|
+
export type QueryData<R extends Responses | undefined, Decoded extends boolean> = Success<HttpReply<R, Decoded>>['data'];
|
|
10
|
+
/**
|
|
11
|
+
* A key: `[method, path, input]`, after the client's `scope`, tagged with its
|
|
12
|
+
* data so that `queryClient.getQueryData(key)` is typed.
|
|
13
|
+
*/
|
|
14
|
+
export type HttpQueryKey<Data> = DataTag<readonly unknown[], Data>;
|
|
15
|
+
export interface HttpQueryOptions<Data> {
|
|
16
|
+
readonly queryKey: HttpQueryKey<Data>;
|
|
17
|
+
/** Sends the call with the query's `signal`: a cancelled query aborts it. */
|
|
18
|
+
readonly queryFn: (context: {
|
|
19
|
+
readonly signal: AbortSignal;
|
|
20
|
+
}) => Promise<Data>;
|
|
21
|
+
}
|
|
22
|
+
/** How an infinite query pages: TanStack's own options, and where the page goes. */
|
|
23
|
+
export interface Paging<Data, PageParam> {
|
|
24
|
+
/**
|
|
25
|
+
* The query parameter each page's `pageParam` is sent as: `'after'`,
|
|
26
|
+
* `'page'`. A `null` or `undefined` page param is left out.
|
|
27
|
+
*/
|
|
28
|
+
readonly pageParamName: string;
|
|
29
|
+
readonly initialPageParam: PageParam;
|
|
30
|
+
readonly getNextPageParam: GetNextPageParamFunction<PageParam, Data>;
|
|
31
|
+
readonly getPreviousPageParam?: GetPreviousPageParamFunction<PageParam, Data>;
|
|
32
|
+
readonly maxPages?: number;
|
|
33
|
+
}
|
|
34
|
+
export interface HttpInfiniteQueryOptions<Data, PageParam> extends Omit<Paging<Data, PageParam>, 'pageParamName'> {
|
|
35
|
+
readonly queryKey: HttpQueryKey<InfiniteData<Data, PageParam>>;
|
|
36
|
+
readonly queryFn: (context: {
|
|
37
|
+
readonly signal: AbortSignal;
|
|
38
|
+
readonly pageParam: PageParam;
|
|
39
|
+
}) => Promise<Data>;
|
|
40
|
+
}
|
|
41
|
+
/** What a mutation's `mutate()` takes: what the call sends, and its call options. */
|
|
42
|
+
export type MutationVariables<Path extends string> = RequestInput<Path> & CallOptions;
|
|
43
|
+
export interface HttpMutationOptions<Path extends string, Data> {
|
|
44
|
+
readonly mutationKey: readonly unknown[];
|
|
45
|
+
/** Optional when the path has no `{name}`s: `mutate()`. */
|
|
46
|
+
readonly mutationFn: (variables: [PathParamNames<Path>] extends [never] ? // biome-ignore lint/suspicious/noConfusingVoidType: void, not undefined, is what lets `mutate()` be called with nothing
|
|
47
|
+
MutationVariables<Path> | void : MutationVariables<Path>) => Promise<Data>;
|
|
48
|
+
}
|
|
49
|
+
/** What a key may hold, for a filter: any part of an input. */
|
|
50
|
+
export interface KeyInput {
|
|
51
|
+
readonly param?: {
|
|
52
|
+
readonly [name: string]: unknown;
|
|
53
|
+
};
|
|
54
|
+
readonly query?: QueryInput;
|
|
55
|
+
readonly json?: unknown;
|
|
56
|
+
readonly form?: unknown;
|
|
57
|
+
readonly text?: string;
|
|
58
|
+
readonly body?: unknown;
|
|
59
|
+
}
|
|
60
|
+
export interface HttpQueries {
|
|
61
|
+
/**
|
|
62
|
+
* A query of a call: `useQuery(queries.queryOptions('get', '/items/{id}', { param: { id }, responses }))`.
|
|
63
|
+
* It resolves to the data of a 2xx reply, and throws a `ReplyStatusError`
|
|
64
|
+
* for any other.
|
|
65
|
+
*/
|
|
66
|
+
queryOptions<Path extends string, R extends Responses | undefined = undefined, Decoded extends boolean = true>(method: Method, path: Path, ...args: RequestArgs<Path, R, Decoded>): HttpQueryOptions<QueryData<R, Decoded>>;
|
|
67
|
+
/** An infinite query of a call: each page sent with its `pageParam` as a query parameter. */
|
|
68
|
+
infiniteQueryOptions<Path extends string, PageParam, R extends Responses | undefined = undefined, Decoded extends boolean = true>(method: Method, path: Path, options: RequestOptions<Path, R, Decoded>, paging: Paging<QueryData<R, Decoded>, PageParam>): HttpInfiniteQueryOptions<QueryData<R, Decoded>, PageParam>;
|
|
69
|
+
/**
|
|
70
|
+
* A mutation of a call, whose `mutate()` takes what it sends:
|
|
71
|
+
* `useMutation(queries.mutationOptions('delete', '/items/{id}'))`, then
|
|
72
|
+
* `mutate({ param: { id } })`. `options` holds what every call shares.
|
|
73
|
+
*/
|
|
74
|
+
mutationOptions<Path extends string, R extends Responses | undefined = undefined, Decoded extends boolean = true>(method: Method, path: Path, options?: CallOptions & ReplyOptions<R, Decoded>): HttpMutationOptions<Path, QueryData<R, Decoded>>;
|
|
75
|
+
/**
|
|
76
|
+
* A key, or the start of one, for a filter:
|
|
77
|
+
* `queryClient.invalidateQueries({ queryKey: queries.queryKey('get', '/items') })`
|
|
78
|
+
* matches every query of `GET /items`, whatever its input.
|
|
79
|
+
*/
|
|
80
|
+
queryKey(method: Method, path?: string, input?: KeyInput): readonly unknown[];
|
|
81
|
+
}
|
|
82
|
+
export interface QueriesOptions {
|
|
83
|
+
/**
|
|
84
|
+
* Put first in every key, to keep two clients' queries apart when their
|
|
85
|
+
* paths are the same: `'catalog'`.
|
|
86
|
+
*/
|
|
87
|
+
readonly scope?: string;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/queries/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nxgt/httpyz-query",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "UNLICENSED",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md",
|
|
11
|
+
"package.json"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./openapi": {
|
|
20
|
+
"types": "./dist/openapi.d.ts",
|
|
21
|
+
"import": "./dist/openapi.js",
|
|
22
|
+
"default": "./dist/openapi.js"
|
|
23
|
+
},
|
|
24
|
+
"./package.json": "./package.json"
|
|
25
|
+
},
|
|
26
|
+
"nxgt": {
|
|
27
|
+
"entrypoints": [
|
|
28
|
+
"src/index.ts",
|
|
29
|
+
"src/openapi.ts"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/softistx/nxgt-http.git",
|
|
35
|
+
"directory": "packages/httpyz-query"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"registry": "https://registry.npmjs.org",
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "bun run ../../build.ts",
|
|
43
|
+
"fixtures": "bun run test/generate.ts",
|
|
44
|
+
"test": "bun run fixtures && bun test src",
|
|
45
|
+
"typecheck": "bun run fixtures && tsc --noEmit"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@nxgt/httpyz": "^0.0.0",
|
|
49
|
+
"@nxgt/openapi-codegen": "^0.1.0",
|
|
50
|
+
"@nxgt/openapi-httpyz": "^0.0.0",
|
|
51
|
+
"@tanstack/query-core": "^5.102.8",
|
|
52
|
+
"@types/bun": "^1.4.0",
|
|
53
|
+
"zod": "^4.5.4"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"@nxgt/httpyz": "^0.0.0",
|
|
57
|
+
"@nxgt/openapi-httpyz": "^0.0.0",
|
|
58
|
+
"@tanstack/query-core": "^5.90.0",
|
|
59
|
+
"typescript": "^6.0.3"
|
|
60
|
+
},
|
|
61
|
+
"peerDependenciesMeta": {
|
|
62
|
+
"@nxgt/openapi-httpyz": {
|
|
63
|
+
"optional": true
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|