@geekmidas/client 9.0.1 → 10.0.0-alpha.0
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/auth-fetcher-CBYuL6rx.d.cts +158 -0
- package/dist/auth-fetcher-CBYuL6rx.d.cts.map +1 -0
- package/dist/auth-fetcher-DOj0iz21.mjs +77 -0
- package/dist/auth-fetcher-DOj0iz21.mjs.map +1 -0
- package/dist/auth-fetcher-DxS8zOLc.d.mts +158 -0
- package/dist/auth-fetcher-DxS8zOLc.d.mts.map +1 -0
- package/dist/auth-fetcher-HILABmws.cjs +82 -0
- package/dist/auth-fetcher-HILABmws.cjs.map +1 -0
- package/dist/auth-fetcher.cjs +3 -76
- package/dist/auth-fetcher.d.cts +3 -158
- package/dist/auth-fetcher.d.mts +3 -158
- package/dist/auth-fetcher.mjs +3 -76
- package/dist/endpoint-hooks.d.mts +1 -1
- package/dist/fetcher-C1xtCKpT.d.mts +25 -0
- package/dist/fetcher-C1xtCKpT.d.mts.map +1 -0
- package/dist/fetcher-cDrfwN-Y.d.cts +25 -0
- package/dist/fetcher-cDrfwN-Y.d.cts.map +1 -0
- package/dist/fetcher.d.cts +3 -25
- package/dist/fetcher.d.mts +3 -25
- package/dist/index.cjs +8 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +6 -0
- package/dist/infer-6KKCgmg1.cjs +0 -0
- package/{src/infer.ts → dist/infer-DfRq5kIb.d.cts} +54 -83
- package/dist/infer-DfRq5kIb.d.cts.map +1 -0
- package/dist/infer-bTirNeNW.d.mts +133 -0
- package/dist/infer-bTirNeNW.d.mts.map +1 -0
- package/dist/infer-uCUq1whM.mjs +0 -0
- package/dist/infer.cjs +1 -0
- package/dist/infer.d.cts +2 -133
- package/dist/infer.d.mts +2 -133
- package/dist/infer.mjs +1 -0
- package/dist/openapi-hooks.cjs.map +1 -1
- package/dist/openapi-hooks.d.cts +3 -3
- package/dist/openapi-hooks.d.cts.map +1 -1
- package/dist/openapi-hooks.d.mts +1 -1
- package/dist/openapi-hooks.d.mts.map +1 -1
- package/dist/openapi-hooks.mjs.map +1 -1
- package/dist/react-query.d.cts +7 -7
- package/dist/react-query.d.mts +1 -1
- package/dist/types-BH8WgGrm.mjs +0 -0
- package/dist/{types-D8Jrl4o3.d.mts → types-BMGM6sZc.d.mts} +1 -1
- package/dist/{types-D8Jrl4o3.d.mts.map → types-BMGM6sZc.d.mts.map} +1 -1
- package/dist/types-a8gm_IaQ.cjs +0 -0
- package/dist/types.cjs +1 -0
- package/dist/types.d.mts +1 -1
- package/dist/types.mjs +1 -0
- package/package.json +8 -5
- package/CHANGELOG.md +0 -124
- package/dist/auth-fetcher.cjs.map +0 -1
- package/dist/auth-fetcher.d.cts.map +0 -1
- package/dist/auth-fetcher.d.mts.map +0 -1
- package/dist/auth-fetcher.mjs.map +0 -1
- package/dist/fetcher.d.cts.map +0 -1
- package/dist/fetcher.d.mts.map +0 -1
- package/dist/infer.d.cts.map +0 -1
- package/dist/infer.d.mts.map +0 -1
- package/src/__tests__/auth-fetcher.spec.ts +0 -505
- package/src/__tests__/endpoint-hooks.spec.tsx +0 -374
- package/src/__tests__/fetcher.spec.ts +0 -580
- package/src/__tests__/infer.integration.spec.ts +0 -188
- package/src/__tests__/infer.spec.ts +0 -189
- package/src/__tests__/method-restrictions.spec.tsx +0 -227
- package/src/__tests__/mutation-inference.spec.tsx +0 -343
- package/src/__tests__/openapi-hooks.spec.tsx +0 -557
- package/src/__tests__/react-query-infinite.spec.tsx +0 -1003
- package/src/__tests__/react-query-invalidation.spec.tsx +0 -239
- package/src/__tests__/react-query.spec.tsx +0 -582
- package/src/__tests__/setup.ts +0 -281
- package/src/__tests__/types.spec.ts +0 -134
- package/src/__tests__/url-parsing.spec.ts +0 -196
- package/src/auth-fetcher.ts +0 -288
- package/src/endpoint-hooks.ts +0 -346
- package/src/fetcher.ts +0 -171
- package/src/openapi-hooks.ts +0 -193
- package/src/openapi-types.d.ts +0 -440
- package/src/openapi.json +0 -595
- package/src/react-query.ts +0 -341
- package/src/types.ts +0 -226
- package/tsconfig.json +0 -12
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { e } from '@geekmidas/constructs/endpoints';
|
|
2
|
-
import { describe, expectTypeOf, it } from 'vitest';
|
|
3
|
-
import { z } from 'zod';
|
|
4
|
-
import type { InferOpenApi } from '../infer';
|
|
5
|
-
|
|
6
|
-
describe('InferOpenApi - TypedFetcher Integration', () => {
|
|
7
|
-
it('should generate paths structure compatible with TypedFetcher', () => {
|
|
8
|
-
// Define some endpoints
|
|
9
|
-
const getUserEndpoint = e
|
|
10
|
-
.get('/users/{id}')
|
|
11
|
-
.params(z.object({ id: z.string() }))
|
|
12
|
-
.output(z.object({ id: z.string(), name: z.string(), email: z.string() }))
|
|
13
|
-
.handle(async ({ params }) => ({
|
|
14
|
-
id: params.id,
|
|
15
|
-
name: 'John Doe',
|
|
16
|
-
email: 'john@example.com',
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
|
-
const createUserEndpoint = e
|
|
20
|
-
.post('/users')
|
|
21
|
-
.body(z.object({ name: z.string(), email: z.string() }))
|
|
22
|
-
.output(z.object({ id: z.string(), name: z.string(), email: z.string() }))
|
|
23
|
-
.handle(async ({ body }) => ({
|
|
24
|
-
id: '123',
|
|
25
|
-
name: body.name,
|
|
26
|
-
email: body.email,
|
|
27
|
-
}));
|
|
28
|
-
|
|
29
|
-
const listUsersEndpoint = e
|
|
30
|
-
.get('/users')
|
|
31
|
-
.query(z.object({ page: z.coerce.number().optional() }))
|
|
32
|
-
.output(
|
|
33
|
-
z.object({
|
|
34
|
-
users: z.array(
|
|
35
|
-
z.object({ id: z.string(), name: z.string(), email: z.string() }),
|
|
36
|
-
),
|
|
37
|
-
}),
|
|
38
|
-
)
|
|
39
|
-
.handle(async ({ query }) => ({
|
|
40
|
-
users: [],
|
|
41
|
-
}));
|
|
42
|
-
|
|
43
|
-
// Infer paths from endpoints
|
|
44
|
-
const endpoints = [
|
|
45
|
-
getUserEndpoint,
|
|
46
|
-
createUserEndpoint,
|
|
47
|
-
listUsersEndpoint,
|
|
48
|
-
] as const;
|
|
49
|
-
type Paths = InferOpenApi<typeof endpoints>['paths'];
|
|
50
|
-
|
|
51
|
-
// Verify the structure matches TypedFetcher expectations
|
|
52
|
-
expectTypeOf<Paths>().toMatchTypeOf<{
|
|
53
|
-
'/users/{id}': {
|
|
54
|
-
get: {
|
|
55
|
-
parameters: {
|
|
56
|
-
path: { id: string };
|
|
57
|
-
};
|
|
58
|
-
responses: {
|
|
59
|
-
200: {
|
|
60
|
-
content: {
|
|
61
|
-
'application/json': {
|
|
62
|
-
id: string;
|
|
63
|
-
name: string;
|
|
64
|
-
email: string;
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
};
|
|
68
|
-
};
|
|
69
|
-
};
|
|
70
|
-
};
|
|
71
|
-
'/users': {
|
|
72
|
-
get: {
|
|
73
|
-
parameters: {
|
|
74
|
-
query: { page?: number };
|
|
75
|
-
};
|
|
76
|
-
responses: {
|
|
77
|
-
200: {
|
|
78
|
-
content: {
|
|
79
|
-
'application/json': {
|
|
80
|
-
users: Array<{ id: string; name: string; email: string }>;
|
|
81
|
-
};
|
|
82
|
-
};
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
|
-
};
|
|
86
|
-
post: {
|
|
87
|
-
requestBody: {
|
|
88
|
-
content: {
|
|
89
|
-
'application/json': {
|
|
90
|
-
name: string;
|
|
91
|
-
email: string;
|
|
92
|
-
};
|
|
93
|
-
};
|
|
94
|
-
};
|
|
95
|
-
responses: {
|
|
96
|
-
200: {
|
|
97
|
-
content: {
|
|
98
|
-
'application/json': {
|
|
99
|
-
id: string;
|
|
100
|
-
name: string;
|
|
101
|
-
email: string;
|
|
102
|
-
};
|
|
103
|
-
};
|
|
104
|
-
};
|
|
105
|
-
};
|
|
106
|
-
};
|
|
107
|
-
};
|
|
108
|
-
}>();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('should handle endpoints with multiple parameter types', () => {
|
|
112
|
-
const updateUserEndpoint = e
|
|
113
|
-
.put('/users/{id}')
|
|
114
|
-
.params(z.object({ id: z.string() }))
|
|
115
|
-
.query(z.object({ notify: z.coerce.boolean().optional() }))
|
|
116
|
-
.body(z.object({ name: z.string() }))
|
|
117
|
-
.output(z.object({ id: z.string(), name: z.string() }))
|
|
118
|
-
.handle(async ({ params, query, body }) => ({
|
|
119
|
-
id: params.id,
|
|
120
|
-
name: body.name,
|
|
121
|
-
}));
|
|
122
|
-
|
|
123
|
-
type Paths = InferOpenApi<[typeof updateUserEndpoint]>['paths'];
|
|
124
|
-
|
|
125
|
-
// Verify all parameter types are present
|
|
126
|
-
expectTypeOf<Paths>().toMatchTypeOf<{
|
|
127
|
-
'/users/{id}': {
|
|
128
|
-
parameters: {
|
|
129
|
-
path: { id: string };
|
|
130
|
-
query: { notify?: boolean };
|
|
131
|
-
};
|
|
132
|
-
put: {
|
|
133
|
-
parameters: {
|
|
134
|
-
path: { id: string };
|
|
135
|
-
query: { notify?: boolean };
|
|
136
|
-
};
|
|
137
|
-
requestBody: {
|
|
138
|
-
content: {
|
|
139
|
-
'application/json': {
|
|
140
|
-
name: string;
|
|
141
|
-
};
|
|
142
|
-
};
|
|
143
|
-
};
|
|
144
|
-
responses: {
|
|
145
|
-
200: {
|
|
146
|
-
content: {
|
|
147
|
-
'application/json': {
|
|
148
|
-
id: string;
|
|
149
|
-
name: string;
|
|
150
|
-
};
|
|
151
|
-
};
|
|
152
|
-
};
|
|
153
|
-
};
|
|
154
|
-
};
|
|
155
|
-
};
|
|
156
|
-
}>();
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it('should handle endpoints without output schema', () => {
|
|
160
|
-
const deleteUserEndpoint = e
|
|
161
|
-
.delete('/users/{id}')
|
|
162
|
-
.params(z.object({ id: z.string() }))
|
|
163
|
-
.handle(async ({ params }) => {
|
|
164
|
-
// No return value
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
type Paths = InferOpenApi<[typeof deleteUserEndpoint]>['paths'];
|
|
168
|
-
|
|
169
|
-
// Verify response content is never when no output schema
|
|
170
|
-
expectTypeOf<Paths>().toMatchTypeOf<{
|
|
171
|
-
'/users/{id}': {
|
|
172
|
-
parameters: {
|
|
173
|
-
path: { id: string };
|
|
174
|
-
};
|
|
175
|
-
delete: {
|
|
176
|
-
parameters: {
|
|
177
|
-
path: { id: string };
|
|
178
|
-
};
|
|
179
|
-
responses: {
|
|
180
|
-
200: {
|
|
181
|
-
content: never;
|
|
182
|
-
};
|
|
183
|
-
};
|
|
184
|
-
};
|
|
185
|
-
};
|
|
186
|
-
}>();
|
|
187
|
-
});
|
|
188
|
-
});
|
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import { e } from '@geekmidas/constructs/endpoints';
|
|
2
|
-
import { describe, expectTypeOf, it } from 'vitest';
|
|
3
|
-
import { z } from 'zod';
|
|
4
|
-
import type { InferOpenApi, InferOpenApiFromEndpoint } from '../infer';
|
|
5
|
-
|
|
6
|
-
describe('InferOpenApi', () => {
|
|
7
|
-
describe('single endpoint', () => {
|
|
8
|
-
it('should infer OpenAPI structure for GET endpoint', () => {
|
|
9
|
-
const endpoint = e
|
|
10
|
-
.get('/users/{id}')
|
|
11
|
-
.params(z.object({ id: z.string() }))
|
|
12
|
-
.output(z.object({ id: z.string(), name: z.string() }))
|
|
13
|
-
.handle(async ({ params }) => ({
|
|
14
|
-
id: params.id,
|
|
15
|
-
name: 'John',
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
type API = InferOpenApiFromEndpoint<typeof endpoint>;
|
|
19
|
-
|
|
20
|
-
expectTypeOf<API>().toMatchTypeOf<{
|
|
21
|
-
paths: {
|
|
22
|
-
'/users/{id}': {
|
|
23
|
-
get: {
|
|
24
|
-
responses: {
|
|
25
|
-
'200': {
|
|
26
|
-
description: string;
|
|
27
|
-
};
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
}>();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('should infer OpenAPI structure for POST endpoint with body', () => {
|
|
36
|
-
const endpoint = e
|
|
37
|
-
.post('/users')
|
|
38
|
-
.body(z.object({ name: z.string(), email: z.string() }))
|
|
39
|
-
.output(z.object({ id: z.string(), name: z.string() }))
|
|
40
|
-
.handle(async ({ body }) => ({
|
|
41
|
-
id: '123',
|
|
42
|
-
name: body.name,
|
|
43
|
-
}));
|
|
44
|
-
|
|
45
|
-
type API = InferOpenApiFromEndpoint<typeof endpoint>;
|
|
46
|
-
|
|
47
|
-
expectTypeOf<API>().toMatchTypeOf<{
|
|
48
|
-
paths: {
|
|
49
|
-
'/users': {
|
|
50
|
-
post: {
|
|
51
|
-
responses: {
|
|
52
|
-
'200': {
|
|
53
|
-
description: string;
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
};
|
|
59
|
-
}>();
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe('multiple endpoints', () => {
|
|
64
|
-
it('should merge OpenAPI specs from multiple endpoints', () => {
|
|
65
|
-
const getUserEndpoint = e
|
|
66
|
-
.get('/users/{id}')
|
|
67
|
-
.params(z.object({ id: z.string() }))
|
|
68
|
-
.output(z.object({ id: z.string(), name: z.string() }))
|
|
69
|
-
.handle(async ({ params }) => ({
|
|
70
|
-
id: params.id,
|
|
71
|
-
name: 'John',
|
|
72
|
-
}));
|
|
73
|
-
|
|
74
|
-
const createUserEndpoint = e
|
|
75
|
-
.post('/users')
|
|
76
|
-
.body(z.object({ name: z.string() }))
|
|
77
|
-
.output(z.object({ id: z.string(), name: z.string() }))
|
|
78
|
-
.handle(async ({ body }) => ({
|
|
79
|
-
id: '123',
|
|
80
|
-
name: body.name,
|
|
81
|
-
}));
|
|
82
|
-
|
|
83
|
-
const endpoints = [getUserEndpoint, createUserEndpoint] as const;
|
|
84
|
-
|
|
85
|
-
type API = InferOpenApi<typeof endpoints>;
|
|
86
|
-
|
|
87
|
-
// Should have both paths
|
|
88
|
-
expectTypeOf<API>().toMatchTypeOf<{
|
|
89
|
-
paths: {
|
|
90
|
-
'/users/{id}': {
|
|
91
|
-
get: unknown;
|
|
92
|
-
};
|
|
93
|
-
'/users': {
|
|
94
|
-
post: unknown;
|
|
95
|
-
};
|
|
96
|
-
};
|
|
97
|
-
}>();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('should handle endpoints with different HTTP methods on same path', () => {
|
|
101
|
-
const getUserEndpoint = e
|
|
102
|
-
.get('/users')
|
|
103
|
-
.output(z.object({ users: z.array(z.object({ id: z.string() })) }))
|
|
104
|
-
.handle(async () => ({
|
|
105
|
-
users: [],
|
|
106
|
-
}));
|
|
107
|
-
|
|
108
|
-
const createUserEndpoint = e
|
|
109
|
-
.post('/users')
|
|
110
|
-
.body(z.object({ name: z.string() }))
|
|
111
|
-
.output(z.object({ id: z.string() }))
|
|
112
|
-
.handle(async ({ body }) => ({
|
|
113
|
-
id: '123',
|
|
114
|
-
}));
|
|
115
|
-
|
|
116
|
-
const endpoints = [getUserEndpoint, createUserEndpoint] as const;
|
|
117
|
-
|
|
118
|
-
type API = InferOpenApi<typeof endpoints>;
|
|
119
|
-
|
|
120
|
-
// Should have both methods on same path
|
|
121
|
-
expectTypeOf<API>().toMatchTypeOf<{
|
|
122
|
-
paths: {
|
|
123
|
-
'/users': {
|
|
124
|
-
get: unknown;
|
|
125
|
-
post: unknown;
|
|
126
|
-
};
|
|
127
|
-
};
|
|
128
|
-
}>();
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
describe('complex schemas', () => {
|
|
133
|
-
it('should handle endpoints with query parameters', () => {
|
|
134
|
-
const endpoint = e
|
|
135
|
-
.get('/users')
|
|
136
|
-
.query(
|
|
137
|
-
z.object({
|
|
138
|
-
page: z.coerce.number().optional(),
|
|
139
|
-
limit: z.coerce.number().optional(),
|
|
140
|
-
}),
|
|
141
|
-
)
|
|
142
|
-
.output(z.object({ users: z.array(z.object({ id: z.string() })) }))
|
|
143
|
-
.handle(async ({ query }) => ({
|
|
144
|
-
users: [],
|
|
145
|
-
}));
|
|
146
|
-
|
|
147
|
-
type API = InferOpenApiFromEndpoint<typeof endpoint>;
|
|
148
|
-
|
|
149
|
-
expectTypeOf<API>().toMatchTypeOf<{
|
|
150
|
-
paths: {
|
|
151
|
-
'/users': {
|
|
152
|
-
get: {
|
|
153
|
-
responses: {
|
|
154
|
-
'200': unknown;
|
|
155
|
-
};
|
|
156
|
-
};
|
|
157
|
-
};
|
|
158
|
-
};
|
|
159
|
-
}>();
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('should handle endpoints with body, params, and query', () => {
|
|
163
|
-
const endpoint = e
|
|
164
|
-
.put('/users/{id}')
|
|
165
|
-
.params(z.object({ id: z.string() }))
|
|
166
|
-
.query(z.object({ notify: z.coerce.boolean().optional() }))
|
|
167
|
-
.body(z.object({ name: z.string() }))
|
|
168
|
-
.output(z.object({ id: z.string(), name: z.string() }))
|
|
169
|
-
.handle(async ({ params, body }) => ({
|
|
170
|
-
id: params.id,
|
|
171
|
-
name: body.name,
|
|
172
|
-
}));
|
|
173
|
-
|
|
174
|
-
type API = InferOpenApiFromEndpoint<typeof endpoint>;
|
|
175
|
-
|
|
176
|
-
expectTypeOf<API>().toMatchTypeOf<{
|
|
177
|
-
paths: {
|
|
178
|
-
'/users/{id}': {
|
|
179
|
-
put: {
|
|
180
|
-
responses: {
|
|
181
|
-
'200': unknown;
|
|
182
|
-
};
|
|
183
|
-
};
|
|
184
|
-
};
|
|
185
|
-
};
|
|
186
|
-
}>();
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
});
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @vitest-environment jsdom
|
|
3
|
-
*/
|
|
4
|
-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
5
|
-
import { renderHook } from '@testing-library/react';
|
|
6
|
-
// biome-ignore lint/style/useImportType: <explanation>
|
|
7
|
-
import React from 'react';
|
|
8
|
-
import { describe, expect, it } from 'vitest';
|
|
9
|
-
import type { paths } from '../openapi-types';
|
|
10
|
-
import { createTypedQueryClient } from '../react-query';
|
|
11
|
-
import './setup';
|
|
12
|
-
|
|
13
|
-
describe('Method Restrictions', () => {
|
|
14
|
-
const queryClient = new QueryClient({
|
|
15
|
-
defaultOptions: {
|
|
16
|
-
queries: {
|
|
17
|
-
retry: false,
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
23
|
-
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
describe('useQuery', () => {
|
|
27
|
-
it('should accept GET endpoints', () => {
|
|
28
|
-
const typedClient = createTypedQueryClient<paths>({
|
|
29
|
-
baseURL: 'https://api.example.com',
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
// This should compile - GET endpoints are allowed
|
|
33
|
-
const { result } = renderHook(() => typedClient.useQuery('GET /users'), {
|
|
34
|
-
wrapper,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
expect(result.current).toBeDefined();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('should accept GET endpoints with parameters', () => {
|
|
41
|
-
const typedClient = createTypedQueryClient<paths>({
|
|
42
|
-
baseURL: 'https://api.example.com',
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// This should compile - GET endpoints with params are allowed
|
|
46
|
-
const { result } = renderHook(
|
|
47
|
-
() =>
|
|
48
|
-
typedClient.useQuery('GET /users/{id}', {
|
|
49
|
-
params: { id: '123' },
|
|
50
|
-
}),
|
|
51
|
-
{ wrapper },
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
expect(result.current).toBeDefined();
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should accept GET endpoints with query parameters', () => {
|
|
58
|
-
const typedClient = createTypedQueryClient<paths>({
|
|
59
|
-
baseURL: 'https://api.example.com',
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// This should compile - GET endpoints with query params are allowed
|
|
63
|
-
const { result } = renderHook(
|
|
64
|
-
() =>
|
|
65
|
-
typedClient.useQuery('GET /posts', {
|
|
66
|
-
query: { page: 1, limit: 10 },
|
|
67
|
-
}),
|
|
68
|
-
{ wrapper },
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
expect(result.current).toBeDefined();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// The following tests would fail TypeScript compilation if uncommented
|
|
75
|
-
// They are left here as documentation of what should NOT work
|
|
76
|
-
|
|
77
|
-
/*
|
|
78
|
-
it('should NOT accept POST endpoints', () => {
|
|
79
|
-
const typedClient = createTypedQueryClient<paths>({
|
|
80
|
-
baseURL: 'https://api.example.com',
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// @ts-expect-error - POST endpoints should not be allowed in useQuery
|
|
84
|
-
const { result } = renderHook(
|
|
85
|
-
() => typedClient.useQuery('POST /users'),
|
|
86
|
-
{ wrapper },
|
|
87
|
-
);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('should NOT accept PUT endpoints', () => {
|
|
91
|
-
const typedClient = createTypedQueryClient<paths>({
|
|
92
|
-
baseURL: 'https://api.example.com',
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
// @ts-expect-error - PUT endpoints should not be allowed in useQuery
|
|
96
|
-
const { result } = renderHook(
|
|
97
|
-
() => typedClient.useQuery('PUT /users/{id}', { params: { id: '123' } }),
|
|
98
|
-
{ wrapper },
|
|
99
|
-
);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('should NOT accept DELETE endpoints', () => {
|
|
103
|
-
const typedClient = createTypedQueryClient<paths>({
|
|
104
|
-
baseURL: 'https://api.example.com',
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// @ts-expect-error - DELETE endpoints should not be allowed in useQuery
|
|
108
|
-
const { result } = renderHook(
|
|
109
|
-
() => typedClient.useQuery('DELETE /users/{id}', { params: { id: '123' } }),
|
|
110
|
-
{ wrapper },
|
|
111
|
-
);
|
|
112
|
-
});
|
|
113
|
-
*/
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
describe('useMutation', () => {
|
|
117
|
-
it('should accept POST endpoints', () => {
|
|
118
|
-
const typedClient = createTypedQueryClient<paths>({
|
|
119
|
-
baseURL: 'https://api.example.com',
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// This should compile - POST endpoints are allowed
|
|
123
|
-
const { result } = renderHook(
|
|
124
|
-
() => typedClient.useMutation('POST /users'),
|
|
125
|
-
{ wrapper },
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
expect(result.current).toBeDefined();
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('should accept PUT endpoints', () => {
|
|
132
|
-
const typedClient = createTypedQueryClient<paths>({
|
|
133
|
-
baseURL: 'https://api.example.com',
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
// This should compile - PUT endpoints are allowed
|
|
137
|
-
const { result } = renderHook(
|
|
138
|
-
() => typedClient.useMutation('PUT /users/{id}'),
|
|
139
|
-
{ wrapper },
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
expect(result.current).toBeDefined();
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('should accept DELETE endpoints', () => {
|
|
146
|
-
const typedClient = createTypedQueryClient<paths>({
|
|
147
|
-
baseURL: 'https://api.example.com',
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
// This should compile - DELETE endpoints are allowed
|
|
151
|
-
const { result } = renderHook(
|
|
152
|
-
() => typedClient.useMutation('DELETE /users/{id}'),
|
|
153
|
-
{ wrapper },
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
expect(result.current).toBeDefined();
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
// The following test would fail TypeScript compilation if uncommented
|
|
160
|
-
// It is left here as documentation of what should NOT work
|
|
161
|
-
|
|
162
|
-
/*
|
|
163
|
-
it('should NOT accept GET endpoints', () => {
|
|
164
|
-
const typedClient = createTypedQueryClient<paths>({
|
|
165
|
-
baseURL: 'https://api.example.com',
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
// @ts-expect-error - GET endpoints should not be allowed in useMutation
|
|
169
|
-
const { result } = renderHook(
|
|
170
|
-
() => typedClient.useMutation('GET /users'),
|
|
171
|
-
{ wrapper },
|
|
172
|
-
);
|
|
173
|
-
});
|
|
174
|
-
*/
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
describe('Type inference', () => {
|
|
178
|
-
it('should correctly infer response types for GET requests', () => {
|
|
179
|
-
const typedClient = createTypedQueryClient<paths>({
|
|
180
|
-
baseURL: 'https://api.example.com',
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
const { result } = renderHook(() => typedClient.useQuery('GET /users'), {
|
|
184
|
-
wrapper,
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
// TypeScript should infer this type correctly
|
|
188
|
-
type ResponseType = typeof result.current.data;
|
|
189
|
-
type ExpectedType =
|
|
190
|
-
| { users: Array<{ id: string; name: string; email: string }> }
|
|
191
|
-
| undefined;
|
|
192
|
-
|
|
193
|
-
// This assertion validates that the types match at compile time
|
|
194
|
-
const _typeCheck: ResponseType extends ExpectedType ? true : false = true;
|
|
195
|
-
const _typeCheck2: ExpectedType extends ResponseType ? true : false =
|
|
196
|
-
true;
|
|
197
|
-
|
|
198
|
-
expect(_typeCheck).toBe(true);
|
|
199
|
-
expect(_typeCheck2).toBe(true);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
it('should correctly infer response types for POST requests', () => {
|
|
203
|
-
const typedClient = createTypedQueryClient<paths>({
|
|
204
|
-
baseURL: 'https://api.example.com',
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
const { result } = renderHook(
|
|
208
|
-
() => typedClient.useMutation('POST /users'),
|
|
209
|
-
{ wrapper },
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
// TypeScript should infer this type correctly
|
|
213
|
-
type ResponseType = typeof result.current.data;
|
|
214
|
-
type ExpectedType =
|
|
215
|
-
| { id: string; name: string; email: string }
|
|
216
|
-
| undefined;
|
|
217
|
-
|
|
218
|
-
// This assertion validates that the types match at compile time
|
|
219
|
-
const _typeCheck: ResponseType extends ExpectedType ? true : false = true;
|
|
220
|
-
const _typeCheck2: ExpectedType extends ResponseType ? true : false =
|
|
221
|
-
true;
|
|
222
|
-
|
|
223
|
-
expect(_typeCheck).toBe(true);
|
|
224
|
-
expect(_typeCheck2).toBe(true);
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
});
|