@kizunajs/tanstack-query 2.0.0-beta.12 → 2.0.0-beta.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @kizunajs/tanstack-query
2
2
 
3
- `@kizunajs/tanstack-query` provides `new KizunaTanstackQuery()`, which builds TanStack Query options from a Kizuna api. Query keys, caching, and invalidation come from the routes you already wrote.
3
+ `@kizunajs/tanstack-query` provides `new KizunaTanstackQuery()`, which builds TanStack Query options from a generated Kizuna fetch client. Query keys, caching, and invalidation come from the routes you already wrote.
4
4
 
5
5
  ## Installation
6
6
 
@@ -13,9 +13,13 @@ pnpm add @kizunajs/tanstack-query
13
13
  ```ts
14
14
  import { useQuery } from '@tanstack/react-query';
15
15
  import { KizunaTanstackQuery } from '@kizunajs/tanstack-query';
16
- import { apiClient } from './api-client';
16
+ import { createClient } from './api-client.generated';
17
17
 
18
- const api = new KizunaTanstackQuery(apiClient);
18
+ const api = new KizunaTanstackQuery(
19
+ createClient({
20
+ baseUrl: 'http://localhost:3000',
21
+ })
22
+ );
19
23
 
20
24
  const { data } = useQuery(
21
25
  api.users.getUser.queryOptions({
package/dist/index.cjs CHANGED
@@ -1,7 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _tanstack_query_core = require("@tanstack/query-core");
3
- let kizunajs = require("kizunajs");
4
- let _kizunajs_fetch = require("@kizunajs/fetch");
5
3
  //#region src/errors.ts
6
4
  /**
7
5
  * Thrown when a route returns a status the api does not declare. Declared
@@ -57,10 +55,9 @@ const buildQueryKey = (segments, input, type) => {
57
55
  const buildPathKey = (segments) => [segments];
58
56
  //#endregion
59
57
  //#region src/proxy.ts
60
- const declaresStatus = (route, status) => {
61
- if (Object.hasOwn(route.responses, String(status))) return true;
62
- return status === 400 && ("body" in route || "query" in route);
63
- };
58
+ const routeOf = (value) => typeof value === "function" ? value["~route"] : void 0;
59
+ const declaresStatus = (route, status) => Object.hasOwn(route.responses, status);
60
+ const streamsStatus = (route, status) => route.responses[status]?.stream === true;
64
61
  const withSignal = (args, signal) => {
65
62
  if (signal === void 0) return args;
66
63
  const { fetchOptions, ...rest } = args ?? {};
@@ -81,7 +78,7 @@ const isQueryMethod = (route) => route.method === "GET" || route.method === "HEA
81
78
  const buildProcedure = (segments, route, clientFn) => {
82
79
  const routeKey = segments.join(".");
83
80
  const call = (args) => clientFn(args);
84
- if ((0, kizunajs.routeStreams)(route)) return {
81
+ if (route.streams) return {
85
82
  streamOptions: (options) => {
86
83
  const { input, refetchMode, ...rest } = options;
87
84
  const skipped = input === _tanstack_query_core.skipToken;
@@ -90,7 +87,7 @@ const buildProcedure = (segments, route, clientFn) => {
90
87
  queryFn: skipped ? _tanstack_query_core.skipToken : (0, _tanstack_query_core.experimental_streamedQuery)({
91
88
  streamFn: async ({ signal }) => {
92
89
  const result = await runRoute(clientFn, route, routeKey, input, signal);
93
- if (!(0, kizunajs.streamStatuses)(route).includes(result.status)) throw new NonStreamResponseError(routeKey, result.status, result.body, result.headers);
90
+ if (!streamsStatus(route, result.status)) throw new NonStreamResponseError(routeKey, result.status, result.body, result.headers);
94
91
  return result.body;
95
92
  },
96
93
  ...refetchMode === void 0 ? {} : { refetchMode }
@@ -146,7 +143,7 @@ const buildNode = (segments, clientNode) => {
146
143
  for (const routeName of Object.keys(clientNode)) {
147
144
  const child = clientNode[routeName];
148
145
  const childSegments = [...segments, routeName];
149
- const route = (0, _kizunajs_fetch.routeOf)(child);
146
+ const route = routeOf(child);
150
147
  if (route) node[routeName] = buildProcedure(childSegments, route, child);
151
148
  else if (child && typeof child === "object") node[routeName] = buildNode(childSegments, child);
152
149
  }
@@ -156,15 +153,19 @@ function buildQueryProxy(client) {
156
153
  return buildNode([], client);
157
154
  }
158
155
  /**
159
- * Builds TanStack Query options from a fetch client. Every client method
160
- * carries the route it answers, so the client is the only argument.
156
+ * Builds TanStack Query options from a generated fetch client. Every client
157
+ * method carries the route it answers, so the client is the only argument.
161
158
  *
162
159
  * ```ts
