@navios/react-query 0.7.0 → 1.0.0-alpha.1

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.
Files changed (124) hide show
  1. package/CHANGELOG.md +166 -0
  2. package/README.md +152 -4
  3. package/dist/src/__tests__/errorSchema.spec.d.mts +2 -0
  4. package/dist/src/__tests__/errorSchema.spec.d.mts.map +1 -0
  5. package/dist/src/client/__type-tests__/from-endpoint.spec-d.d.mts +2 -0
  6. package/dist/src/client/__type-tests__/from-endpoint.spec-d.d.mts.map +1 -0
  7. package/dist/src/client/__type-tests__/infinite-query.spec-d.d.mts +2 -0
  8. package/dist/src/client/__type-tests__/infinite-query.spec-d.d.mts.map +1 -0
  9. package/dist/src/client/__type-tests__/multipart-mutation.spec-d.d.mts +2 -0
  10. package/dist/src/client/__type-tests__/multipart-mutation.spec-d.d.mts.map +1 -0
  11. package/dist/src/client/__type-tests__/mutation.spec-d.d.mts +2 -0
  12. package/dist/src/client/__type-tests__/mutation.spec-d.d.mts.map +1 -0
  13. package/dist/src/client/__type-tests__/query.spec-d.d.mts +2 -0
  14. package/dist/src/client/__type-tests__/query.spec-d.d.mts.map +1 -0
  15. package/dist/src/client/declare-client.d.mts +15 -8
  16. package/dist/src/client/declare-client.d.mts.map +1 -1
  17. package/dist/src/client/types/from-endpoint.d.mts +130 -0
  18. package/dist/src/client/types/from-endpoint.d.mts.map +1 -0
  19. package/dist/src/client/types/helpers.d.mts +74 -0
  20. package/dist/src/client/types/helpers.d.mts.map +1 -0
  21. package/dist/src/client/types/index.d.mts +21 -0
  22. package/dist/src/client/types/index.d.mts.map +1 -0
  23. package/dist/src/client/types/infinite-query.d.mts +61 -0
  24. package/dist/src/client/types/infinite-query.d.mts.map +1 -0
  25. package/dist/src/client/types/multipart-mutation.d.mts +98 -0
  26. package/dist/src/client/types/multipart-mutation.d.mts.map +1 -0
  27. package/dist/src/client/types/mutation.d.mts +75 -0
  28. package/dist/src/client/types/mutation.d.mts.map +1 -0
  29. package/dist/src/client/types/query.d.mts +65 -0
  30. package/dist/src/client/types/query.d.mts.map +1 -0
  31. package/dist/src/client/types.d.mts +1 -608
  32. package/dist/src/client/types.d.mts.map +1 -1
  33. package/dist/src/common/types.d.mts +30 -3
  34. package/dist/src/common/types.d.mts.map +1 -1
  35. package/dist/src/mutation/index.d.mts +1 -0
  36. package/dist/src/mutation/index.d.mts.map +1 -1
  37. package/dist/src/mutation/make-hook.d.mts +42 -16
  38. package/dist/src/mutation/make-hook.d.mts.map +1 -1
  39. package/dist/src/mutation/optimistic.d.mts +166 -0
  40. package/dist/src/mutation/optimistic.d.mts.map +1 -0
  41. package/dist/src/mutation/types.d.mts +51 -19
  42. package/dist/src/mutation/types.d.mts.map +1 -1
  43. package/dist/src/query/index.d.mts +1 -0
  44. package/dist/src/query/index.d.mts.map +1 -1
  45. package/dist/src/query/key-creator.d.mts.map +1 -1
  46. package/dist/src/query/make-infinite-options.d.mts +3 -2
  47. package/dist/src/query/make-infinite-options.d.mts.map +1 -1
  48. package/dist/src/query/make-options.d.mts +42 -12
  49. package/dist/src/query/make-options.d.mts.map +1 -1
  50. package/dist/src/query/prefetch.d.mts +245 -0
  51. package/dist/src/query/prefetch.d.mts.map +1 -0
  52. package/dist/src/query/types.d.mts +35 -17
  53. package/dist/src/query/types.d.mts.map +1 -1
  54. package/dist/tsconfig.tsbuildinfo +1 -1
  55. package/lib/index.cjs +454 -37
  56. package/lib/index.cjs.map +1 -1
  57. package/lib/index.d.cts +1021 -598
  58. package/lib/index.d.cts.map +1 -1
  59. package/lib/index.d.mts +1019 -596
  60. package/lib/index.d.mts.map +1 -1
  61. package/lib/index.mjs +441 -29
  62. package/lib/index.mjs.map +1 -1
  63. package/package.json +8 -8
  64. package/src/__tests__/declare-client.spec.mts +1 -2
  65. package/src/__tests__/errorSchema.spec.mts +391 -0
  66. package/src/__tests__/make-mutation.spec.mts +6 -5
  67. package/src/__tests__/makeDataTag.spec.mts +2 -1
  68. package/src/__tests__/makeQueryOptions.spec.mts +2 -1
  69. package/src/client/__type-tests__/from-endpoint.spec-d.mts +550 -0
  70. package/src/client/__type-tests__/infinite-query.spec-d.mts +648 -0
  71. package/src/client/__type-tests__/multipart-mutation.spec-d.mts +725 -0
  72. package/src/client/__type-tests__/mutation.spec-d.mts +757 -0
  73. package/src/client/__type-tests__/query.spec-d.mts +701 -0
  74. package/src/client/declare-client.mts +59 -34
  75. package/src/client/types/from-endpoint.mts +345 -0
  76. package/src/client/types/helpers.mts +140 -0
  77. package/src/client/types/index.mts +26 -0
  78. package/src/client/types/infinite-query.mts +133 -0
  79. package/src/client/types/multipart-mutation.mts +264 -0
  80. package/src/client/types/mutation.mts +176 -0
  81. package/src/client/types/query.mts +132 -0
  82. package/src/client/types.mts +1 -1935
  83. package/src/common/types.mts +48 -3
  84. package/src/mutation/index.mts +1 -0
  85. package/src/mutation/make-hook.mts +171 -63
  86. package/src/mutation/optimistic.mts +294 -0
  87. package/src/mutation/types.mts +102 -29
  88. package/src/query/index.mts +1 -0
  89. package/src/query/key-creator.mts +24 -13
  90. package/src/query/make-infinite-options.mts +53 -10
  91. package/src/query/make-options.mts +184 -43
  92. package/src/query/prefetch.mts +326 -0
  93. package/src/query/types.mts +76 -16
  94. package/dist/src/declare-client.d.mts +0 -31
  95. package/dist/src/declare-client.d.mts.map +0 -1
  96. package/dist/src/make-infinite-query-options.d.mts +0 -13
  97. package/dist/src/make-infinite-query-options.d.mts.map +0 -1
  98. package/dist/src/make-mutation.d.mts +0 -15
  99. package/dist/src/make-mutation.d.mts.map +0 -1
  100. package/dist/src/make-query-options.d.mts +0 -15
  101. package/dist/src/make-query-options.d.mts.map +0 -1
  102. package/dist/src/types/client-endpoint-helper.d.mts +0 -8
  103. package/dist/src/types/client-endpoint-helper.d.mts.map +0 -1
  104. package/dist/src/types/client-instance.d.mts +0 -211
  105. package/dist/src/types/client-instance.d.mts.map +0 -1
  106. package/dist/src/types/index.d.mts +0 -8
  107. package/dist/src/types/index.d.mts.map +0 -1
  108. package/dist/src/types/mutation-args.d.mts +0 -10
  109. package/dist/src/types/mutation-args.d.mts.map +0 -1
  110. package/dist/src/types/mutation-helpers.d.mts +0 -10
  111. package/dist/src/types/mutation-helpers.d.mts.map +0 -1
  112. package/dist/src/types/query-args.d.mts +0 -8
  113. package/dist/src/types/query-args.d.mts.map +0 -1
  114. package/dist/src/types/query-helpers.d.mts +0 -14
  115. package/dist/src/types/query-helpers.d.mts.map +0 -1
  116. package/dist/src/types/query-url-params-args.d.mts +0 -5
  117. package/dist/src/types/query-url-params-args.d.mts.map +0 -1
  118. package/dist/src/types.d.mts +0 -49
  119. package/dist/src/types.d.mts.map +0 -1
  120. package/dist/src/utils/mutation-key.creator.d.mts +0 -39
  121. package/dist/src/utils/mutation-key.creator.d.mts.map +0 -1
  122. package/dist/src/utils/query-key-creator.d.mts +0 -24
  123. package/dist/src/utils/query-key-creator.d.mts.map +0 -1
  124. package/src/client/__type-tests__/client-instance.spec-d.mts +0 -852
