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/cli.js +701 -580
- package/dist/core.d.mts +23 -3
- package/dist/core.d.ts +23 -3
- package/dist/core.js +1 -0
- package/dist/core.mjs +1 -0
- package/dist/react.d.mts +91 -13
- package/dist/react.d.ts +91 -13
- package/dist/react.js +98 -4
- package/dist/react.mjs +94 -4
- package/dist/sdk.d.mts +44 -12
- package/dist/sdk.d.ts +44 -12
- package/dist/sdk.js +23 -1
- package/dist/sdk.mjs +23 -1
- package/dist/vue.d.mts +9 -0
- package/dist/vue.d.ts +9 -0
- package/package.json +3 -2
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
|
|
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
|
|
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
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
|
|
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
|
|
42
|
-
params
|
|
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
|
-
|
|
48
|
-
|
|
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<
|
|
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,
|
|
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<
|
|
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
|
-
|
|
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
|
|
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
|
|
42
|
-
params
|
|
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
|
-
|
|
48
|
-
|
|
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<
|
|
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,
|
|
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<
|
|
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
|
-
|
|
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,
|
|
32
|
-
const
|
|
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
|
});
|