@cushin/api-codegen 5.0.1 → 5.0.3

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/dist/index.js CHANGED
@@ -171,6 +171,19 @@ var BaseGenerator = class {
171
171
  (e) => e.method === "GET"
172
172
  );
173
173
  }
174
+ // Helper methods to get named type references
175
+ getResponseTypeName(name) {
176
+ return `${this.capitalize(name)}Response`;
177
+ }
178
+ getInputTypeName(name) {
179
+ return `${this.capitalize(name)}Input`;
180
+ }
181
+ getQueryTypeName(name) {
182
+ return `${this.capitalize(name)}Query`;
183
+ }
184
+ getParamsTypeName(name) {
185
+ return `${this.capitalize(name)}Params`;
186
+ }
174
187
  };
175
188
 
176
189
  // src/generators/hooks.ts
@@ -183,16 +196,12 @@ var HooksGenerator = class extends BaseGenerator {
183
196
  }
184
197
  generateContent() {
185
198
  const useClientDirective = this.context.config.options?.useClientDirective ?? true;
186
- const outputPath = path2.join(this.context.config.outputDir, "types.ts");
187
- const endpointsPath = path2.join(this.context.config.endpointsPath);
188
- const relativePath = path2.relative(path2.dirname(outputPath), endpointsPath).replace(/\\/g, "/").replace(/\.ts$/, "");
189
199
  const content = `${useClientDirective ? "'use client';\n" : ""}
190
200
  import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
191
201
  import { apiClient } from "./client";
192
202
  import { queryKeys } from "./query-keys";
193
203
  import { apiQueryOptions } from "./query-options";
194
- import { z } from "zod";
195
- import { apiConfig } from "${relativePath}";
204
+ import type * as Types from "./types";
196
205
 
197
206
  ${this.generateQueryHooks()}
198
207
  ${this.generateMutationHooks()}
@@ -213,29 +222,23 @@ ${this.generateMutationHooks()}
213
222
  const hookName = `use${this.capitalize(name)}`;
214
223
  const resource = this.getResourceFromEndpoint(name, endpoint);
215
224
  const optionName = this.getEndpointKeyName(name);
216
- const inferParams = this.inferNonNull(
217
- `typeof apiConfig.endpoints.${name}.params`
218
- );
219
- const inferQuery = this.inferNonNull(
220
- `typeof apiConfig.endpoints.${name}.query`
221
- );
222
- const inferResponse = this.inferNonNull(
223
- `typeof apiConfig.endpoints.${name}.response`
224
- );
225
+ const responseType = `Types.${this.getResponseTypeName(name)}`;
226
+ const paramsType = endpoint.params ? `Types.${this.getParamsTypeName(name)}` : null;
227
+ const queryType = endpoint.query ? `Types.${this.getQueryTypeName(name)}` : null;
225
228
  const params = [];
226
229
  const optionParams = [];
227
230
  const queryTags = this.getQueryTags(endpoint);
228
- if (endpoint.params) {
229
- params.push(`params: ${inferParams}`);
231
+ if (paramsType) {
232
+ params.push(`params: ${paramsType}`);
230
233
  optionParams.push("params");
231
234
  }
232
- if (endpoint.query) {
233
- params.push(`filters?: ${inferQuery}`);
235
+ if (queryType) {
236
+ params.push(`filters?: ${queryType}`);
234
237
  optionParams.push("filters");
235
238
  }
236
239
  params.push(`options?: {
237
240
  enabled?: boolean;
238
- select?: <TData = ${inferResponse}>(data: ${inferResponse}) => TData;
241
+ select?: <TData = ${responseType}>(data: ${responseType}) => TData;
239
242
  }`);
240
243
  return `/**
241
244
  * ${endpoint.description || `Query hook for ${name}`}
@@ -261,26 +264,20 @@ export function ${hookName}(${params.join(",\n ")}) {
261
264
  generateMutationHook(name, endpoint) {
262
265
  const hookName = `use${this.capitalize(name)}`;
263
266
  const resource = this.getResourceFromEndpoint(name, endpoint);
264
- const inferParams = this.inferNonNull(
265
- `typeof apiConfig.endpoints.${name}.params`
266
- );
267
- const inferBody = this.inferNonNull(
268
- `typeof apiConfig.endpoints.${name}.body`
269
- );
270
- const inferResponse = this.inferNonNull(
271
- `typeof apiConfig.endpoints.${name}.response`
272
- );
267
+ const responseType = `Types.${this.getResponseTypeName(name)}`;
268
+ const paramsType = endpoint.params ? `Types.${this.getParamsTypeName(name)}` : null;
269
+ const bodyType = endpoint.body ? `Types.${this.getInputTypeName(name)}` : null;
273
270
  const resourceHasQueries = this.resourceHasQueryEndpoints(resource);
274
271
  let inputType;
275
272
  let fnBody;
276
- if (endpoint.params && endpoint.body) {
277
- inputType = `{ params: ${inferParams}; body: ${inferBody}; }`;
273
+ if (paramsType && bodyType) {
274
+ inputType = `{ params: ${paramsType}; body: ${bodyType}; }`;
278
275
  fnBody = `({ params, body }: ${inputType}) => apiClient.${name}(params, body)`;
279
- } else if (endpoint.params) {
280
- inputType = `${inferParams}`;
276
+ } else if (paramsType) {
277
+ inputType = paramsType;
281
278
  fnBody = `(params: ${inputType}) => apiClient.${name}(params)`;
282
- } else if (endpoint.body) {
283
- inputType = `${inferBody}`;
279
+ } else if (bodyType) {
280
+ inputType = bodyType;
284
281
  fnBody = `(body: ${inputType}) => apiClient.${name}(body)`;
285
282
  } else {
286
283
  inputType = "void";
@@ -291,24 +288,24 @@ export function ${hookName}(${params.join(",\n ")}) {
291
288
  * ${endpoint.description || `Mutation hook for ${name}`}
292
289
  * @tags ${endpoint.tags?.join(", ") || "none"}
293
290
  */
294
- export function ${hookName}(options?: {
295
- onSuccess?: (data: ${inferResponse}, variables: ${inputType}, context: unknown) => void;
296
- onError?: (error: Error, variables: ${inputType}, context: unknown) => void;
297
- onSettled?: (data: ${inferResponse} | undefined, error: Error | null, variables: ${inputType}, context: unknown) => void;
298
- onMutate?: (variables: ${inputType}) => Promise<unknown> | unknown;
299
- }) {
300
- ${invalidate ? "const queryClient = useQueryClient();" : ""}
301
- return useMutation({
302
- mutationFn: ${fnBody},
303
- onSuccess: (data, variables, context) => {
304
- ${invalidate}
305
- options?.onSuccess?.(data, variables, context);
306
- },
307
- onError: options?.onError,
308
- onSettled: options?.onSettled,
309
- onMutate: options?.onMutate,
310
- });
311
- }`;
291
+ export function ${hookName}(options?: {
292
+ onSuccess?: (data: ${responseType}, variables: ${inputType}, context: unknown) => void;
293
+ onError?: (error: Error, variables: ${inputType}, context: unknown) => void;
294
+ onSettled?: (data: ${responseType} | undefined, error: Error | null, variables: ${inputType}, context: unknown) => void;
295
+ onMutate?: (variables: ${inputType}) => Promise<unknown> | unknown;
296
+ }) {
297
+ ${invalidate ? "const queryClient = useQueryClient();" : ""}
298
+ return useMutation({
299
+ mutationFn: ${fnBody},
300
+ onSuccess: (data, variables, context) => {
301
+ ${invalidate}
302
+ options?.onSuccess?.(data, variables, context);
303
+ },
304
+ onError: options?.onError,
305
+ onSettled: options?.onSettled,
306
+ onMutate: options?.onMutate,
307
+ });
308
+ }`;
312
309
  }