@@ -1,6 +1,8 @@
1
1
  import type {
2
2
  AnyEndpointConfig,
3
- NaviosZodRequest,
3
+ ErrorSchemaRecord,
4
+ InferErrorSchemaOutput,
5
+ RequestArgs,
4
6
  UrlHasParams,
5
7
  UrlParams,
6
8
  } from '@navios/builder'
@@ -9,57 +11,119 @@ import type {
9
11
  MutationFunctionContext,
10
12
  UseMutationOptions,
11
13
  } from '@tanstack/react-query'
12
- import type { z, ZodObject } from 'zod/v4'
14
+ import type { z, ZodObject, ZodType } from 'zod/v4'
13
15
 
14
16
  import type { ProcessResponseFunction } from '../common/types.mjs'
15
17
 
18
+ /**
19
+ * Compute the response input type based on discriminator and error schema.
20
+ * When UseDiscriminator=true and errorSchema is present, errors are included as a union.
21
+ * When UseDiscriminator=false, only the success type is returned (errors are thrown).
22
+ *
23
+ * @template UseDiscriminator - Whether to include error types in the response union
24
+ * @template ResponseSchema - The success response schema
25
+ * @template ErrorSchema - The error schema record (optional)
26
+ */
27
+ type ComputeResponseInput<
28
+ UseDiscriminator extends boolean,
29
+ ResponseSchema extends ZodType,
30
+ ErrorSchema extends ErrorSchemaRecord | undefined,
31
+ > = UseDiscriminator extends true
32
+ ? ErrorSchema extends ErrorSchemaRecord
33
+ ? z.output<ResponseSchema> | InferErrorSchemaOutput<ErrorSchema>
34
+ : z.output<ResponseSchema>
35
+ : z.output<ResponseSchema>
36
+
16
37
  /**
17
38
  * Arguments for mutation functions based on URL params, request schema, and query schema.
39
+ * Uses RequestArgs from builder for consistency.
18
40
  */
