routesync 1.0.19 → 1.0.20
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 +698 -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 +31 -11
- package/dist/react.d.ts +31 -11
- package/dist/react.js +4 -2
- package/dist/react.mjs +4 -2
- 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
|
@@ -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,10 @@ 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>;
|
|
63
83
|
|
|
64
84
|
/**
|
|
65
85
|
* useApiMutation — accepts an endpoint callable directly.
|
|
@@ -74,11 +94,11 @@ declare function useApiQuery<T = any>(endpoint: EndpointCallable, options?: Call
|
|
|
74
94
|
* invalidate: [api.cart.list, api.orders.index],
|
|
75
95
|
* })
|
|
76
96
|
*/
|
|
77
|
-
interface ApiMutationOptions<TData, TVariables> extends Omit<UseMutationOptions<TData,
|
|
97
|
+
interface ApiMutationOptions<TData, TError, TVariables> extends Omit<UseMutationOptions<TData, TError, TVariables>, 'mutationFn'> {
|
|
78
98
|
/** Extra endpoints to invalidate on success (in addition to the auto group invalidation). */
|
|
79
|
-
invalidate?: EndpointCallable[];
|
|
99
|
+
invalidate?: EndpointCallable<any, any, any>[];
|
|
80
100
|
}
|
|
81
|
-
declare function useApiMutation<
|
|
101
|
+
declare function useApiMutation<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: ApiMutationOptions<TResponse, TError, EndpointCallableOptions<TParams, TBody>>): _tanstack_react_query.UseMutationResult<TResponse, TError, EndpointCallableOptions<TParams, TBody>, unknown>;
|
|
82
102
|
|
|
83
103
|
/**
|
|
84
104
|
* createHooks — generate typed hooks from an api group.
|
package/dist/react.d.ts
CHANGED
|
@@ -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,10 @@ 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>;
|
|
63
83
|
|
|
64
84
|
/**
|
|
65
85
|
* useApiMutation — accepts an endpoint callable directly.
|
|
@@ -74,11 +94,11 @@ declare function useApiQuery<T = any>(endpoint: EndpointCallable, options?: Call
|
|
|
74
94
|
* invalidate: [api.cart.list, api.orders.index],
|
|
75
95
|
* })
|
|
76
96
|
*/
|
|
77
|
-
interface ApiMutationOptions<TData, TVariables> extends Omit<UseMutationOptions<TData,
|
|
97
|
+
interface ApiMutationOptions<TData, TError, TVariables> extends Omit<UseMutationOptions<TData, TError, TVariables>, 'mutationFn'> {
|
|
78
98
|
/** Extra endpoints to invalidate on success (in addition to the auto group invalidation). */
|
|
79
|
-
invalidate?: EndpointCallable[];
|
|
99
|
+
invalidate?: EndpointCallable<any, any, any>[];
|
|
80
100
|
}
|
|
81
|
-
declare function useApiMutation<
|
|
101
|
+
declare function useApiMutation<TResponse = unknown, TParams = unknown, TBody = unknown, TError = ApiError>(endpoint: EndpointCallable<TResponse, TParams, TBody>, options?: ApiMutationOptions<TResponse, TError, EndpointCallableOptions<TParams, TBody>>): _tanstack_react_query.UseMutationResult<TResponse, TError, EndpointCallableOptions<TParams, TBody>, unknown>;
|
|
82
102
|
|
|
83
103
|
/**
|
|
84
104
|
* createHooks — generate typed hooks from an api group.
|
package/dist/react.js
CHANGED
|
@@ -28,8 +28,10 @@ module.exports = __toCommonJS(src_exports);
|
|
|
28
28
|
|
|
29
29
|
// packages/react/src/hooks/useQuery.ts
|
|
30
30
|
var import_react_query = require("@tanstack/react-query");
|
|
31
|
-
function useApiQuery(endpoint,
|
|
32
|
-
const
|
|
31
|
+
function useApiQuery(endpoint, ...args) {
|
|
32
|
+
const options = args[0];
|
|
33
|
+
const queryOptions = args[1];
|
|
34
|
+
const queryKey = endpoint.$queryKey(options);
|
|
33
35
|
return (0, import_react_query.useQuery)({
|
|
34
36
|
queryKey,
|
|
35
37
|
queryFn: () => endpoint(options),
|
package/dist/react.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// packages/react/src/hooks/useQuery.ts
|
|
2
2
|
import { useQuery } from "@tanstack/react-query";
|
|
3
|
-
function useApiQuery(endpoint,
|
|
4
|
-
const
|
|
3
|
+
function useApiQuery(endpoint, ...args) {
|
|
4
|
+
const options = args[0];
|
|
5
|
+
const queryOptions = args[1];
|
|
6
|
+
const queryKey = endpoint.$queryKey(options);
|
|
5
7
|
return useQuery({
|
|
6
8
|
queryKey,
|
|
7
9
|
queryFn: () => endpoint(options),
|
package/dist/sdk.d.mts
CHANGED
|
@@ -7,6 +7,14 @@ interface ServiceConfig {
|
|
|
7
7
|
timeout?: number;
|
|
8
8
|
retry?: RetryConfig;
|
|
9
9
|
cache?: boolean;
|
|
10
|
+
validateResponse?: boolean;
|
|
11
|
+
onValidationError?: (error: unknown, context: {
|
|
12
|
+
endpoint: string;
|
|
13
|
+
method: string;
|
|
14
|
+
path: string;
|
|
15
|
+
request: unknown;
|
|
16
|
+
response: unknown;
|
|
17
|
+
}) => void;
|
|
10
18
|
}
|
|
11
19
|
interface RetryConfig {
|
|
12
20
|
attempts: number;
|
|
@@ -16,6 +24,7 @@ interface RetryConfig {
|
|
|
16
24
|
|
|
17
25
|
declare class HttpClient {
|
|
18
26
|
private client;
|
|
27
|
+
readonly config: ServiceConfig;
|
|
19
28
|
constructor(config: ServiceConfig);
|
|
20
29
|
private setupInterceptors;
|
|
21
30
|
setToken(token: string): void;
|
|
@@ -56,11 +65,15 @@ interface RouteSchemaMap {
|
|
|
56
65
|
}
|
|
57
66
|
type RouteSchemaValue = RouteTransform | RouteParserSchema;
|
|
58
67
|
type RouteSchema = RouteSchemaValue | RouteSchemaMap;
|
|
59
|
-
interface
|
|
68
|
+
interface ResponseSchema<T> {
|
|
69
|
+
parse(input: unknown): T;
|
|
70
|
+
}
|
|
71
|
+
interface RouteDefinition<TResponse = unknown, TParams = unknown, TBody = unknown> {
|
|
60
72
|
method: HttpMethod;
|
|
61
73
|
path: string;
|
|
62
74
|
auth?: boolean;
|
|
63
75
|
schema?: RouteSchema;
|
|
76
|
+
responseSchema?: ResponseSchema<TResponse>;
|
|
64
77
|
mapper?: RouteMapper;
|
|
65
78
|
headers?: Record<string, string>;
|
|
66
79
|
cache?: unknown;
|
|
@@ -68,10 +81,13 @@ interface RouteDefinition {
|
|
|
68
81
|
body?: Record<string, any>;
|
|
69
82
|
params?: Record<string, any>;
|
|
70
83
|
query?: Record<string, any>;
|
|
84
|
+
_typeResponse?: TResponse;
|
|
85
|
+
_typeParams?: TParams;
|
|
86
|
+
_typeBody?: TBody;
|
|
71
87
|
}
|
|
72
88
|
interface ApiDefinition {
|
|
73
89
|
[group: string]: {
|
|
74
|
-
[action: string]: RouteDefinition
|
|
90
|
+
[action: string]: RouteDefinition<any, any, any>;
|
|
75
91
|
};
|
|
76
92
|
}
|
|
77
93
|
|
|
@@ -99,21 +115,37 @@ declare class TokenManager {
|
|
|
99
115
|
exists(): boolean;
|
|
100
116
|
}
|
|
101
117
|
|
|
102
|
-
type CallOptions = {
|
|
103
|
-
params?:
|
|
118
|
+
type CallOptions<TParams = unknown, TBody = unknown> = {
|
|
119
|
+
params?: TParams;
|
|
104
120
|
query?: Record<string, any>;
|
|
105
|
-
body?:
|
|
121
|
+
body?: TBody;
|
|
106
122
|
headers?: Record<string, string>;
|
|
107
123
|
};
|
|
108
|
-
|
|
109
|
-
|
|
124
|
+
type EndpointCallableOptions<TParams, TBody> = (unknown extends TParams ? {} : {
|
|
125
|
+
params: TParams;
|
|
126
|
+
}) & (unknown extends TBody ? {} : {
|
|
127
|
+
body: TBody;
|
|
128
|
+
}) & {
|
|
129
|
+
query?: Record<string, any>;
|
|
130
|
+
headers?: Record<string, string>;
|
|
131
|
+
};
|
|
132
|
+
type OptionalIfEmpty<T> = keyof Omit<T, 'query' | 'headers'> extends never ? [options?: T] : [options: T];
|
|
133
|
+
interface ApiError {
|
|
134
|
+
message: string;
|
|
135
|
+
status?: number;
|
|
136
|
+
errors?: Record<string, string[]>;
|
|
137
|
+
}
|
|
138
|
+
interface EndpointCallable<TResponse = unknown, TParams = unknown, TBody = unknown> {
|
|
139
|
+
(...args: OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>): Promise<TResponse>;
|
|
110
140
|
/** Original RouteDefinition — used by useApiQuery / useApiMutation */
|
|
111
|
-
$def: RouteDefinition
|
|
141
|
+
$def: RouteDefinition<TResponse, TParams, TBody>;
|
|
112
142
|
/** Stable TanStack query key: [group, action] */
|
|
113
143
|
$key: string[];
|
|
144
|
+
/** Consistent query key builder that incorporates params/query if provided */
|
|
145
|
+
$queryKey: (...args: OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>) => unknown[];
|
|
114
146
|
}
|
|
115
|
-
type ApiGroupProxy<G extends Record<string, RouteDefinition
|
|
116
|
-
[K in keyof G]: EndpointCallable
|
|
147
|
+
type ApiGroupProxy<G extends Record<string, RouteDefinition<any, any, any>>> = {
|
|
148
|
+
[K in keyof G]: EndpointCallable<G[K] extends RouteDefinition<infer R, any, any> ? R : unknown, G[K] extends RouteDefinition<any, infer P, any> ? P : unknown, G[K] extends RouteDefinition<any, any, infer B> ? B : unknown>;
|
|
117
149
|
};
|
|
118
150
|
type ApiProxy<T extends ApiDefinition> = {
|
|
119
151
|
[G in keyof T]: ApiGroupProxy<T[G]>;
|
|
@@ -139,7 +171,7 @@ type EndpointDefinition$1 = RouteDefinition;
|
|
|
139
171
|
* const { data } = useApiQuery(api.cart.list)
|
|
140
172
|
* const mutation = useApiMutation(api.cart.create)
|
|
141
173
|
*/
|
|
142
|
-
declare function endpoint(def: RouteDefinition): RouteDefinition
|
|
174
|
+
declare function endpoint<TResponse = unknown, TParams = unknown, TBody = unknown>(def: RouteDefinition<TResponse, TParams, TBody>): RouteDefinition<TResponse, TParams, TBody>;
|
|
143
175
|
|
|
144
176
|
type EndpointDefinition = RouteDefinition;
|
|
145
177
|
interface ResourceConfig<TEndpoints extends Record<string, EndpointDefinition>> {
|
|
@@ -271,4 +303,4 @@ declare function mapKeysDeep<T>(value: T, keyCase: KeyCase): T;
|
|
|
271
303
|
declare function toCamelCase<T>(value: T): T;
|
|
272
304
|
declare function toSnakeCase<T>(value: T): T;
|
|
273
305
|
|
|
274
|
-
export { type ApiDefinition, type ApiResponse, type CallOptions, type CamelCasedPropertiesDeep, type CamelToSnake, type EndpointCallable, type EndpointDefinition$1 as EndpointDefinition, GenericService, type GenericServiceOptions, type HttpMethod, type Id, type KeyCase, type ParseResult, type ParserSchema, type QueryParams, type ResourceConfig, type ResourceDefinition, type RouteDefinition, type RouteMapper, type RouteParserSchema, type RouteSchema, type RouteSchemaMap, type RouteSchemaValue, type RouteTransform, type RouteTransformMap, type SchemaLike, type ServiceConfig, type SnakeCasedPropertiesDeep, type SnakeToCamel, type UnknownRecord, camelToSnakeKey, createClient$1 as createClient, createClient as createHttpClient, createService, defineApi, endpoint, generateHooks, mapKeysDeep, parseWithSchema, resource, snakeToCamelKey, toCamelCase, toSnakeCase };
|
|
306
|
+
export { type ApiDefinition, type ApiError, type ApiResponse, type CallOptions, type CamelCasedPropertiesDeep, type CamelToSnake, type EndpointCallable, type EndpointCallableOptions, type EndpointDefinition$1 as EndpointDefinition, GenericService, type GenericServiceOptions, type HttpMethod, type Id, type KeyCase, type OptionalIfEmpty, type ParseResult, type ParserSchema, type QueryParams, type ResourceConfig, type ResourceDefinition, type RouteDefinition, type RouteMapper, type RouteParserSchema, type RouteSchema, type RouteSchemaMap, type RouteSchemaValue, type RouteTransform, type RouteTransformMap, type SchemaLike, type ServiceConfig, type SnakeCasedPropertiesDeep, type SnakeToCamel, type UnknownRecord, camelToSnakeKey, createClient$1 as createClient, createClient as createHttpClient, createService, defineApi, endpoint, generateHooks, mapKeysDeep, parseWithSchema, resource, snakeToCamelKey, toCamelCase, toSnakeCase };
|
package/dist/sdk.d.ts
CHANGED
|
@@ -7,6 +7,14 @@ interface ServiceConfig {
|
|
|
7
7
|
timeout?: number;
|
|
8
8
|
retry?: RetryConfig;
|
|
9
9
|
cache?: boolean;
|
|
10
|
+
validateResponse?: boolean;
|
|
11
|
+
onValidationError?: (error: unknown, context: {
|
|
12
|
+
endpoint: string;
|
|
13
|
+
method: string;
|
|
14
|
+
path: string;
|
|
15
|
+
request: unknown;
|
|
16
|
+
response: unknown;
|
|
17
|
+
}) => void;
|
|
10
18
|
}
|
|
11
19
|
interface RetryConfig {
|
|
12
20
|
attempts: number;
|
|
@@ -16,6 +24,7 @@ interface RetryConfig {
|
|
|
16
24
|
|
|
17
25
|
declare class HttpClient {
|
|
18
26
|
private client;
|
|
27
|
+
readonly config: ServiceConfig;
|
|
19
28
|
constructor(config: ServiceConfig);
|
|
20
29
|
private setupInterceptors;
|
|
21
30
|
setToken(token: string): void;
|
|
@@ -56,11 +65,15 @@ interface RouteSchemaMap {
|
|
|
56
65
|
}
|
|
57
66
|
type RouteSchemaValue = RouteTransform | RouteParserSchema;
|
|
58
67
|
type RouteSchema = RouteSchemaValue | RouteSchemaMap;
|
|
59
|
-
interface
|
|
68
|
+
interface ResponseSchema<T> {
|
|
69
|
+
parse(input: unknown): T;
|
|
70
|
+
}
|
|
71
|
+
interface RouteDefinition<TResponse = unknown, TParams = unknown, TBody = unknown> {
|
|
60
72
|
method: HttpMethod;
|
|
61
73
|
path: string;
|
|
62
74
|
auth?: boolean;
|
|
63
75
|
schema?: RouteSchema;
|
|
76
|
+
responseSchema?: ResponseSchema<TResponse>;
|
|
64
77
|
mapper?: RouteMapper;
|
|
65
78
|
headers?: Record<string, string>;
|
|
66
79
|
cache?: unknown;
|
|
@@ -68,10 +81,13 @@ interface RouteDefinition {
|
|
|
68
81
|
body?: Record<string, any>;
|
|
69
82
|
params?: Record<string, any>;
|
|
70
83
|
query?: Record<string, any>;
|
|
84
|
+
_typeResponse?: TResponse;
|
|
85
|
+
_typeParams?: TParams;
|
|
86
|
+
_typeBody?: TBody;
|
|
71
87
|
}
|
|
72
88
|
interface ApiDefinition {
|
|
73
89
|
[group: string]: {
|
|
74
|
-
[action: string]: RouteDefinition
|
|
90
|
+
[action: string]: RouteDefinition<any, any, any>;
|
|
75
91
|
};
|
|
76
92
|
}
|
|
77
93
|
|
|
@@ -99,21 +115,37 @@ declare class TokenManager {
|
|
|
99
115
|
exists(): boolean;
|
|
100
116
|
}
|
|
101
117
|
|
|
102
|
-
type CallOptions = {
|
|
103
|
-
params?:
|
|
118
|
+
type CallOptions<TParams = unknown, TBody = unknown> = {
|
|
119
|
+
params?: TParams;
|
|
104
120
|
query?: Record<string, any>;
|
|
105
|
-
body?:
|
|
121
|
+
body?: TBody;
|
|
106
122
|
headers?: Record<string, string>;
|
|
107
123
|
};
|
|
108
|
-
|
|
109
|
-
|
|
124
|
+
type EndpointCallableOptions<TParams, TBody> = (unknown extends TParams ? {} : {
|
|
125
|
+
params: TParams;
|
|
126
|
+
}) & (unknown extends TBody ? {} : {
|
|
127
|
+
body: TBody;
|
|
128
|
+
}) & {
|
|
129
|
+
query?: Record<string, any>;
|
|
130
|
+
headers?: Record<string, string>;
|
|
131
|
+
};
|
|
132
|
+
type OptionalIfEmpty<T> = keyof Omit<T, 'query' | 'headers'> extends never ? [options?: T] : [options: T];
|
|
133
|
+
interface ApiError {
|
|
134
|
+
message: string;
|
|
135
|
+
status?: number;
|
|
136
|
+
errors?: Record<string, string[]>;
|
|
137
|
+
}
|
|
138
|
+
interface EndpointCallable<TResponse = unknown, TParams = unknown, TBody = unknown> {
|
|
139
|
+
(...args: OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>): Promise<TResponse>;
|
|
110
140
|
/** Original RouteDefinition — used by useApiQuery / useApiMutation */
|
|
111
|
-
$def: RouteDefinition
|
|
141
|
+
$def: RouteDefinition<TResponse, TParams, TBody>;
|
|
112
142
|
/** Stable TanStack query key: [group, action] */
|
|
113
143
|
$key: string[];
|
|
144
|
+
/** Consistent query key builder that incorporates params/query if provided */
|
|
145
|
+
$queryKey: (...args: OptionalIfEmpty<EndpointCallableOptions<TParams, TBody>>) => unknown[];
|
|
114
146
|
}
|
|
115
|
-
type ApiGroupProxy<G extends Record<string, RouteDefinition
|
|
116
|
-
[K in keyof G]: EndpointCallable
|
|
147
|
+
type ApiGroupProxy<G extends Record<string, RouteDefinition<any, any, any>>> = {
|
|
148
|
+
[K in keyof G]: EndpointCallable<G[K] extends RouteDefinition<infer R, any, any> ? R : unknown, G[K] extends RouteDefinition<any, infer P, any> ? P : unknown, G[K] extends RouteDefinition<any, any, infer B> ? B : unknown>;
|
|
117
149
|
};
|
|
118
150
|
type ApiProxy<T extends ApiDefinition> = {
|
|
119
151
|
[G in keyof T]: ApiGroupProxy<T[G]>;
|
|
@@ -139,7 +171,7 @@ type EndpointDefinition$1 = RouteDefinition;
|
|
|
139
171
|
* const { data } = useApiQuery(api.cart.list)
|
|
140
172
|
* const mutation = useApiMutation(api.cart.create)
|
|
141
173
|
*/
|
|
142
|
-
declare function endpoint(def: RouteDefinition): RouteDefinition
|
|
174
|
+
declare function endpoint<TResponse = unknown, TParams = unknown, TBody = unknown>(def: RouteDefinition<TResponse, TParams, TBody>): RouteDefinition<TResponse, TParams, TBody>;
|
|
143
175
|
|
|
144
176
|
type EndpointDefinition = RouteDefinition;
|
|
145
177
|
interface ResourceConfig<TEndpoints extends Record<string, EndpointDefinition>> {
|
|
@@ -271,4 +303,4 @@ declare function mapKeysDeep<T>(value: T, keyCase: KeyCase): T;
|
|
|
271
303
|
declare function toCamelCase<T>(value: T): T;
|
|
272
304
|
declare function toSnakeCase<T>(value: T): T;
|
|
273
305
|
|
|
274
|
-
export { type ApiDefinition, type ApiResponse, type CallOptions, type CamelCasedPropertiesDeep, type CamelToSnake, type EndpointCallable, type EndpointDefinition$1 as EndpointDefinition, GenericService, type GenericServiceOptions, type HttpMethod, type Id, type KeyCase, type ParseResult, type ParserSchema, type QueryParams, type ResourceConfig, type ResourceDefinition, type RouteDefinition, type RouteMapper, type RouteParserSchema, type RouteSchema, type RouteSchemaMap, type RouteSchemaValue, type RouteTransform, type RouteTransformMap, type SchemaLike, type ServiceConfig, type SnakeCasedPropertiesDeep, type SnakeToCamel, type UnknownRecord, camelToSnakeKey, createClient$1 as createClient, createClient as createHttpClient, createService, defineApi, endpoint, generateHooks, mapKeysDeep, parseWithSchema, resource, snakeToCamelKey, toCamelCase, toSnakeCase };
|
|
306
|
+
export { type ApiDefinition, type ApiError, type ApiResponse, type CallOptions, type CamelCasedPropertiesDeep, type CamelToSnake, type EndpointCallable, type EndpointCallableOptions, type EndpointDefinition$1 as EndpointDefinition, GenericService, type GenericServiceOptions, type HttpMethod, type Id, type KeyCase, type OptionalIfEmpty, type ParseResult, type ParserSchema, type QueryParams, type ResourceConfig, type ResourceDefinition, type RouteDefinition, type RouteMapper, type RouteParserSchema, type RouteSchema, type RouteSchemaMap, type RouteSchemaValue, type RouteTransform, type RouteTransformMap, type SchemaLike, type ServiceConfig, type SnakeCasedPropertiesDeep, type SnakeToCamel, type UnknownRecord, camelToSnakeKey, createClient$1 as createClient, createClient as createHttpClient, createService, defineApi, endpoint, generateHooks, mapKeysDeep, parseWithSchema, resource, snakeToCamelKey, toCamelCase, toSnakeCase };
|
package/dist/sdk.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,
|
|
@@ -344,14 +345,35 @@ function defineApi(definition, config) {
|
|
|
344
345
|
} else {
|
|
345
346
|
response = await client[method](resolvedPath, body, requestConfig);
|
|
346
347
|
}
|
|
348
|
+
if (client.config.validateResponse && route.responseSchema) {
|
|
349
|
+
try {
|
|
350
|
+
response = route.responseSchema.parse(response);
|
|
351
|
+
} catch (error) {
|
|
352
|
+
if (client.config.onValidationError) {
|
|
353
|
+
client.config.onValidationError(error, {
|
|
354
|
+
endpoint: action,
|
|
355
|
+
method: route.method,
|
|
356
|
+
path: resolvedPath,
|
|
357
|
+
request: { params, query, body, headers: requestConfig.headers },
|
|
358
|
+
response
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
throw error;
|
|
362
|
+
}
|
|
363
|
+
} else if (client.config.validateResponse) {
|
|
364
|
+
response = parseRouteSchema(route, "response", response);
|
|
365
|
+
}
|
|
347
366
|
return applyMapper(
|
|
348
367
|
route,
|
|
349
368
|
"response",
|
|
350
|
-
|
|
369
|
+
response
|
|
351
370
|
);
|
|
352
371
|
};
|
|
353
372
|
callable.$def = route;
|
|
354
373
|
callable.$key = [group, action];
|
|
374
|
+
callable.$queryKey = (options) => {
|
|
375
|
+
return options ? [group, action, options] : [group, action];
|
|
376
|
+
};
|
|
355
377
|
groupProxy[action] = callable;
|
|
356
378
|
}
|
|
357
379
|
;
|