313
310
  };
314
311
 
@@ -323,15 +320,11 @@ var ServerActionsGenerator = class extends BaseGenerator {
323
320
  await fs2.writeFile(outputPath, content, "utf-8");
324
321
  }
325
322
  generateContent() {
326
- const outputPath = path3.join(this.context.config.outputDir, "types.ts");
327
- const endpointsPath = path3.join(this.context.config.endpointsPath);
328
- const relativePath = path3.relative(path3.dirname(outputPath), endpointsPath).replace(/\\/g, "/").replace(/\.ts$/, "");
329
323
  const imports = `'use server';
330
324
 
331
325
  import { revalidateTag, revalidatePath } from 'next/cache';
332
326
  import { serverClient } from './server-client';
333
- import { z } from 'zod';
334
- import { apiConfig } from '${relativePath}';
327
+ import type * as Types from './types';
335
328
 
336
329
  export type ActionResult<T> =
337
330
  | { success: true; data: T }
@@ -350,18 +343,20 @@ export type ActionResult<T> =
350
343
  generateServerAction(name, endpoint) {
351
344
  const actionSuffix = this.context.config.options?.actionSuffix || "Action";
352
345
  const actionName = `${name}${actionSuffix}`;
353
- const signature = this.getEndpointSignature(name, endpoint);
354
346
  const invalidationTags = this.getInvalidationTags(endpoint);
347
+ const responseType = `Types.${this.getResponseTypeName(name)}`;
348
+ const paramsType = endpoint.params ? `Types.${this.getParamsTypeName(name)}` : null;
349
+ const bodyType = endpoint.body ? `Types.${this.getInputTypeName(name)}` : null;
355
350
  let inputType = "";
356
351
  let callArgs = "";
357
- if (signature.hasParams && signature.hasBody) {
358
- inputType = `input: { params: ${signature.paramType}; body: ${signature.bodyType} }`;
352
+ if (paramsType && bodyType) {
353
+ inputType = `input: { params: ${paramsType}; body: ${bodyType} }`;
359
354
  callArgs = "input.params, input.body";
360
- } else if (signature.hasParams) {
361
- inputType = `params: ${signature.paramType}`;
355
+ } else if (paramsType) {
356
+ inputType = `params: ${paramsType}`;
362
357
  callArgs = "params";
363
- } else if (signature.hasBody) {
364
- inputType = `body: ${signature.bodyType}`;
358
+ } else if (bodyType) {
359
+ inputType = `body: ${bodyType}`;
365
360
  callArgs = "body";
366
361
  }
367
362
  const revalidateStatements = invalidationTags.length > 0 ? invalidationTags.map((tag) => ` revalidateTag('${tag}');`).join("\n") : " // No automatic revalidations";
@@ -371,7 +366,7 @@ export type ActionResult<T> =
371
366
  */
372
367
  export async function ${actionName}(
373
368
  ${inputType}
374
- ): Promise<ActionResult<${signature.responseType}>> {
369
+ ): Promise<ActionResult<${responseType}>> {
375
370
  try {
376
371
  const result = await (serverClient as any).${name}(${callArgs});
377
372
 
@@ -401,14 +396,10 @@ var ServerQueriesGenerator = class extends BaseGenerator {
401
396
  await fs3.writeFile(outputPath, content, "utf-8");
402
397
  }
403
398
  generateContent() {
404
- const outputPath = path4.join(this.context.config.outputDir, "types.ts");
405
- const endpointsPath = path4.join(this.context.config.endpointsPath);
406
- const relativePath = path4.relative(path4.dirname(outputPath), endpointsPath).replace(/\\/g, "/").replace(/\.ts$/, "");
407
399
  const imports = `import { cache } from 'react';
408
400
  import { unstable_cache } from 'next/cache';
409
401
  import { serverClient } from './server-client';
410
- import { z } from 'zod';
411
- import { apiConfig } from '${relativePath}';
402
+ import type * as Types from './types';
412
403
  `;
413
404
  const queries = [];
414
405
  Object.entries(this.context.apiConfig.endpoints).forEach(
@@ -422,24 +413,26 @@ import { apiConfig } from '${relativePath}';
422
413
  }
423
414
  generateServerQuery(name, endpoint) {
424
415
  const queryName = `${name}Query`;
425
- const signature = this.getEndpointSignature(name, endpoint);
426
416
  const queryTags = this.getQueryTags(endpoint);
427
- const paramDef = signature.hasParams ? `params: ${signature.paramType}` : "";
428
- const queryDef = signature.hasQuery ? `query?: ${signature.queryType}` : "";
417
+ const responseType = `Types.${this.getResponseTypeName(name)}`;
418
+ const paramsType = endpoint.params ? `Types.${this.getParamsTypeName(name)}` : null;
419
+ const queryType = endpoint.query ? `Types.${this.getQueryTypeName(name)}` : null;
420
+ const paramDef = paramsType ? `params: ${paramsType}` : "";
421
+ const queryDef = queryType ? `query?: ${queryType}` : "";
429
422
  const paramsList = [paramDef, queryDef].filter(Boolean).join(",\n ");
430
423
  let clientCall = "";
431
- if (signature.hasParams && signature.hasQuery) {
424
+ if (paramsType && queryType) {
432
425
  clientCall = `(serverClient as any).${name}(params, query)`;
433
- } else if (signature.hasParams) {
426
+ } else if (paramsType) {
434
427
  clientCall = `(serverClient as any).${name}(params)`;
435
- } else if (signature.hasQuery) {
428
+ } else if (queryType) {
436
429
  clientCall = `(serverClient as any).${name}(query)`;
437
430
  } else {
438
431
  clientCall = `(serverClient as any).${name}()`;
439
432
  }
440
433
  const cacheKeyParts = [`'${name}'`];
441
- if (signature.hasParams) cacheKeyParts.push("JSON.stringify(params)");
442
- if (signature.hasQuery)
434
+ if (paramsType) cacheKeyParts.push("JSON.stringify(params)");
435
+ if (queryType)
443
436
  cacheKeyParts.push("query ? JSON.stringify(query) : 'no-query'");
444
437
  return `/**
445
438
  * ${endpoint.description || `Server query for ${name}`}
@@ -447,7 +440,7 @@ import { apiConfig } from '${relativePath}';
447
440
  */
448
441
  export const ${queryName} = cache(async (
449
442
  ${paramsList}
450
- ): Promise<${signature.responseType}> => {
443
+ ): Promise<${responseType}> => {
451
444
  return unstable_cache(
452
445
  async () => ${clientCall},
453
446
  [${cacheKeyParts.join(", ")}],
@@ -492,22 +485,24 @@ ${this.generateEndpointTypes()}
492
485
  Object.entries(this.context.apiConfig.endpoints).forEach(
493
486
  ([name, endpoint]) => {
494
487
  const cap = this.capitalize(name);
495
- if (endpoint.response)
496
- types.push(
497
- `export type ${cap}Response = ${this.inferNonNull(`typeof apiConfig.endpoints.${name}.response`)};`
498
- );
499
- if (endpoint.body)
488
+ types.push(
489
+ `export type ${cap}Response = z.infer<NonNullable<typeof apiConfig.endpoints.${name}.response>>;`
490
+ );
491
+ if (endpoint.body) {
500
492
  types.push(
501
- `export type ${cap}Input = ${this.inferNonNull(`typeof apiConfig.endpoints.${name}.body`)};`
493
+ `export type ${cap}Input = z.infer<NonNullable<typeof apiConfig.endpoints.${name}.body>>;`
502
494
  );
503
- if (endpoint.query)
495
+ }
496
+ if (endpoint.query) {
504
497
  types.push(
505
- `export type ${cap}Query = ${this.inferNonNull(`typeof apiConfig.endpoints.${name}.query`)};`
498
+ `export type ${cap}Query = z.infer<NonNullable<typeof apiConfig.endpoints.${name}.query>>;`
506
499
  );
507
- if (endpoint.params)
500
+ }
501
+ if (endpoint.params) {
508
502
  types.push(
509
- `export type ${cap}Params = ${this.inferNonNull(`typeof apiConfig.endpoints.${name}.params`)};`
503
+ `export type ${cap}Params = z.infer<NonNullable<typeof apiConfig.endpoints.${name}.params>>;`
510
504
  );
505
+ }
511
506
  }
512
507
  );
513
508
  return types.join("\n");
@@ -548,32 +543,13 @@ var ClientGenerator = class extends BaseGenerator {
548
543
  import { createAPIClient } from '@cushin/api-runtime';
549
544
  import type { AuthCallbacks } from '@cushin/api-runtime';
550
545
  import { apiConfig } from '${relativePath}';
551
- import { z } from 'zod';
546
+ import type * as Types from './types';
552
547
 
553
- // Type the methods based on endpoints
548
+ // Type the methods based on generated types
554
549
  type APIClientMethods = {
555
- [K in keyof typeof apiConfig.endpoints]: (typeof apiConfig.endpoints)[K] extends infer E
556
- ? E extends { method: "GET"; params: infer P; query: infer Q; response: infer R }
557
- ? (params: P extends z.ZodType ? z.infer<P> : never, query?: Q extends z.ZodType ? z.infer<Q> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
558
- : E extends { method: "GET"; params: infer P; response: infer R }
559
- ? (params: P extends z.ZodType ? z.infer<P> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
560
- : E extends { method: "GET"; query: infer Q; response: infer R }
561
- ? (query?: Q extends z.ZodType ? z.infer<Q> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
562
- : E extends { method: "GET"; response: infer R }
563
- ? () => Promise<R extends z.ZodType ? z.infer<R> : never>
564
- : E extends { method: string; params: infer P; body: infer B; response: infer R }
565
- ? (params: P extends z.ZodType ? z.infer<P> : never, body: B extends z.ZodType ? z.infer<B> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
566
- : E extends { method: string; params: infer P; response: infer R }
567
- ? (params: P extends z.ZodType ? z.infer<P> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
568
- : E extends { method: string; body: infer B; response: infer R }
569
- ? (body: B extends z.ZodType ? z.infer<B> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
570
- : E extends { method: string; response: infer R }
571
- ? () => Promise<R extends z.ZodType ? z.infer<R> : never>
572
- : never
573
- : never;
550
+ ${this.generateAPIClientMethodTypes()}
574
551
  };
575
552
 
576
-
577
553
  // Export singleton instance (will be initialized later)
578
554
  export let baseClient: APIClientMethods & {
579
555
  refreshAuth: () => Promise<void>;
@@ -587,7 +563,7 @@ ${this.generateApiClientMethods()}
587
563
  /**
588
564
  * Initialize API client with auth callbacks
589
565
  * Call this function in your auth provider setup
590
- *
566
+ *
591
567
  * @example
592
568
  * const authCallbacks = {
593
569
  * getTokens: () => getStoredTokens(),
@@ -596,7 +572,7 @@ ${this.generateApiClientMethods()}
596
572
  * await refreshAccessToken();
597
573
  * },
598
574
  * };
599
- *
575
+ *
600
576
  * initializeAPIClient(authCallbacks);
601
577
  */
602
578
  export const initializeAPIClient = (authCallbacks: AuthCallbacks) => {
@@ -615,29 +591,11 @@ export type { AuthCallbacks };
615
591
  const relativePath = path6.relative(path6.dirname(outputPath), endpointsPath).replace(/\\/g, "/").replace(/\.ts$/, "");
616
592
  return `import { createAPIClient } from '@cushin/api-runtime';
617
593
  import { apiConfig } from '${relativePath}';
618
- import { z } from 'zod';
594
+ import type * as Types from './types';
619
595
 
620
- // Type the methods based on endpoints
596
+ // Type the methods based on generated types
621
597
  type APIClientMethods = {
622
- [K in keyof typeof apiConfig.endpoints]: (typeof apiConfig.endpoints)[K] extends infer E
623
- ? E extends { method: "GET"; params: infer P; query: infer Q; response: infer R }
624
- ? (params: P extends z.ZodType ? z.infer<P> : never, query?: Q extends z.ZodType ? z.infer<Q> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
625
- : E extends { method: "GET"; params: infer P; response: infer R }
626
- ? (params: P extends z.ZodType ? z.infer<P> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
627
- : E extends { method: "GET"; query: infer Q; response: infer R }
628
- ? (query?: Q extends z.ZodType ? z.infer<Q> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
629
- : E extends { method: "GET"; response: infer R }
630
- ? () => Promise<R extends z.ZodType ? z.infer<R> : never>
631
- : E extends { method: string; params: infer P; body: infer B; response: infer R }
632
- ? (params: P extends z.ZodType ? z.infer<P> : never, body: B extends z.ZodType ? z.infer<B> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
633
- : E extends { method: string; params: infer P; response: infer R }
634
- ? (params: P extends z.ZodType ? z.infer<P> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
635
- : E extends { method: string; body: infer B; response: infer R }
636
- ? (body: B extends z.ZodType ? z.infer<B> : never) => Promise<R extends z.ZodType ? z.infer<R> : never>
637
- : E extends { method: string; response: infer R }
638
- ? () => Promise<R extends z.ZodType ? z.infer<R> : never>
639
- : never
640
- : never;
598
+ ${this.generateAPIClientMethodTypes()}
641
599
  };
642
600
 
643
601
  /**
@@ -647,48 +605,75 @@ type APIClientMethods = {
647
605
  export const serverClient = createAPIClient(apiConfig) as APIClientMethods;
648
606
  `;
649
607
  }
608
+ generateAPIClientMethodTypes() {
609
+ const methods = [];
610
+ Object.entries(this.context.apiConfig.endpoints).forEach(
611
+ ([name, endpoint]) => {
612
+ const responseType = `Types.${this.getResponseTypeName(name)}`;
613
+ const paramsType = endpoint.params ? `Types.${this.getParamsTypeName(name)}` : null;
614
+ const queryType = endpoint.query ? `Types.${this.getQueryTypeName(name)}` : null;
615
+ const bodyType = endpoint.body ? `Types.${this.getInputTypeName(name)}` : null;
616
+ let signature = "";
617
+ if (endpoint.method === "GET") {
618
+ if (paramsType && queryType) {
619
+ signature = `(params: ${paramsType}, query?: ${queryType}) => Promise<${responseType}>`;
620
+ } else if (paramsType) {
621
+ signature = `(params: ${paramsType}) => Promise<${responseType}>`;
622
+ } else if (queryType) {
623
+ signature = `(query?: ${queryType}) => Promise<${responseType}>`;
624
+ } else {
625
+ signature = `() => Promise<${responseType}>`;
626
+ }
627
+ } else {
628
+ if (paramsType && bodyType) {
629
+ signature = `(params: ${paramsType}, body: ${bodyType}) => Promise<${responseType}>`;
630
+ } else if (paramsType) {
631
+ signature = `(params: ${paramsType}) => Promise<${responseType}>`;
632
+ } else if (bodyType) {
633
+ signature = `(body: ${bodyType}) => Promise<${responseType}>`;
634
+ } else {
635
+ signature = `() => Promise<${responseType}>`;
636
+ }
637
+ }
638
+ methods.push(` ${name}: ${signature};`);
639
+ }
640
+ );
641
+ return methods.join("\n");
642
+ }
650
643
  generateApiClientMethods() {
651
644
  const methods = [];
652
645
  Object.entries(this.context.apiConfig.endpoints).forEach(
653
646
  ([name, endpoint]) => {
654
- const inferParams = this.inferNonNull(
655
- `typeof apiConfig.endpoints.${name}.params`
656
- );
657
- const inferQuery = this.inferNonNull(
658
- `typeof apiConfig.endpoints.${name}.query`
659
- );
660
- const inferBody = this.inferNonNull(
661
- `typeof apiConfig.endpoints.${name}.body`
662
- );
663
- const inferResponse = this.inferNonNull(
664
- `typeof apiConfig.endpoints.${name}.response`
665
- );
647
+ const responseType = `Types.${this.getResponseTypeName(name)}`;
648
+ const paramsType = endpoint.params ? `Types.${this.getParamsTypeName(name)}` : null;
649
+ const queryType = endpoint.query ? `Types.${this.getQueryTypeName(name)}` : null;
650
+ const bodyType = endpoint.body ? `Types.${this.getInputTypeName(name)}` : null;
666
651
  if (endpoint.method === "GET") {
667
- if (endpoint.params && endpoint.query) {
668
- methods.push(` ${name}: (params: ${inferParams}, query?: ${inferQuery}): Promise<${inferResponse}> =>
652
+ if (paramsType && queryType) {
653
+ methods.push(` ${name}: (params: ${paramsType}, query?: ${queryType}): Promise<${responseType}> =>
669
654
  (baseClient as any).${name}(params, query),`);
670
- } else if (endpoint.params) {
671
- methods.push(` ${name}: (params: ${inferParams}): Promise<${inferResponse}> =>
655
+ } else if (paramsType) {
656
+ methods.push(` ${name}: (params: ${paramsType}): Promise<${responseType}> =>
672
657
  (baseClient as any).${name}(params),`);
673
- } else if (endpoint.query) {
674
- methods.push(` ${name}: (query?: ${inferQuery}): Promise<${inferResponse}> =>
658
+ } else if (queryType) {
659
+ methods.push(` ${name}: (query?: ${queryType}): Promise<${responseType}> =>
675
660
  (baseClient as any).${name}(query),`);
676
661
  } else {
677
- methods.push(` ${name}: (): Promise<${inferResponse}> =>
662
+ methods.push(` ${name}: (): Promise<${responseType}> =>
678
663
  (baseClient as any).${name}(),`);
679
664
  }
680
665
  } else {
681
- if (endpoint.params && endpoint.body) {
682
- methods.push(` ${name}: (params: ${inferParams}, body: ${inferBody}): Promise<${inferResponse}> =>
666
+ if (paramsType && bodyType) {
667
+ methods.push(` ${name}: (params: ${paramsType}, body: ${bodyType}): Promise<${responseType}> =>
683
668
  (baseClient as any).${name}(params, body),`);
684
- } else if (endpoint.params) {
685
- methods.push(` ${name}: (params: ${inferParams}): Promise<${inferResponse}> =>
669
+ } else if (paramsType) {
670
+ methods.push(` ${name}: (params: ${paramsType}): Promise<${responseType}> =>
686
671
  (baseClient as any).${name}(params),`);
687
- } else if (endpoint.body) {
688
- methods.push(` ${name}: (body: ${inferBody}): Promise<${inferResponse}> =>
672
+ } else if (bodyType) {
673
+ methods.push(` ${name}: (body: ${bodyType}): Promise<${responseType}> =>
689
674
  (baseClient as any).${name}(body),`);
690
675
  } else {
691
- methods.push(` ${name}: (): Promise<${inferResponse}> =>
676
+ methods.push(` ${name}: (): Promise<${responseType}> =>
692
677
  (baseClient as any).${name}(),`);
693
678
  }
694
679
  }
@@ -716,8 +701,7 @@ var QueryKeysGenerator = class extends BaseGenerator {
716
701
  const endpointsPath = path7.join(this.context.config.endpointsPath);
717
702
  const relativePath = path7.relative(path7.dirname(outputPath), endpointsPath).replace(/\\/g, "/").replace(/\.ts$/, "");
718
703
  const content = `// Auto-generated query keys
719
- import { z } from 'zod';
720
- import { apiConfig } from '${relativePath}';
704
+ import type * as Types from './types';
721
705
 
722
706
  export const queryKeys = {
723
707
  ${this.generateQueryKeysContent()}
@@ -738,16 +722,12 @@ ${this.generateQueryKeysContent()}
738
722
  queryEndpoints.forEach(({ name, endpoint }) => {
739
723
  const keyName = this.getEndpointKeyName(name);
740
724
  if (added.has(keyName)) return;
741
- const inferParams = this.inferNonNull(
742
- `typeof apiConfig.endpoints.${name}.params`
743
- );
744
- const inferQuery = this.inferNonNull(
745
- `typeof apiConfig.endpoints.${name}.query`
746
- );
747
725
  if (endpoint.params || endpoint.query) {
748
726
  const params = [];
749
- if (endpoint.params) params.push(`params?: ${inferParams}`);
750
- if (endpoint.query) params.push(`query?: ${inferQuery}`);
727
+ if (endpoint.params)
728
+ params.push(`params?: Types.${this.getParamsTypeName(name)}`);
729
+ if (endpoint.query)
730
+ params.push(`query?: Types.${this.getQueryTypeName(name)}`);
751
731
  resourceKeys.push(` ${keyName}: (${params.join(", ")}) =>
752
732
  ['${resource}', '${keyName}', ${endpoint.params ? "params" : "undefined"}, ${endpoint.query ? "query" : "undefined"}] as const,`);
753
733
  } else {
@@ -779,15 +759,11 @@ var QueryOptionsGenerator = class extends BaseGenerator {
779
759
  await fs7.writeFile(outputPath, content, "utf-8");
780
760
  }
781
761
  generateContent() {
782
- const outputPath = path8.join(this.context.config.outputDir, "types.ts");
783
- const endpointsPath = path8.join(this.context.config.endpointsPath);
784
- const relativePath = path8.relative(path8.dirname(outputPath), endpointsPath).replace(/\\/g, "/").replace(/\.ts$/, "");
785
762
  const content = `// Auto-generated query options
786
763
  import { queryOptions } from '@tanstack/react-query';
787
764
  import { apiClient } from './client';
788
765
  import { queryKeys } from './query-keys';
789
- import { z } from 'zod';
790
- import { apiConfig } from '${relativePath}';
766
+ import type * as Types from './types';
791
767
 
792
768
  ${this.generateQueryOptionsContent()}
793
769
 
@@ -808,25 +784,19 @@ ${this.generateQueryOptionsExports()}
808
784
  const resourceOptions = [];
809
785
  queries.forEach(({ name, endpoint }) => {
810
786
  const optionName = this.getEndpointKeyName(name);
811
- const inferParams = this.inferNonNull(
812
- `typeof apiConfig.endpoints.${name}.params`
813
- );
814
- const inferQuery = this.inferNonNull(
815
- `typeof apiConfig.endpoints.${name}.query`
816
- );
817
- const inferResponse = this.inferNonNull(
818
- `typeof apiConfig.endpoints.${name}.response`
819
- );
787
+ const responseType = `Types.${this.getResponseTypeName(name)}`;
788
+ const paramsType = endpoint.params ? `Types.${this.getParamsTypeName(name)}` : null;
789
+ const queryType = endpoint.query ? `Types.${this.getQueryTypeName(name)}` : null;
820
790
  const params = [];
821
791
  let apiCall = "";
822
- if (endpoint.params && endpoint.query) {
823
- params.push(`params: ${inferParams}`, `filters?: ${inferQuery}`);
792
+ if (paramsType && queryType) {
793
+ params.push(`params: ${paramsType}`, `filters?: ${queryType}`);
824
794
  apiCall = `apiClient.${name}(params, filters)`;
825
- } else if (endpoint.params) {
826
- params.push(`params: ${inferParams}`);
795
+ } else if (paramsType) {
796
+ params.push(`params: ${paramsType}`);
827
797
  apiCall = `apiClient.${name}(params)`;
828
- } else if (endpoint.query) {
829
- params.push(`filters?: ${inferQuery}`);
798
+ } else if (queryType) {
799
+ params.push(`filters?: ${queryType}`);
830
800
  apiCall = `apiClient.${name}(filters)`;
831
801
  } else {
832
802
  apiCall = `apiClient.${name}()`;
@@ -835,7 +805,7 @@ ${this.generateQueryOptionsExports()}
835
805
  resourceOptions.push(` ${optionName}: (${params.join(", ")}) =>
836
806
  queryOptions({
837
807
  queryKey: ${keyCall},
838
- queryFn: (): Promise<${inferResponse}> => ${apiCall},
808
+ queryFn: (): Promise<${responseType}> => ${apiCall},
839
809
  staleTime: 1000 * 60 * 5,
840
810
  }),`);
841
811
  });
@@ -875,8 +845,7 @@ var PrefetchGenerator = class extends BaseGenerator {
875
845
  const content = `// Auto-generated prefetch utilities
876
846
  import { type QueryClient } from '@tanstack/react-query';
877
847
  ${this.hasQueryOptions() ? "import { apiQueryOptions } from './query-options';" : ""}
878
- import { z } from 'zod';
879
- import { apiConfig } from '../config/endpoints';
848
+ import type * as Types from './types';
880
849
 
881
850
  ${this.generatePrefetchFunctions()}
882
851
  `;
@@ -896,20 +865,14 @@ ${this.generatePrefetchFunctions()}
896
865
  const prefetchName = `prefetch${this.capitalize(name)}`;
897
866
  const resource = this.getResourceFromEndpoint(name, endpoint);
898
867
  const optionName = this.getEndpointKeyName(name);
899
- const inferParams = this.inferNonNull(
900
- `typeof apiConfig.endpoints.${name}.params`
901
- );
902
- const inferQuery = this.inferNonNull(
903
- `typeof apiConfig.endpoints.${name}.query`
904
- );
905
868
  const params = ["queryClient: QueryClient"];
906
869
  const optionParams = [];
907
870
  if (endpoint.params) {
908
- params.push(`params: ${inferParams}`);
871
+ params.push(`params: Types.${this.getParamsTypeName(name)}`);
909
872
  optionParams.push("params");
910
873
  }
911
874
  if (endpoint.query) {
912
- params.push(`filters?: ${inferQuery}`);
875
+ params.push(`filters?: Types.${this.getQueryTypeName(name)}`);
913
876
  optionParams.push("filters");
914
877
  }
915
878
  return `export const ${prefetchName} = async (${params.join(",\n ")}) => {