19
41
  export type MutationArgs<
20
42
  Url extends string = string,
21
- RequestSchema = unknown,
22
- QuerySchema = unknown,
23
- > = (UrlHasParams<Url> extends true ? { urlParams: UrlParams<Url> } : {}) &
24
- (RequestSchema extends ZodObject ? { data: z.input<RequestSchema> } : {}) &
25
- (QuerySchema extends ZodObject ? { params: z.input<QuerySchema> } : {})
43
+ RequestSchema extends ZodType | undefined = undefined,
44
+ QuerySchema extends ZodObject | undefined = undefined,
45
+ > = RequestArgs<Url, QuerySchema, RequestSchema>
26
46
 
27
47
  /**
28
48
  * Helper methods attached to mutation hooks.
49
+ *
50
+ * @template Url - The URL template string
51
+ * @template Result - The mutation result type
29
52
  */
30
53
  export type MutationHelpers<Url extends string, Result = unknown> =
31
54
  UrlHasParams<Url> extends true
32
55
  ? {
33
- mutationKey: (params: UrlParams<Url>) => DataTag<[Url], Result, Error>
34
- useIsMutating: (keyParams: UrlParams<Url>) => boolean
56
+ /**
57
+ * Generates a mutation key for the given URL parameters.
58
+ * Useful for tracking mutations or invalidating related queries.
59
+ */
60
+ mutationKey: (params: {
61
+ urlParams: UrlParams<Url>
62
+ }) => DataTag<[Url], Result, Error>
63
+ /**
64
+ * Returns true if a mutation with the given URL parameters is currently in progress.
65
+ * Requires `useKey: true` to be set when creating the mutation.
66
+ */
67
+ useIsMutating: (keyParams: { urlParams: UrlParams<Url> }) => boolean
35
68
  }
36
69
  : {
70
+ /**
71
+ * Generates a mutation key.
72
+ * Useful for tracking mutations or invalidating related queries.
73
+ */
37
74
  mutationKey: () => DataTag<[Url], Result, Error>
75
+ /**
76
+ * Returns true if a mutation is currently in progress.
77
+ * Requires `useKey: true` to be set when creating the mutation.
78
+ */
38
79
  useIsMutating: () => boolean
39
80
  }
40
81
 
41
82
  /**
42
83
  * Base parameters for mutation configuration.
84
+ *
85
+ * @template UseDiscriminator - When `true`, errors are returned as union types in processResponse.
86
+ * When `false` (default), errors are thrown and not included in TResponse.
43
87
  */
44
88
  export interface MutationParams<
45
89
  Config extends AnyEndpointConfig,
46
90
  TData = unknown,
47
- TVariables = NaviosZodRequest<Config>,
48
- TResponse = z.output<Config['responseSchema']>,
91
+ TVariables = RequestArgs<
92
+ Config['url'],
93
+ Config['querySchema'],
94
+ Config['requestSchema'],
95
+ Config['urlParamsSchema']
96
+ >,
97
+ _TResponse = ComputeResponseInput<false, Config['responseSchema'], Config['errorSchema']>,
49
98
  TOnMutateResult = unknown,