163
160
  * import { useQuery } from '@tanstack/react-query';
164
161
  * import { KizunaTanstackQuery } from '@kizunajs/tanstack-query';
165
- * import { apiClient } from './api-client.js';
162
+ * import { createClient } from './api-client.generated.js';
166
163
  *
167
- * const api = new KizunaTanstackQuery(apiClient);
164
+ * const api = new KizunaTanstackQuery(
165
+ * createClient({
166
+ * baseUrl: 'http://localhost:3000',
167
+ * })
168
+ * );
168
169
  *
169
170
  * useQuery(
170
171
  * api.users.listUsers.queryOptions({
package/dist/index.d.cts CHANGED
@@ -1,6 +1,4 @@
1
1
  import { DataTag, DefaultError, InfiniteData, InfiniteQueryObserverOptions, MutationObserverOptions, QueryFunction, QueryFunctionContext, QueryObserverOptions, SkipToken } from "@tanstack/query-core";
2
- import { RouteDefinition, Routes, StreamResponseDefinition } from "kizunajs";
3
- import { Client, ClientArgs, ClientMethod, ClientResponse } from "@kizunajs/fetch";
4
2
 
5
3
  //#region src/types.d.ts
6
4
  type KizunaQueryKeyType = 'query' | 'infinite' | 'stream';
@@ -151,43 +149,50 @@ interface StreamProcedure<Args, Result> {
151
149
  key: () => KizunaPathKey;
152
150
  call: CallFn<Args, Result>;
153
151
  }
154
- type HasStream<R extends RouteDefinition> = { [Status in keyof R['responses']]: R['responses'][Status] extends StreamResponseDefinition ? true : never }[keyof R['responses']] extends never ? false : true;
152
+ /**
153
+ * A method on a client `@kizunajs/fetch` generates. Its `'~route'` names the
154
+ * HTTP method it sends and whether its response streams, which is all the
155
+ * proxy needs to choose its factories.
156
+ */
157
+ type ClientMethod<Method extends string, Streams extends boolean, Args, Result> = ({} extends Args ? (args?: Args) => Promise<Result> : (args: Args) => Promise<Result>) & {
158
+ readonly '~route': {
159
+ readonly method: Method;
160
+ readonly streams: Streams;
161
+ };
162
+ };
155
163
  /**
156
164
  * Which factories a route gets: a streamed response takes `streamOptions`, a
157
165
  * `GET` or `HEAD` takes the query factories, and everything else mutates.
158
166
  */
159
167
  type ProcedureFor<Method, Streams, Args, Result> = Streams extends true ? StreamProcedure<Args, Result> : Method extends 'GET' | 'HEAD' ? QueryProcedure<Args, Result> : MutationProcedure<Args, Result>;
160
- type Procedure<R extends RouteDefinition, Codes extends string> = ProcedureFor<R['method'], HasStream<R>, ClientArgs<R>, ClientResponse<R, Codes>>;
161
168
  /**
162
- * The route tree, each route carrying its query or mutation factories.
169
+ * The client's tree, each method carrying its query, mutation, or stream
170
+ * factories and each group its partial key.
163
171
  */
164
- type KizunaQueryProxy<T extends Routes, Codes extends string = never> = { [K in keyof T as K extends string ? K : never]: T[K] extends RouteDefinition ? Procedure<T[K], Codes> : T[K] extends Routes ? KizunaQueryProxy<T[K], Codes> & PathProcedures : never };
165
- /**
166
- * The same tree, read off a generated client instead of off the routes. Each of
167
- * its methods carries the method it calls and whether that response streams, so
168
- * the client alone says which factories every route gets.
169
- */
170
- type GeneratedQueryProxy<C> = { [K in keyof C as K extends string ? K : never]: C[K] extends ClientMethod<infer Method, infer Streams, infer Args, infer Result> ? ProcedureFor<Method, Streams, Args, Result> : C[K] extends object ? GeneratedQueryProxy<C[K]> & PathProcedures : never };
172
+ type KizunaQueryProxy<C> = { [K in keyof C as K extends string ? K : never]: C[K] extends ClientMethod<infer Method, infer Streams, infer Args, infer Result> ? ProcedureFor<Method, Streams, Args, Result> : C[K] extends object ? KizunaQueryProxy<C[K]> & PathProcedures : never };
171
173
  interface KizunaTanstackQueryConstructor {
172
174
  /**
173
- * The client is the only argument: each of its methods carries the route it
174
- * answers, so nothing has to hand over the api a second time.
175
+ * The generated client is the only argument: each of its methods carries
176
+ * the route it answers.
175
177
  */
176
- new <T extends Routes, Codes extends string = never>(client: Client<T, Codes>): KizunaQueryProxy<T, Codes> & PathProcedures;
177
- new <C extends object>(client: C): GeneratedQueryProxy<C> & PathProcedures;
178
+ new <C extends object>(client: C): KizunaQueryProxy<C> & PathProcedures;
178
179
  }
179
180
  //#endregion
180
181
  //#region src/proxy.d.ts
181
182
  /**
182
- * Builds TanStack Query options from a fetch client. Every client method
183
- * carries the route it answers, so the client is the only argument.
183
+ * Builds TanStack Query options from a generated fetch client. Every client
184
+ * method carries the route it answers, so the client is the only argument.
184
185
  *
185
186
  * ```ts
186
187
  * import { useQuery } from '@tanstack/react-query';
187
188
  * import { KizunaTanstackQuery } from '@kizunajs/tanstack-query';
188
- * import { apiClient } from './api-client.js';
189
+ * import { createClient } from './api-client.generated.js';
189
190
  *
190
- * const api = new KizunaTanstackQuery(apiClient);
191
+ * const api = new KizunaTanstackQuery(
192
+ * createClient({
193
+ * baseUrl: 'http://localhost:3000',
194
+ * })
195
+ * );
191
196
  *
192
197
  * useQuery(
193
198
  * api.users.listUsers.queryOptions({
package/dist/index.d.mts CHANGED
@@ -1,6 +1,4 @@
1
1
  import { DataTag, DefaultError, InfiniteData, InfiniteQueryObserverOptions, MutationObserverOptions, QueryFunction, QueryFunctionContext, QueryObserverOptions, SkipToken } from "@tanstack/query-core";
2
- import { RouteDefinition, Routes, StreamResponseDefinition } from "kizunajs";
3
- import { Client, ClientArgs, ClientMethod, ClientResponse } from "@kizunajs/fetch";
4
2
 
5
3
  //#region src/types.d.ts
6
4
  type KizunaQueryKeyType = 'query' | 'infinite' | 'stream';
@@ -151,43 +149,50 @@ interface StreamProcedure<Args, Result> {
151
149
  key: () => KizunaPathKey;
152
150
  call: CallFn<Args, Result>;
153
151
  }
154
- type HasStream<R extends RouteDefinition> = { [Status in keyof R['responses']]: R['responses'][Status] extends StreamResponseDefinition ? true : never }[keyof R['responses']] extends never ? false : true;
152
+ /**
153
+ * A method on a client `@kizunajs/fetch` generates. Its `'~route'` names the
154
+ * HTTP method it sends and whether its response streams, which is all the
155
+ * proxy needs to choose its factories.
156
+ */
157
+ type ClientMethod<Method extends string, Streams extends boolean, Args, Result> = ({} extends Args ? (args?: Args) => Promise<Result> : (args: Args) => Promise<Result>) & {
158
+ readonly '~route': {
159
+ readonly method: Method;
160
+ readonly streams: Streams;
161
+ };
162
+ };
155
163
  /**
156
164
  * Which factories a route gets: a streamed response takes `streamOptions`, a
157
165
  * `GET` or `HEAD` takes the query factories, and everything else mutates.
158
166
  */
159
167
  type ProcedureFor<Method, Streams, Args, Result> = Streams extends true ? StreamProcedure<Args, Result> : Method extends 'GET' | 'HEAD' ? QueryProcedure<Args, Result> : MutationProcedure<Args, Result>;
160
- type Procedure<R extends RouteDefinition, Codes extends string> = ProcedureFor<R['method'], HasStream<R>, ClientArgs<R>, ClientResponse<R, Codes>>;
161
168
  /**
162
- * The route tree, each route carrying its query or mutation factories.
169
+ * The client's tree, each method carrying its query, mutation, or stream
170
+ * factories and each group its partial key.
163
171
  */
164
- type KizunaQueryProxy<T extends Routes, Codes extends string = never> = { [K in keyof T as K extends string ? K : never]: T[K] extends RouteDefinition ? Procedure<T[K], Codes> : T[K] extends Routes ? KizunaQueryProxy<T[K], Codes> & PathProcedures : never };
165
- /**
166
- * The same tree, read off a generated client instead of off the routes. Each of
167
- * its methods carries the method it calls and whether that response streams, so
168
- * the client alone says which factories every route gets.
169
- */
170
- type GeneratedQueryProxy<C> = { [K in keyof C as K extends string ? K : never]: C[K] extends ClientMethod<infer Method, infer Streams, infer Args, infer Result> ? ProcedureFor<Method, Streams, Args, Result> : C[K] extends object ? GeneratedQueryProxy<C[K]> & PathProcedures : never };
172
+ type KizunaQueryProxy<C> = { [K in keyof C as K extends string ? K : never]: C[K] extends ClientMethod<infer Method, infer Streams, infer Args, infer Result> ? ProcedureFor<Method, Streams, Args, Result> : C[K] extends object ? KizunaQueryProxy<C[K]> & PathProcedures : never };
171
173
  interface KizunaTanstackQueryConstructor {
172
174
  /**
173
- * The client is the only argument: each of its methods carries the route it
174
- * answers, so nothing has to hand over the api a second time.
175
+ * The generated client is the only argument: each of its methods carries
176
+ * the route it answers.
175
177
  */
176
- new <T extends Routes, Codes extends string = never>(client: Client<T, Codes>): KizunaQueryProxy<T, Codes> & PathProcedures;
177
- new <C extends object>(client: C): GeneratedQueryProxy<C> & PathProcedures;
178
+ new <C extends object>(client: C): KizunaQueryProxy<C> & PathProcedures;
178
179
  }
179
180
  //#endregion
180
181
  //#region src/proxy.d.ts
181
182
  /**
182
- * Builds TanStack Query options from a fetch client. Every client method
183
- * carries the route it answers, so the client is the only argument.
183
+ * Builds TanStack Query options from a generated fetch client. Every client
184
+ * method carries the route it answers, so the client is the only argument.
184
185
  *
185
186
  * ```ts
186
187
  * import { useQuery } from '@tanstack/react-query';
187
188
  * import { KizunaTanstackQuery } from '@kizunajs/tanstack-query';
188
- * import { apiClient } from './api-client.js';
189
+ * import { createClient } from './api-client.generated.js';
189
190
  *
190
- * const api = new KizunaTanstackQuery(apiClient);
191
+ * const api = new KizunaTanstackQuery(
192
+ * createClient({
193
+ * baseUrl: 'http://localhost:3000',
194
+ * })
195
+ * );
191
196
  *
192
197
  * useQuery(
193
198
  * api.users.listUsers.queryOptions({
package/dist/index.mjs CHANGED
@@ -1,6 +1,4 @@
1
1
  import { experimental_streamedQuery, skipToken } from "@tanstack/query-core";
2
- import { routeStreams, streamStatuses } from "kizunajs";
3
- import { routeOf } from "@kizunajs/fetch";
4
2
  //#region src/errors.ts
5
3
  /**
6
4
  * Thrown when a route returns a status the api does not declare. Declared
@@ -56,10 +54,9 @@ const buildQueryKey = (segments, input, type) => {
56
54
  const buildPathKey = (segments) => [segments];
57
55
  //#endregion
58
56
  //#region src/proxy.ts
59
- const declaresStatus = (route, status) => {
60
- if (Object.hasOwn(route.responses, String(status))) return true;
61
- return status === 400 && ("body" in route || "query" in route);
62
- };
57
+ const routeOf = (value) => typeof value === "function" ? value["~route"] : void 0;
58
+ const declaresStatus = (route, status) => Object.hasOwn(route.responses, status);
59
+ const streamsStatus = (route, status) => route.responses[status]?.stream === true;
63
60
  const withSignal = (args, signal) => {
64
61
  if (signal === void 0) return args;
65
62
  const { fetchOptions, ...rest } = args ?? {};
@@ -80,7 +77,7 @@ const isQueryMethod = (route) => route.method === "GET" || route.method === "HEA
80
77
  const buildProcedure = (segments, route, clientFn) => {
81
78
  const routeKey = segments.join(".");
82
79
  const call = (args) => clientFn(args);
83
- if (routeStreams(route)) return {
80
+ if (route.streams) return {
84
81
  streamOptions: (options) => {
85
82
  const { input, refetchMode, ...rest } = options;
86
83
  const skipped = input === skipToken;
@@ -89,7 +86,7 @@ const buildProcedure = (segments, route, clientFn) => {
89
86
  queryFn: skipped ? skipToken : experimental_streamedQuery({
90
87
  streamFn: async ({ signal }) => {
91
88
  const result = await runRoute(clientFn, route, routeKey, input, signal);
92
- if (!streamStatuses(route).includes(result.status)) throw new NonStreamResponseError(routeKey, result.status, result.body, result.headers);
89
+ if (!streamsStatus(route, result.status)) throw new NonStreamResponseError(routeKey, result.status, result.body, result.headers);
93
90
  return result.body;
94
91
  },
95
92
  ...refetchMode === void 0 ? {} : { refetchMode }
@@ -155,15 +152,19 @@ function buildQueryProxy(client) {
155
152
  return buildNode([], client);
156
153
  }
157
154
  /**
158
- * Builds TanStack Query options from a fetch client. Every client method
159
- * carries the route it answers, so the client is the only argument.
155
+ * Builds TanStack Query options from a generated fetch client. Every client
156
+ * method carries the route it answers, so the client is the only argument.
160
157
  *
161
158
  * ```ts
162
159
  * import { useQuery } from '@tanstack/react-query';
163
160
  * import { KizunaTanstackQuery } from '@kizunajs/tanstack-query';
164
- * import { apiClient } from './api-client.js';
161
+ * import { createClient } from './api-client.generated.js';
165
162
  *
166
- * const api = new KizunaTanstackQuery(apiClient);
163
+ * const api = new KizunaTanstackQuery(
164
+ * createClient({
165
+ * baseUrl: 'http://localhost:3000',
166
+ * })
167
+ * );
167
168
  *
168
169
  * useQuery(
169
170
  * api.users.listUsers.queryOptions({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kizunajs/tanstack-query",
3
- "version": "2.0.0-beta.12",
3
+ "version": "2.0.0-beta.14",
4
4
  "description": "TanStack Query client for Kizuna.js",
5
5
  "keywords": [
6
6
  "kizunajs",
@@ -56,10 +56,7 @@
56
56
  "access": "public"
57
57
  },
58
58
  "peerDependencies": {
59
- "@tanstack/query-core": "^5.69.0",
60
- "zod": "^4.0.0",
61
- "kizunajs": "2.0.0-beta.12",
62
- "@kizunajs/fetch": "2.0.0-beta.12"
59
+ "@tanstack/query-core": "^5.69.0"
63
60
  },
64
61
  "devDependencies": {
65
62
  "@tanstack/query-core": "^5.101.0",
@@ -73,11 +70,11 @@
73
70
  "typescript": "^6.0.3",
74
71
  "vue": "^3.5.0",
75
72
  "zod": "^4.0.0",
76
- "kizunajs": "2.0.0-beta.12",
77
- "@kizunajs/fetch": "2.0.0-beta.12"
73
+ "kizunajs": "2.0.0-beta.14",
74
+ "@kizunajs/fetch": "2.0.0-beta.14"
78
75
  },
79
76
  "scripts": {
80
- "build": "tsdown src/index.ts --format esm,cjs --dts --clean --external kizunajs --external @kizunajs/fetch --external @tanstack/query-core --external zod",
77
+ "build": "tsdown src/index.ts --format esm,cjs --dts --clean --external @tanstack/query-core",
81
78
  "typecheck": "tsc --noEmit"
82
79
  }
83
80
  }