routesync 1.0.19 → 1.0.21

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/core.d.mts CHANGED
@@ -12,6 +12,14 @@ interface ServiceConfig {
12
12
  timeout?: number;
13
13
  retry?: RetryConfig;
14
14
  cache?: boolean;
15
+ validateResponse?: boolean;
16
+ onValidationError?: (error: unknown, context: {
17
+ endpoint: string;
18
+ method: string;
19
+ path: string;
20
+ request: unknown;
21
+ response: unknown;
22
+ }) => void;
15
23
  }
16
24
  interface RetryConfig {
17
25
  attempts: number;
@@ -27,6 +35,7 @@ interface AuthConfig {
27
35
 
28
36
  declare class HttpClient {
29
37
  private client;
38
+ readonly config: ServiceConfig;
30
39
  constructor(config: ServiceConfig);
31
40
  private setupInterceptors;
32
41
  setToken(token: string): void;
@@ -73,11 +82,15 @@ interface RequestOptions {
73
82
  timeout?: number;
74
83
  signal?: AbortSignal;
75
84
  }
76
- interface RouteDefinition {
85
+ interface ResponseSchema<T> {
86
+ parse(input: unknown): T;
87
+ }
88
+ interface RouteDefinition<TResponse = unknown, TParams = unknown, TBody = unknown> {
77
89
  method: HttpMethod;
78
90
  path: string;
79
91
  auth?: boolean;
80
92
  schema?: RouteSchema;
93
+ responseSchema?: ResponseSchema<TResponse>;
81
94
  mapper?: RouteMapper;
82
95
  headers?: Record<string, string>;
83
96
  cache?: unknown;
@@ -85,10 +98,13 @@ interface RouteDefinition {
85
98
  body?: Record<string, any>;
86
99
  params?: Record<string, any>;
87
100
  query?: Record<string, any>;
101
+ _typeResponse?: TResponse;
102
+ _typeParams?: TParams;
103
+ _typeBody?: TBody;
88
104
  }
89
105
  interface ApiDefinition {
90
106
  [group: string]: {
91
- [action: string]: RouteDefinition;
107
+ [action: string]: RouteDefinition<any, any, any>;
92
108
  };
93
109
  }
94
110
 
@@ -218,6 +234,10 @@ interface ParsedRoute {
218
234
  schema?: Record<string, any>;
219
235
  group?: string;
220
236
  action?: string;
237
+ response?: {
238
+ type: string;
239
+ collection: boolean;
240
+ };
221
241
  }
222
242
  interface ParsedColumn {
223
243
  name: string;
@@ -233,4 +253,4 @@ interface ParsedModel {
233
253
  casts?: Record<string, string>;
234
254
  }
235
255
 
236
- export { type ApiDefinition, ApiError, type ApiResponse, type AuthConfig, AuthMiddleware, ErrorHandler, HttpClient, type HttpMethod, Interceptor, type PaginationMeta, type ParsedChannel, type ParsedColumn, type ParsedModel, type ParsedRoute, PathResolver, QueryBuilder, Request, type RequestOptions, Response, type RetryConfig, type RouteDefinition, type RouteManifest, type RouteMapper, type RouteParserSchema, type RouteSchema, type RouteSchemaMap, type RouteSchemaValue, type RouteTransform, type RouteTransformMap, type ServiceConfig, TokenManager, camelCase, camelCaseKeys, snakeCase, snakeCaseKeys };
256
+ export { type ApiDefinition, ApiError, type ApiResponse, type AuthConfig, AuthMiddleware, ErrorHandler, HttpClient, type HttpMethod, Interceptor, type PaginationMeta, type ParsedChannel, type ParsedColumn, type ParsedModel, type ParsedRoute, PathResolver, QueryBuilder, Request, type RequestOptions, Response, type ResponseSchema, type RetryConfig, type RouteDefinition, type RouteManifest, type RouteMapper, type RouteParserSchema, type RouteSchema, type RouteSchemaMap, type RouteSchemaValue, type RouteTransform, type RouteTransformMap, type ServiceConfig, TokenManager, camelCase, camelCaseKeys, snakeCase, snakeCaseKeys };
package/dist/core.d.ts CHANGED
@@ -12,6 +12,14 @@ interface ServiceConfig {
12
12
  timeout?: number;
13
13
  retry?: RetryConfig;
14
14
  cache?: boolean;
15
+ validateResponse?: boolean;
16
+ onValidationError?: (error: unknown, context: {
17
+ endpoint: string;
18
+ method: string;
19
+ path: string;
20
+ request: unknown;
21
+ response: unknown;
22
+ }) => void;
15
23
  }
16
24
  interface RetryConfig {
17
25
  attempts: number;
@@ -27,6 +35,7 @@ interface AuthConfig {
27
35
 
28
36
  declare class HttpClient {
29
37
  private client;
38
+ readonly config: ServiceConfig;
30
39
  constructor(config: ServiceConfig);
31
40
  private setupInterceptors;
32
41
  setToken(token: string): void;
@@ -73,11 +82,15 @@ interface RequestOptions {
73
82
  timeout?: number;
74
83
  signal?: AbortSignal;
75
84
  }
76
- interface RouteDefinition {
85
+ interface ResponseSchema<T> {
86
+ parse(input: unknown): T;
87
+ }
88
+ interface RouteDefinition<TResponse = unknown, TParams = unknown, TBody = unknown> {
77
89
  method: HttpMethod;
78
90
  path: string;
79
91
  auth?: boolean;
80
92
  schema?: RouteSchema;
93
+ responseSchema?: ResponseSchema<TResponse>;
81
94
  mapper?: RouteMapper;
82
95
  headers?: Record<string, string>;
83
96
  cache?: unknown;
@@ -85,10 +98,13 @@ interface RouteDefinition {
85
98
  body?: Record<string, any>;
86
99
  params?: Record<string, any>;
87
100
  query?: Record<string, any>;
101
+ _typeResponse?: TResponse;
102
+ _typeParams?: TParams;
103
+ _typeBody?: TBody;
88
104
  }
89
105
  interface ApiDefinition {
90
106
  [group: string]: {
91
- [action: string]: RouteDefinition;
107
+ [action: string]: RouteDefinition<any, any, any>;
92
108
  };
93
109
  }
94
110
 
@@ -218,6 +234,10 @@ interface ParsedRoute {
218
234
  schema?: Record<string, any>;
219
235
  group?: string;
220
236
  action?: string;
237
+ response?: {
238
+ type: string;
239
+ collection: boolean;
240
+ };
221
241
  }
222
242
  interface ParsedColumn {
223
243
  name: string;
@@ -233,4 +253,4 @@ interface ParsedModel {
233
253
  casts?: Record<string, string>;
234
254
  }
235
255
 
236
- export { type ApiDefinition, ApiError, type ApiResponse, type AuthConfig, AuthMiddleware, ErrorHandler, HttpClient, type HttpMethod, Interceptor, type PaginationMeta, type ParsedChannel, type ParsedColumn, type ParsedModel, type ParsedRoute, PathResolver, QueryBuilder, Request, type RequestOptions, Response, type RetryConfig, type RouteDefinition, type RouteManifest, type RouteMapper, type RouteParserSchema, type RouteSchema, type RouteSchemaMap, type RouteSchemaValue, type RouteTransform, type RouteTransformMap, type ServiceConfig, TokenManager, camelCase, camelCaseKeys, snakeCase, snakeCaseKeys };
256
+ export { type ApiDefinition, ApiError, type ApiResponse, type AuthConfig, AuthMiddleware, ErrorHandler, HttpClient, type HttpMethod, Interceptor, type PaginationMeta, type ParsedChannel, type ParsedColumn, type ParsedModel, type ParsedRoute, PathResolver, QueryBuilder, Request, type RequestOptions, Response, type ResponseSchema, type RetryConfig, type RouteDefinition, type RouteManifest, type RouteMapper, type RouteParserSchema, type RouteSchema, type RouteSchemaMap, type RouteSchemaValue, type RouteTransform, type RouteTransformMap, type ServiceConfig, TokenManager, camelCase, camelCaseKeys, snakeCase, snakeCaseKeys };
package/dist/core.js CHANGED
@@ -87,6 +87,7 @@ function snakeCaseKeys(obj) {
87
87
  var import_axios = __toESM(require("axios"));
88
88
  var HttpClient = class {
89
89
  constructor(config) {
90
+ this.config = config;
90
91
  this.client = import_axios.default.create({
91
92
  baseURL: config.baseURL,
92
93
  timeout: config.timeout ?? 1e4,
package/dist/core.mjs CHANGED
@@ -38,6 +38,7 @@ function snakeCaseKeys(obj) {
38
38
  import axios from "axios";
39
39
  var HttpClient = class {
40
40
  constructor(config) {
41
+ this.config = config;
41
42
  this.client = axios.create({
42
43
  baseURL: config.baseURL,
43
44
  timeout: config.timeout ?? 1e4,
package/dist/react.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
2
+ import { UseQueryOptions, InfiniteData, UseInfiniteQueryOptions, UseSuspenseQueryOptions, UseMutationOptions, QueryClient } from '@tanstack/react-query';
3
3
 
4
4
  type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
5
5
  type RouteTransform = (value: unknown) => unknown;
@@ -24,11 +24,15 @@ interface RouteSchemaMap {
24
24
  }
25
25
  type RouteSchemaValue = RouteTransform | RouteParserSchema;
26
26
  type RouteSchema = RouteSchemaValue | RouteSchemaMap;
27
- interface RouteDefinition {
27
+ interface ResponseSchema<T> {
28
+ parse(input: unknown): T;
29
+ }
30
+ interface RouteDefinition<TResponse = unknown, TParams = unknown, TBody = unknown> {
28
31
  method: HttpMethod;
29
32
  path: string;
30
33
  auth?: boolean;
31
34
  schema?: RouteSchema;
35
+ responseSchema?: ResponseSchema<TResponse>;
32
36
  mapper?: RouteMapper;
33
37
  headers?: Record<string, string>;
34
38
  cache?: unknown;
@@ -36,20 +40,33 @@ interface RouteDefinition {
36
40
  body?: Record<string, any>;
37
41
  params?: Record<string, any>;
38
42
  query?: Record<string, any>;
43
+ _typeResponse?: TResponse;
44
+ _typeParams?: TParams;
45
+ _typeBody?: TBody;
39
46
  }
40
47
 
41
- type CallOptions = {
42
- params?: Record<string, any>;
48
+ type EndpointCallableOptions<TParams, TBody> = (unknown extends TParams ? {} : {
49
+ params: TParams;
50
+ }) & (unknown extends TBody ? {} : {
51
+ body: TBody;
52
+ }) & {
43
53
  query?: Record<string, any>;
44
- body?: Record<string, any>;
45
54
  headers?: Record<string, string>;
46
55
  };
47
- interface EndpointCallable {
48
- <TResponse = unknown>(options?: CallOptions): Promise<TResponse>;
56
+ type OptionalIfEmpty<T> = keyof Omit<T, 'query' | 'headers'> extends never ? [options?: T] : [options: T];
57
+ interface ApiError {
58
+ message: string;
59
+ status?: number;
60
+ errors?: Record<string, string[]>;
61
+ }
62
+ interface EndpointCallable<TResponse = unknown, TParams = unknown, TBody = unknown> {
63
+ (...args: OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>): Promise<TResponse>;
49
64
  /** Original RouteDefinition — used by useApiQuery / useApiMutation */
50
- $def: RouteDefinition;
65
+ $def: RouteDefinition<TResponse, TParams, TBody>;
51
66
  /** Stable TanStack query key: [group, action] */
52
67
  $key: string[];
68
+ /** Consistent query key builder that incorporates params/query if provided */
69
+ $queryKey: (...args: OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>) => unknown[];
53
70
  }
54
71
 
55
72
  /**
@@ -59,7 +76,24 @@ interface EndpointCallable {
59
76
  * const { data, isLoading } = useApiQuery(api.produk.list)
60
77
  * const { data } = useApiQuery(api.produk.detail, { params: { id: 10 } })
61
78
  */
62
- declare function useApiQuery<T = any>(endpoint: EndpointCallable, options?: CallOptions, queryOptions?: Omit<UseQueryOptions<T>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<T>, Error>;
79
+ declare function useApiQuery<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TData = TResponse>(endpoint: EndpointCallable<TResponse, TParams, TBody>, ...args: [
80
+ ...OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>,
81
+ queryOptions?: Omit<UseQueryOptions<TResponse, TError, TData>, 'queryKey' | 'queryFn'>
82
+ ]): _tanstack_react_query.UseQueryResult<NoInfer<TData>, TError>;
83
+ /**
84
+ * useApiSuspenseQuery — generic wrapper for Suspense-enabled data fetching (TanStack v5).
85
+ */
86
+ declare function useApiSuspenseQuery<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TData = TResponse>(endpoint: EndpointCallable<TResponse, TParams, TBody>, ...args: [
87
+ ...OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>,
88
+ queryOptions?: Omit<UseSuspenseQueryOptions<TResponse, TError, TData>, 'queryKey' | 'queryFn'>
89
+ ]): _tanstack_react_query.UseSuspenseQueryResult<TData, TError>;
90
+ /**
91
+ * useApiInfiniteQuery — framework agnostic paginated fetching.
92
+ */
93
+ declare function useApiInfiniteQuery<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TData = InfiniteData<TResponse>, TPageParam = unknown>(endpoint: EndpointCallable<TResponse, TParams, TBody>, ...args: [
94
+ ...OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>,
95
+ queryOptions: Omit<UseInfiniteQueryOptions<TResponse, TError, TData, any, TPageParam>, 'queryKey' | 'queryFn'>
96
+ ]): _tanstack_react_query.UseInfiniteQueryResult<TData, TError>;
63
97
 
64
98
  /**
65
99
  * useApiMutation — accepts an endpoint callable directly.
@@ -74,11 +108,40 @@ declare function useApiQuery<T = any>(endpoint: EndpointCallable, options?: Call
74
108
  * invalidate: [api.cart.list, api.orders.index],
75
109
  * })
76
110
  */
77
- interface ApiMutationOptions<TData, TVariables> extends Omit<UseMutationOptions<TData, unknown, TVariables>, 'mutationFn'> {
111
+ interface ApiMutationOptions<TData, TError, TVariables, TContext = unknown> extends Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn'> {
78
112
  /** Extra endpoints to invalidate on success (in addition to the auto group invalidation). */
79
- invalidate?: EndpointCallable[];
113
+ invalidate?: EndpointCallable<any, any, any>[];
80
114
  }
81
- declare function useApiMutation<TData = any, TVariables extends CallOptions = CallOptions>(endpoint: EndpointCallable, options?: ApiMutationOptions<TData, TVariables>): _tanstack_react_query.UseMutationResult<TData, unknown, TVariables, unknown>;
115
+ declare function useApiMutation<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TContext = unknown>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: ApiMutationOptions<TResponse, TError, EndpointCallableOptions<TParams, TBody>, TContext>): _tanstack_react_query.UseMutationResult<TResponse, TError, EndpointCallableOptions<TParams, TBody>, TContext>;
116
+
117
+ /**
118
+ * useApiQueryClient — a typed wrapper over TanStack's QueryClient
119
+ *
120
+ * Provides ergonomic helpers like invalidateEndpoint and prefetchEndpoint
121
+ * with strong typing based on the RouteSync SDK contracts.
122
+ */
123
+ declare function useApiQueryClient(): {
124
+ queryClient: QueryClient;
125
+ /**
126
+ * Invalidate specific queries related to an endpoint.
127
+ * Optionally pass parameters to invalidate a more specific cache entry.
128
+ */
129
+ invalidateEndpoint: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: EndpointCallableOptions<TParams, TBody>) => Promise<void>;
130
+ /**
131
+ * Prefetch data for an endpoint into the cache.
132
+ * Useful for SSR, RSC hydration, or proactive prefetching.
133
+ */
134
+ prefetchEndpoint: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: EndpointCallableOptions<TParams, TBody>) => Promise<void>;
135
+ /**
136
+ * Manually update the cache for a specific endpoint.
137
+ * Often used for optimistic updates in mutations.
138
+ */
139
+ setEndpointData: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options: EndpointCallableOptions<TParams, TBody> | undefined, updater: TResponse | ((oldData: TResponse | undefined) => TResponse)) => unknown;
140
+ /**
141
+ * Retrieve the current cached data for a specific endpoint.
142
+ */
143
+ getEndpointData: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: EndpointCallableOptions<TParams, TBody>) => TResponse | undefined;
144
+ };
82
145
 
83
146
  /**
84
147
  * createHooks — generate typed hooks from an api group.
@@ -93,4 +156,19 @@ declare function useApiMutation<TData = any, TVariables extends CallOptions = Ca
93
156
  */
94
157
  declare function createHooks<T extends Record<string, EndpointCallable>>(group: T): { [K in keyof T as `use${Capitalize<string & K>}`]: T[K] extends EndpointCallable ? T[K]["$def"]["method"] extends "GET" | "DELETE" ? (options?: any, queryOptions?: any) => ReturnType<typeof useApiQuery> : (options?: any) => ReturnType<typeof useApiMutation> : never; };
95
158
 
96
- export { type ApiMutationOptions, createHooks, useApiMutation, useApiQuery };
159
+ interface UseFormSetError<TFieldValues extends Record<string, any>> {
160
+ (name: keyof TFieldValues | string, error: {
161
+ type: string;
162
+ message?: string;
163
+ }): void;
164
+ }
165
+ /**
166
+ * Parses an unknown error and safely pipes 422 Unprocessable Entity
167
+ * validation messages to react-hook-form's setError.
168
+ *
169
+ * @param error - The error thrown by a RouteSync mutation
170
+ * @param setError - The `setError` function destructured from `useForm()`
171
+ */
172
+ declare function setFormErrors<TFieldValues extends Record<string, any>>(error: unknown, setError: UseFormSetError<TFieldValues>): void;
173
+
174
+ export { type ApiMutationOptions, createHooks, setFormErrors, useApiInfiniteQuery, useApiMutation, useApiQuery, useApiQueryClient, useApiSuspenseQuery };
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _tanstack_react_query from '@tanstack/react-query';
2
- import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
2
+ import { UseQueryOptions, InfiniteData, UseInfiniteQueryOptions, UseSuspenseQueryOptions, UseMutationOptions, QueryClient } from '@tanstack/react-query';
3
3
 
4
4
  type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
5
5
  type RouteTransform = (value: unknown) => unknown;
@@ -24,11 +24,15 @@ interface RouteSchemaMap {
24
24
  }
25
25
  type RouteSchemaValue = RouteTransform | RouteParserSchema;
26
26
  type RouteSchema = RouteSchemaValue | RouteSchemaMap;
27
- interface RouteDefinition {
27
+ interface ResponseSchema<T> {
28
+ parse(input: unknown): T;
29
+ }
30
+ interface RouteDefinition<TResponse = unknown, TParams = unknown, TBody = unknown> {
28
31
  method: HttpMethod;
29
32
  path: string;
30
33
  auth?: boolean;
31
34
  schema?: RouteSchema;
35
+ responseSchema?: ResponseSchema<TResponse>;
32
36
  mapper?: RouteMapper;
33
37
  headers?: Record<string, string>;
34
38
  cache?: unknown;
@@ -36,20 +40,33 @@ interface RouteDefinition {
36
40
  body?: Record<string, any>;
37
41
  params?: Record<string, any>;
38
42
  query?: Record<string, any>;
43
+ _typeResponse?: TResponse;
44
+ _typeParams?: TParams;
45
+ _typeBody?: TBody;
39
46
  }
40
47
 
41
- type CallOptions = {
42
- params?: Record<string, any>;
48
+ type EndpointCallableOptions<TParams, TBody> = (unknown extends TParams ? {} : {
49
+ params: TParams;
50
+ }) & (unknown extends TBody ? {} : {
51
+ body: TBody;
52
+ }) & {
43
53
  query?: Record<string, any>;
44
- body?: Record<string, any>;
45
54
  headers?: Record<string, string>;
46
55
  };
47
- interface EndpointCallable {
48
- <TResponse = unknown>(options?: CallOptions): Promise<TResponse>;
56
+ type OptionalIfEmpty<T> = keyof Omit<T, 'query' | 'headers'> extends never ? [options?: T] : [options: T];
57
+ interface ApiError {
58
+ message: string;
59
+ status?: number;
60
+ errors?: Record<string, string[]>;
61
+ }
62
+ interface EndpointCallable<TResponse = unknown, TParams = unknown, TBody = unknown> {
63
+ (...args: OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>): Promise<TResponse>;
49
64
  /** Original RouteDefinition — used by useApiQuery / useApiMutation */
50
- $def: RouteDefinition;
65
+ $def: RouteDefinition<TResponse, TParams, TBody>;
51
66
  /** Stable TanStack query key: [group, action] */
52
67
  $key: string[];
68
+ /** Consistent query key builder that incorporates params/query if provided */
69
+ $queryKey: (...args: OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>) => unknown[];
53
70
  }
54
71
 
55
72
  /**
@@ -59,7 +76,24 @@ interface EndpointCallable {
59
76
  * const { data, isLoading } = useApiQuery(api.produk.list)
60
77
  * const { data } = useApiQuery(api.produk.detail, { params: { id: 10 } })
61
78
  */
62
- declare function useApiQuery<T = any>(endpoint: EndpointCallable, options?: CallOptions, queryOptions?: Omit<UseQueryOptions<T>, 'queryKey' | 'queryFn'>): _tanstack_react_query.UseQueryResult<NoInfer<T>, Error>;
79
+ declare function useApiQuery<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TData = TResponse>(endpoint: EndpointCallable<TResponse, TParams, TBody>, ...args: [
80
+ ...OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>,
81
+ queryOptions?: Omit<UseQueryOptions<TResponse, TError, TData>, 'queryKey' | 'queryFn'>
82
+ ]): _tanstack_react_query.UseQueryResult<NoInfer<TData>, TError>;
83
+ /**
84
+ * useApiSuspenseQuery — generic wrapper for Suspense-enabled data fetching (TanStack v5).
85
+ */
86
+ declare function useApiSuspenseQuery<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TData = TResponse>(endpoint: EndpointCallable<TResponse, TParams, TBody>, ...args: [
87
+ ...OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>,
88
+ queryOptions?: Omit<UseSuspenseQueryOptions<TResponse, TError, TData>, 'queryKey' | 'queryFn'>
89
+ ]): _tanstack_react_query.UseSuspenseQueryResult<TData, TError>;
90
+ /**
91
+ * useApiInfiniteQuery — framework agnostic paginated fetching.
92
+ */
93
+ declare function useApiInfiniteQuery<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TData = InfiniteData<TResponse>, TPageParam = unknown>(endpoint: EndpointCallable<TResponse, TParams, TBody>, ...args: [
94
+ ...OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>,
95
+ queryOptions: Omit<UseInfiniteQueryOptions<TResponse, TError, TData, any, TPageParam>, 'queryKey' | 'queryFn'>
96
+ ]): _tanstack_react_query.UseInfiniteQueryResult<TData, TError>;
63
97
 
64
98
  /**
65
99
  * useApiMutation — accepts an endpoint callable directly.
@@ -74,11 +108,40 @@ declare function useApiQuery<T = any>(endpoint: EndpointCallable, options?: Call
74
108
  * invalidate: [api.cart.list, api.orders.index],
75
109
  * })
76
110
  */
77
- interface ApiMutationOptions<TData, TVariables> extends Omit<UseMutationOptions<TData, unknown, TVariables>, 'mutationFn'> {
111
+ interface ApiMutationOptions<TData, TError, TVariables, TContext = unknown> extends Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn'> {
78
112
  /** Extra endpoints to invalidate on success (in addition to the auto group invalidation). */
79
- invalidate?: EndpointCallable[];
113
+ invalidate?: EndpointCallable<any, any, any>[];
80
114
  }
81
- declare function useApiMutation<TData = any, TVariables extends CallOptions = CallOptions>(endpoint: EndpointCallable, options?: ApiMutationOptions<TData, TVariables>): _tanstack_react_query.UseMutationResult<TData, unknown, TVariables, unknown>;
115
+ declare function useApiMutation<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError, TContext = unknown>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: ApiMutationOptions<TResponse, TError, EndpointCallableOptions<TParams, TBody>, TContext>): _tanstack_react_query.UseMutationResult<TResponse, TError, EndpointCallableOptions<TParams, TBody>, TContext>;
116
+
117
+ /**
118
+ * useApiQueryClient — a typed wrapper over TanStack's QueryClient
119
+ *
120
+ * Provides ergonomic helpers like invalidateEndpoint and prefetchEndpoint
121
+ * with strong typing based on the RouteSync SDK contracts.
122
+ */
123
+ declare function useApiQueryClient(): {
124
+ queryClient: QueryClient;
125
+ /**
126
+ * Invalidate specific queries related to an endpoint.
127
+ * Optionally pass parameters to invalidate a more specific cache entry.
128
+ */
129
+ invalidateEndpoint: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: EndpointCallableOptions<TParams, TBody>) => Promise<void>;
130
+ /**
131
+ * Prefetch data for an endpoint into the cache.
132
+ * Useful for SSR, RSC hydration, or proactive prefetching.
133
+ */
134
+ prefetchEndpoint: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: EndpointCallableOptions<TParams, TBody>) => Promise<void>;
135
+ /**
136
+ * Manually update the cache for a specific endpoint.
137
+ * Often used for optimistic updates in mutations.
138
+ */
139
+ setEndpointData: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options: EndpointCallableOptions<TParams, TBody> | undefined, updater: TResponse | ((oldData: TResponse | undefined) => TResponse)) => unknown;
140
+ /**
141
+ * Retrieve the current cached data for a specific endpoint.
142
+ */
143
+ getEndpointData: <TResponse, TParams, TBody>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: EndpointCallableOptions<TParams, TBody>) => TResponse | undefined;
144
+ };
82
145
 
83
146
  /**
84
147
  * createHooks — generate typed hooks from an api group.
@@ -93,4 +156,19 @@ declare function useApiMutation<TData = any, TVariables extends CallOptions = Ca
93
156
  */
94
157
  declare function createHooks<T extends Record<string, EndpointCallable>>(group: T): { [K in keyof T as `use${Capitalize<string & K>}`]: T[K] extends EndpointCallable ? T[K]["$def"]["method"] extends "GET" | "DELETE" ? (options?: any, queryOptions?: any) => ReturnType<typeof useApiQuery> : (options?: any) => ReturnType<typeof useApiMutation> : never; };
95
158
 
96
- export { type ApiMutationOptions, createHooks, useApiMutation, useApiQuery };
159
+ interface UseFormSetError<TFieldValues extends Record<string, any>> {
160
+ (name: keyof TFieldValues | string, error: {
161
+ type: string;
162
+ message?: string;
163
+ }): void;
164
+ }
165
+ /**
166
+ * Parses an unknown error and safely pipes 422 Unprocessable Entity
167
+ * validation messages to react-hook-form's setError.
168
+ *
169
+ * @param error - The error thrown by a RouteSync mutation
170
+ * @param setError - The `setError` function destructured from `useForm()`
171
+ */
172
+ declare function setFormErrors<TFieldValues extends Record<string, any>>(error: unknown, setError: UseFormSetError<TFieldValues>): void;
173
+
174
+ export { type ApiMutationOptions, createHooks, setFormErrors, useApiInfiniteQuery, useApiMutation, useApiQuery, useApiQueryClient, useApiSuspenseQuery };
package/dist/react.js CHANGED
@@ -21,21 +21,53 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  createHooks: () => createHooks,
24
+ setFormErrors: () => setFormErrors,
25
+ useApiInfiniteQuery: () => useApiInfiniteQuery,
24
26
  useApiMutation: () => useApiMutation,
25
- useApiQuery: () => useApiQuery
27
+ useApiQuery: () => useApiQuery,
28
+ useApiQueryClient: () => useApiQueryClient,
29
+ useApiSuspenseQuery: () => useApiSuspenseQuery
26
30
  });
27
31
  module.exports = __toCommonJS(src_exports);
28
32
 
29
33
  // packages/react/src/hooks/useQuery.ts
30
34
  var import_react_query = require("@tanstack/react-query");
31
- function useApiQuery(endpoint, options, queryOptions) {
32
- const queryKey = options ? [...endpoint.$key, options] : endpoint.$key;
35
+ function useApiQuery(endpoint, ...args) {
36
+ const options = args[0];
37
+ const queryOptions = args[1];
38
+ const queryKey = endpoint.$queryKey(options);
33
39
  return (0, import_react_query.useQuery)({
34
40
  queryKey,
35
41
  queryFn: () => endpoint(options),
36
42
  ...queryOptions
37
43
  });
38
44
  }
45
+ function useApiSuspenseQuery(endpoint, ...args) {
46
+ const options = args[0];
47
+ const queryOptions = args[1];
48
+ const queryKey = endpoint.$queryKey(options);
49
+ return (0, import_react_query.useSuspenseQuery)({
50
+ queryKey,
51
+ queryFn: () => endpoint(options),
52
+ ...queryOptions
53
+ });
54
+ }
55
+ function useApiInfiniteQuery(endpoint, ...args) {
56
+ const options = args[0];
57
+ const queryOptions = args.length > 1 ? args[1] : args[0];
58
+ const queryKey = endpoint.$queryKey(options);
59
+ return (0, import_react_query.useInfiniteQuery)({
60
+ queryKey,
61
+ queryFn: ({ pageParam }) => {
62
+ const fetchOptions = { ...options };
63
+ if (pageParam !== void 0) {
64
+ fetchOptions.query = { ...fetchOptions.query || {}, page: pageParam };
65
+ }
66
+ return endpoint(fetchOptions);
67
+ },
68
+ ...queryOptions
69
+ });
70
+ }
39
71
 
40
72
  // packages/react/src/hooks/useMutation.ts
41
73
  var import_react_query2 = require("@tanstack/react-query");
@@ -55,6 +87,47 @@ function useApiMutation(endpoint, options) {
55
87
  });
56
88
  }
57
89
 
90
+ // packages/react/src/hooks/useQueryClient.ts
91
+ var import_react_query3 = require("@tanstack/react-query");
92
+ function useApiQueryClient() {
93
+ const queryClient = (0, import_react_query3.useQueryClient)();
94
+ return {
95
+ queryClient,
96
+ /**
97
+ * Invalidate specific queries related to an endpoint.
98
+ * Optionally pass parameters to invalidate a more specific cache entry.
99
+ */
100
+ invalidateEndpoint: (endpoint, options) => {
101
+ return queryClient.invalidateQueries({
102
+ queryKey: endpoint.$queryKey(options)
103
+ });
104
+ },
105
+ /**
106
+ * Prefetch data for an endpoint into the cache.
107
+ * Useful for SSR, RSC hydration, or proactive prefetching.
108
+ */
109
+ prefetchEndpoint: (endpoint, options) => {
110
+ return queryClient.prefetchQuery({
111
+ queryKey: endpoint.$queryKey(options),
112
+ queryFn: () => endpoint(options)
113
+ });
114
+ },
115
+ /**
116
+ * Manually update the cache for a specific endpoint.
117
+ * Often used for optimistic updates in mutations.
118
+ */
119
+ setEndpointData: (endpoint, options, updater) => {
120
+ return queryClient.setQueryData(endpoint.$queryKey(options), updater);
121
+ },
122
+ /**
123
+ * Retrieve the current cached data for a specific endpoint.
124
+ */
125
+ getEndpointData: (endpoint, options) => {
126
+ return queryClient.getQueryData(endpoint.$queryKey(options));
127
+ }
128
+ };
129
+ }
130
+
58
131
  // packages/react/src/hooks/createHooks.ts
59
132
  function createHooks(group) {
60
133
  const hooks = {};
@@ -69,9 +142,30 @@ function createHooks(group) {
69
142
  }
70
143
  return hooks;
71
144
  }
145
+
146
+ // packages/react/src/utils/form.ts
147
+ function setFormErrors(error, setError) {
148
+ if (error && typeof error === "object" && "status" in error && error.status === 422) {
149
+ const apiError = error;
150
+ const errors = apiError.errors;
151
+ if (errors && typeof errors === "object") {
152
+ for (const [field, messages] of Object.entries(errors)) {
153
+ if (Array.isArray(messages) && messages.length > 0) {
154
+ setError(field, { type: "server", message: String(messages[0]) });
155
+ } else if (typeof messages === "string") {
156
+ setError(field, { type: "server", message: messages });
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
72
162
  // Annotate the CommonJS export names for ESM import in node:
73
163
  0 && (module.exports = {
74
164
  createHooks,
165
+ setFormErrors,
166
+ useApiInfiniteQuery,
75
167
  useApiMutation,
76
- useApiQuery
168
+ useApiQuery,
169
+ useApiQueryClient,
170
+ useApiSuspenseQuery
77
171
  });