50
99
  TContext = unknown,
51
100
  UseKey extends boolean = false,
101
+ UseDiscriminator extends boolean = false,
102
+ TError = UseDiscriminator extends true
103
+ ? Error
104
+ : Config['errorSchema'] extends ErrorSchemaRecord
105
+ ? InferErrorSchemaOutput<Config['errorSchema']> | Error
106
+ : Error,
52
107
  > extends Omit<
53
- UseMutationOptions<TData, Error, TVariables>,
54
- | 'mutationKey'
55
- | 'mutationFn'
56
- | 'onMutate'
57
- | 'onSuccess'
58
- | 'onError'
59
- | 'onSettled'
60
- | 'scope'
61
- > {
62
- processResponse?: ProcessResponseFunction<TData, TResponse>
108
+ UseMutationOptions<
109
+ TData,
110
+ // When UseDiscriminator is false and errorSchema exists, errors are thrown, so Error is correct.
111
+ // When UseDiscriminator is true, errors are part of the response union, but network/other errors still throw Error.
112
+ TError,
113
+ TVariables
114
+ >,
115
+ | 'mutationKey'
116
+ | 'mutationFn'
117
+ | 'onMutate'
118
+ | 'onSuccess'
119
+ | 'onError'
120
+ | 'onSettled'
121
+ | 'scope'
122
+ > {
123
+ processResponse?: ProcessResponseFunction<
124
+ TData,
125
+ ComputeResponseInput<UseDiscriminator, Config['responseSchema'], Config['errorSchema']>
126
+ >
63
127
  /**
64
128
  * React hooks that will prepare the context for the mutation onSuccess and onError
65
129
  * callbacks. This is useful for when you want to use the context in the callbacks
@@ -72,7 +136,7 @@ export interface MutationParams<
72
136
  MutationFunctionContext & { onMutateResult: TOnMutateResult | undefined },
73
137
  ) => void | Promise<void>
74
138
  onError?: (
75
- err: unknown,
139
+ err: TError,
76
140
  variables: TVariables,
77
141
  context: TContext &
78
142
  MutationFunctionContext & { onMutateResult: TOnMutateResult | undefined },
@@ -83,7 +147,7 @@ export interface MutationParams<
83
147
  ) => TOnMutateResult | Promise<TOnMutateResult>
84
148
  onSettled?: (
85
149
  data: TData | undefined,
86
- error: Error | null,
150
+ error: TError | null,
87
151
  variables: TVariables,
88
152
  context: TContext &
89
153
  MutationFunctionContext & { onMutateResult: TOnMutateResult | undefined },
@@ -109,20 +173,29 @@ export interface MutationParams<
109
173
  /** @deprecated Use MutationArgs instead */
110
174
  export type ClientMutationArgs<
111
175
  Url extends string = string,
112
- RequestSchema = unknown,
113
- QuerySchema = unknown,
176
+ RequestSchema extends ZodType | undefined = undefined,
177
+ QuerySchema extends ZodObject | undefined = undefined,
114
178
  > = MutationArgs<Url, RequestSchema, QuerySchema>
115
179
 
116
180
  /** @deprecated Use MutationParams instead */
117
181
  export type BaseMutationParams<
118
182
  Config extends AnyEndpointConfig,
119
183
  TData = unknown,
120
- TVariables = NaviosZodRequest<Config>,
184
+ TVariables = RequestArgs<
185
+ Config['url'],
186
+ Config['querySchema'],
187
+ Config['requestSchema'],
188
+ Config['urlParamsSchema']
189
+ >,
121
190
  TResponse = z.output<Config['responseSchema']>,
122
191
  TContext = unknown,
123
192
  UseKey extends boolean = false,
124
193
  > = MutationParams<Config, TData, TVariables, TResponse, TContext, UseKey>
125
194
 
126
- /** @deprecated Use NaviosZodRequest from @navios/builder instead */
127
- export type BaseMutationArgs<Config extends AnyEndpointConfig> =
128
- NaviosZodRequest<Config>
195
+ /** @deprecated Use RequestArgs from @navios/builder instead */
196
+ export type BaseMutationArgs<Config extends AnyEndpointConfig> = RequestArgs<
197
+ Config['url'],
198
+ Config['querySchema'],
199
+ Config['requestSchema'],
200
+ Config['urlParamsSchema']
201
+ >
@@ -2,3 +2,4 @@ export * from './types.mjs'
2
2
  export * from './key-creator.mjs'
3
3
  export * from './make-options.mjs'
4
4
  export * from './make-infinite-options.mjs'
5
+ export * from './prefetch.mjs'
@@ -46,14 +46,18 @@ export function createQueryKey<
46
46
  params && 'querySchema' in config && 'params' in params
47
47
  ? config.querySchema?.parse(params.params)
48
48
  : []
49
+
50
+ // Use bindUrlParams to get the bound URL, then split it to get the parts
51
+ const boundUrl = bindUrlParams<Url>(
52
+ url,
53
+ params && 'urlParams' in params ? params : {},
54
+ config.urlParamsSchema,
55
+ )
56
+ const boundUrlParts = boundUrl.split('/').filter(Boolean)
57
+
49
58
  return [
50
59
  ...(options.keyPrefix ?? []),
51
- ...urlParts.map((part) =>
52
- part.startsWith('$')
53
- ? // @ts-expect-error TS2339 We know that the urlParams are defined only if the url has params
54
- params.urlParams[part.slice(1)].toString()
55
- : part,
56
- ),
60
+ ...boundUrlParts,
57
61
  ...(options.keySuffix ?? []),
58
62
  queryParams ?? [],
59
63
  ] as unknown as DataTag<
@@ -68,14 +72,17 @@ export function createQueryKey<
68
72
  },
69
73
  // @ts-expect-error We have correct types in return type
70
74
  filterKey: (params) => {
75
+ // Use bindUrlParams to get the bound URL, then split it to get the parts
76
+ const boundUrl = bindUrlParams<Url>(
77
+ url,
78
+ params && 'urlParams' in params ? params : {},
79
+ config.urlParamsSchema,
80
+ )
81
+ const boundUrlParts = boundUrl.split('/').filter(Boolean)
82
+
71
83
  return [
72
84
  ...(options.keyPrefix ?? []),
73
- ...urlParts.map((part) =>
74
- part.startsWith('$')
75
- ? // @ts-expect-error TS2339 We know that the urlParams are defined only if the url has params
76
- params.urlParams[part.slice(1)].toString()
77
- : part,
78
- ),
85
+ ...boundUrlParts,
79
86
  ...(options.keySuffix ?? []),
80
87
  ] as unknown as DataTag<
81
88
  Split<Url, '/'>,
@@ -89,7 +96,11 @@ export function createQueryKey<
89
96
  },
90
97
 
91
98
  bindToUrl: (params) => {
92
- return bindUrlParams<Url>(url, params ?? ({} as never))
99
+ return bindUrlParams<Url>(
100
+ url,
101
+ params && 'urlParams' in params ? params : {},
102
+ config.urlParamsSchema,
103
+ )
93
104
  },
94
105
  }
95
106
  }
@@ -66,8 +66,12 @@ export function makeInfiniteQueryOptions<
66
66
  : never => {
67
67
  // @ts-expect-error TS2322 We know that the processResponse is defined
68
68
  return infiniteQueryOptions({
69
+ // @ts-expect-error TS2345 We bind the url params only if the url has params
69
70
  queryKey: queryKey.dataTag(params),
70
- queryFn: async ({ signal, pageParam }): Promise<ReturnType<Options['processResponse']>> => {
71
+ queryFn: async ({
72
+ signal,
73
+ pageParam,
74
+ }): Promise<ReturnType<Options['processResponse']>> => {
71
75
  let result
72
76
  try {
73
77
  result = await endpoint({
@@ -92,37 +96,76 @@ export function makeInfiniteQueryOptions<
92
96
  getPreviousPageParam: options.getPreviousPageParam,
93
97
  initialPageParam:
94
98
  options.initialPageParam ??
95
- config.querySchema.parse('params' in params ? params.params : {}),
99
+ config.querySchema?.parse('params' in params ? params.params : {}) ??
100
+ ('params' in params ? params.params : {}),
96
101
  ...baseQuery,
97
102
  })
98
103
  }
104
+ /** The query key creator for this infinite query endpoint */
99
105
  res.queryKey = queryKey
100
106
 
107
+ /**
108
+ * React hook that executes the infinite query.
109
+ * Uses `useInfiniteQuery` from TanStack Query internally.
110
+ *
111
+ * @param params - URL parameters and initial query parameters
112
+ * @returns Infinite query result with pages, fetchNextPage, etc.
113
+ */
101
114
  res.use = (params: QueryArgs<Config['url'], Config['querySchema']>) => {
102
115
  return useInfiniteQuery(res(params))
103
116
  }
104
117
 
105
- res.useSuspense = (params: QueryArgs<Config['url'], Config['querySchema']>) => {
118
+ /**
119
+ * React hook that executes the infinite query with Suspense support.
120
+ * Uses `useSuspenseInfiniteQuery` from TanStack Query internally.
121
+ * The component will suspend while loading and throw on error.
122
+ *
123
+ * @param params - URL parameters and initial query parameters
124
+ * @returns Infinite query result with pages guaranteed to be defined
125
+ */
126
+ res.useSuspense = (
127
+ params: QueryArgs<Config['url'], Config['querySchema']>,
128
+ ) => {
106
129
  return useSuspenseInfiniteQuery(res(params))
107
130
  }
108
131
 
132
+ /**
133
+ * Creates a function that invalidates this specific infinite query in the cache.
134
+ * Call the returned function to trigger the invalidation.
135
+ *
136
+ * @param queryClient - The TanStack Query client instance
137
+ * @param params - The exact parameters used for this query
138
+ * @returns A function that when called invalidates the query
139
+ */
109
140
  res.invalidate = (
110
141
  queryClient: QueryClient,
111
142
  params: QueryArgs<Config['url'], Config['querySchema']>,
112
143
  ) => {
113
- return queryClient.invalidateQueries({
114
- queryKey: res.queryKey.dataTag(params),
115
- })
144
+ return () =>
145
+ queryClient.invalidateQueries({
146
+ // @ts-expect-error TS2345 We bind the url params only if the url has params
147
+ queryKey: res.queryKey.dataTag(params),
148
+ })
116
149
  }
117
150
 
151
+ /**
152
+ * Creates a function that invalidates all infinite queries matching the URL pattern.
153
+ * Useful for invalidating all queries for a resource regardless of query params.
154
+ *
155
+ * @param queryClient - The TanStack Query client instance
156
+ * @param params - URL parameters only (query params are ignored for matching)
157
+ * @returns A function that when called invalidates all matching queries
158
+ */
118
159
  res.invalidateAll = (
119
160
  queryClient: QueryClient,
120
161
  params: QueryArgs<Config['url'], Config['querySchema']>,
121
162
  ) => {
122
- return queryClient.invalidateQueries({
123
- queryKey: res.queryKey.filterKey(params),
124
- exact: false,
125
- })
163
+ return () =>
164
+ queryClient.invalidateQueries({
165
+ // @ts-expect-error TS2345 We bind the url params only if the url has params
166
+ queryKey: res.queryKey.filterKey(params),
167
+ exact: false,
168
+ })
126
169
  }
127
170
 
128
171
  return res
@@ -1,34 +1,83 @@
1
- import type { AbstractEndpoint, AnyEndpointConfig } from '@navios/builder'
1
+ import type {
2
+ EndpointHandler,
3
+ EndpointOptions,
4
+ InferEndpointReturn,
5
+ Simplify,
6
+ } from '@navios/builder'
2
7
  import type {
3
8
  DataTag,
4
9
  QueryClient,
5
10
  UseQueryOptions,
6
11
  UseSuspenseQueryOptions,
7
12
  } from '@tanstack/react-query'
13
+ import type { ZodObject, ZodType } from 'zod/v4'
8
14
 
9
15
  import { queryOptions, useQuery, useSuspenseQuery } from '@tanstack/react-query'
10
16
 
11
17
  import type { Split } from '../common/types.mjs'
12
- import type { QueryArgs, QueryParams } from './types.mjs'
18
+ import type { QueryArgs, QueryHelpers, QueryResult } from './types.mjs'
13
19
 
14
20
  import { createQueryKey } from './key-creator.mjs'
15
21
 
22
+ /**
23
+ * Options for makeQueryOptions.
24
+ */
25
+ export interface MakeQueryOptionsParams<
26
+ Options extends EndpointOptions,
27
+ UseDiscriminator extends boolean = false,
28
+ Result = QueryResult<Options, UseDiscriminator>,
29
+ > {
30
+ keyPrefix?: string[]
31
+ keySuffix?: string[]
32
+ onFail?: (err: unknown) => void
33
+ processResponse: (
34
+ data: InferEndpointReturn<Options, UseDiscriminator>,
35
+ ) => Result
36
+ }
37
+
16
38
  /**
17
39
  * Creates query options for a given endpoint.
18
40
  *
19
41
  * Returns a function that generates TanStack Query options when called with params.
20
42
  * The returned function also has helper methods attached (use, useSuspense, invalidate, etc.)
21
43
  *
22
- * @param endpoint - The navios endpoint to create query options for
44
+ * Uses const generics pattern to automatically infer types from the endpoint configuration.
45
+ *
46
+ * @param endpoint - The navios endpoint handler (from builder's declareEndpoint)
23
47
  * @param options - Query configuration including processResponse
24
48
  * @param baseQuery - Optional base query options to merge
25
49
  * @returns A function that generates query options with attached helpers
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const getUser = api.declareEndpoint({
54
+ * method: 'GET',
55
+ * url: '/users/$userId',
56
+ * responseSchema: userSchema,
57
+ * })
58
+ *
59
+ * const queryOptions = makeQueryOptions(getUser, {
60
+ * processResponse: (data) => data,
61
+ * })
62
+ *
63
+ * const { data } = queryOptions.useSuspense({ urlParams: { userId: '123' } })
64
+ * ```
26
65
  */
27
66
  export function makeQueryOptions<
28
- Config extends AnyEndpointConfig,
29
- Options extends QueryParams<Config>,
67
+ const Options extends EndpointOptions,
68
+ UseDiscriminator extends boolean = false,
69
+ Result = QueryResult<Options, UseDiscriminator>,
30
70
  BaseQuery extends Omit<
31
- UseQueryOptions<ReturnType<Options['processResponse']>, Error, any>,
71
+ UseQueryOptions<Result, Error, any>,
72
+ | 'queryKey'
73
+ | 'queryFn'
74
+ | 'getNextPageParam'
75
+ | 'initialPageParam'
76
+ | 'enabled'
77
+ | 'throwOnError'
78
+ | 'placeholderData'
79
+ > = Omit<
80
+ UseQueryOptions<Result, Error, any>,
32
81
  | 'queryKey'
33
82
  | 'queryFn'
34
83
  | 'getNextPageParam'
@@ -38,34 +87,58 @@ export function makeQueryOptions<
38
87
  | 'placeholderData'
39
88
  >,
40
89
  >(
41
- endpoint: AbstractEndpoint<Config>,
42
- options: Options,
43
- baseQuery: BaseQuery = {} as BaseQuery,
44
- ) {
90
+ endpoint: EndpointHandler<Options, UseDiscriminator>,
91
+ options: MakeQueryOptionsParams<Options, UseDiscriminator, Result>,
92
+ baseQuery?: BaseQuery,
93
+ ): ((
94
+ params: Simplify<
95
+ QueryArgs<
96
+ Options['url'],
97
+ Options extends { querySchema: infer Q extends ZodObject }
98
+ ? Q
99
+ : undefined,
100
+ Options extends { requestSchema: infer R extends ZodType } ? R : undefined
101
+ >
102
+ >,
103
+ ) => UseSuspenseQueryOptions<
104
+ Result,
105
+ Error,
106
+ BaseQuery extends { select: (...args: any[]) => infer T } ? T : Result,
107
+ DataTag<Split<Options['url'], '/'>, Result, Error>
108
+ >) &
109
+ QueryHelpers<
110
+ Options['url'],
111
+ Options extends { querySchema: infer Q extends ZodObject } ? Q : undefined,
112
+ Result,
113
+ false,
114
+ Options extends { requestSchema: infer R extends ZodType } ? R : undefined
115
+ > {
45
116
  const config = endpoint.config
46
- const queryKey = createQueryKey(config, options, false)
117
+ const queryKey = createQueryKey(config as any, options as any, false)
47
118
  const processResponse = options.processResponse
48
119
 
49
120
  const result = (
50
- params: QueryArgs<Config['url'], Config['querySchema']>,
51
- ): Options['processResponse'] extends (...args: any[]) => infer Result
52
- ? UseSuspenseQueryOptions<
53
- Result,
54
- Error,
55
- BaseQuery['select'] extends (...args: any[]) => infer T ? T : Result,
56
- DataTag<Split<Config['url'], '/'>, Result, Error>
121
+ params: Simplify<
122
+ QueryArgs<
123
+ Options['url'],
124
+ Options extends { querySchema: infer Q extends ZodObject }
125
+ ? Q
126
+ : undefined,
127
+ Options extends { requestSchema: infer R extends ZodType }
128
+ ? R
129
+ : undefined
57
130
  >
58
- : never => {
59
- // @ts-expect-error TS2322 We know that the processResponse is defined
131
+ >,
132
+ ): any => {
60
133
  return queryOptions({
61
- queryKey: queryKey.dataTag(params),
62
- queryFn: async ({ signal }): Promise<ReturnType<Options['processResponse']>> => {
134
+ queryKey: queryKey.dataTag(params as any),
135
+ queryFn: async ({ signal }): Promise<Result> => {
63
136
  let result
64
137
  try {
65
138
  result = await endpoint({
66
139
  signal,
67
140
  ...params,
68
- })
141
+ } as any)
69
142
  } catch (err) {
70
143
  if (options.onFail) {
71
144
  options.onFail(err)
@@ -73,38 +146,106 @@ export function makeQueryOptions<
73
146
  throw err
74
147
  }
75
148
 
76
- return processResponse(result) as ReturnType<Options['processResponse']>
149
+ return processResponse(result)
77
150
  },
78
151
  ...baseQuery,
79
152
  })
80
153
  }
81
- result.queryKey = queryKey
82
- result.use = (params: QueryArgs<Config['url'], Config['querySchema']>) => {
154
+
155
+ /** The query key creator for this endpoint */
156
+ result.queryKey = queryKey as any
157
+
158
+ /**
159
+ * React hook that executes the query.
160
+ * Uses `useQuery` from TanStack Query internally.
161
+ *
162
+ * @param params - URL parameters, query parameters, and request body
163
+ * @returns Query result with data, isLoading, error, etc.
164
+ */
165
+ result.use = (params: any) => {
83
166
  return useQuery(result(params))
84
167
  }
85
168
 
86
- result.useSuspense = (params: QueryArgs<Config['url'], Config['querySchema']>) => {
169
+ /**
170
+ * React hook that executes the query with Suspense support.
171
+ * Uses `useSuspenseQuery` from TanStack Query internally.
172
+ * The component will suspend while loading and throw on error.
173
+ *
174
+ * @param params - URL parameters, query parameters, and request body
175
+ * @returns Query result with data guaranteed to be defined
176
+ */
177
+ result.useSuspense = (params: any) => {
87
178
  return useSuspenseQuery(result(params))
88
179
  }
89
180
 
90
- result.invalidate = (
91
- queryClient: QueryClient,
92
- params: QueryArgs<Config['url'], Config['querySchema']>,
93
- ) => {
94
- return queryClient.invalidateQueries({
95
- queryKey: result.queryKey.dataTag(params),
96
- })
181
+ /**
182
+ * Creates a function that invalidates a specific query in the cache.
183
+ * Call the returned function to trigger the invalidation.
184
+ *
185
+ * @param queryClient - The TanStack Query client instance
186
+ * @param params - The exact parameters used for this query
187
+ * @returns A function that when called invalidates the query
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * const invalidate = getUser.invalidate(queryClient, { urlParams: { userId: '123' } })
192
+ * await invalidate() // Invalidates this specific query
193
+ * ```
194
+ */
195
+ result.invalidate = (queryClient: QueryClient, params: any) => {
196
+ return () =>
197
+ queryClient.invalidateQueries({
198
+ queryKey: result.queryKey.dataTag(params),
199
+ })
97
200
  }
98
201
 
99
- result.invalidateAll = (
100
- queryClient: QueryClient,
101
- params: QueryArgs<Config['url'], Config['querySchema']>,
102
- ) => {
103
- return queryClient.invalidateQueries({
104
- queryKey: result.queryKey.filterKey(params),
105
- exact: false,
106
- })
202
+ /**
203
+ * Creates a function that invalidates all queries matching the URL pattern.
204
+ * Useful for invalidating all queries for a resource regardless of query params.
205
+ *
206
+ * @param queryClient - The TanStack Query client instance
207
+ * @param params - URL parameters only (query params are ignored for matching)
208
+ * @returns A function that when called invalidates all matching queries
209
+ *
210
+ * @example
211
+ * ```ts
212
+ * const invalidateAll = getUserPosts.invalidateAll(queryClient, { urlParams: { userId: '123' } })
213
+ * await invalidateAll() // Invalidates all getUserPosts queries for user 123
214
+ * ```
215
+ */
216
+ result.invalidateAll = (queryClient: QueryClient, params: any) => {
217
+ return () =>
218
+ queryClient.invalidateQueries({
219
+ queryKey: result.queryKey.filterKey(params),
220
+ exact: false,
221
+ })
107
222
  }
108
223
 
109
- return result
224
+ return result as unknown as ((
225
+ params: Simplify<
226
+ QueryArgs<
227
+ Options['url'],
228
+ Options extends { querySchema: infer Q extends ZodObject }
229
+ ? Q
230
+ : undefined,
231
+ Options extends { requestSchema: infer R extends ZodType }
232
+ ? R
233
+ : undefined
234
+ >
235
+ >,
236
+ ) => UseSuspenseQueryOptions<
237
+ Result,
238
+ Error,
239
+ BaseQuery extends { select: (...args: any[]) => infer T } ? T : Result,
240
+ DataTag<Split<Options['url'], '/'>, Result, Error>
241
+ >) &
242
+ QueryHelpers<
243
+ Options['url'],
244
+ Options extends { querySchema: infer Q extends ZodObject }
245
+ ? Q
246
+ : undefined,
247
+ Result,
248
+ false,
249
+ Options extends { requestSchema: infer R extends ZodType } ? R : undefined
250
+ >
110
251
  }