@geekmidas/client 0.3.0 → 0.5.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.
Files changed (80) hide show
  1. package/dist/auth-fetcher.cjs +2 -3
  2. package/dist/auth-fetcher.cjs.map +1 -1
  3. package/dist/auth-fetcher.d.cts +2 -1
  4. package/dist/auth-fetcher.d.cts.map +1 -0
  5. package/dist/auth-fetcher.d.mts +2 -1
  6. package/dist/auth-fetcher.d.mts.map +1 -0
  7. package/dist/auth-fetcher.mjs +2 -3
  8. package/dist/auth-fetcher.mjs.map +1 -1
  9. package/dist/endpoint-hooks.cjs +10 -5
  10. package/dist/endpoint-hooks.cjs.map +1 -1
  11. package/dist/endpoint-hooks.d.cts +2 -2
  12. package/dist/endpoint-hooks.d.cts.map +1 -0
  13. package/dist/endpoint-hooks.d.mts +2 -2
  14. package/dist/endpoint-hooks.d.mts.map +1 -0
  15. package/dist/endpoint-hooks.mjs +10 -5
  16. package/dist/endpoint-hooks.mjs.map +1 -1
  17. package/dist/{fetcher-DLDD_7Sa.mjs → fetcher-5fnBE7Dk.mjs} +2 -2
  18. package/dist/fetcher-5fnBE7Dk.mjs.map +1 -0
  19. package/dist/{fetcher-KdwHgdAl.cjs → fetcher-CgLEaIAC.cjs} +2 -2
  20. package/dist/fetcher-CgLEaIAC.cjs.map +1 -0
  21. package/dist/fetcher.cjs +1 -1
  22. package/dist/fetcher.d.cts +3 -1
  23. package/dist/fetcher.d.cts.map +1 -0
  24. package/dist/fetcher.d.mts +3 -1
  25. package/dist/fetcher.d.mts.map +1 -0
  26. package/dist/fetcher.mjs +1 -1
  27. package/dist/infer.d.cts.map +1 -0
  28. package/dist/infer.d.mts.map +1 -0
  29. package/dist/openapi-hooks.cjs +3 -5
  30. package/dist/openapi-hooks.cjs.map +1 -1
  31. package/dist/openapi-hooks.d.cts +3 -3
  32. package/dist/openapi-hooks.d.cts.map +1 -0
  33. package/dist/openapi-hooks.d.mts +6 -6
  34. package/dist/openapi-hooks.d.mts.map +1 -0
  35. package/dist/openapi-hooks.mjs +3 -5
  36. package/dist/openapi-hooks.mjs.map +1 -1
  37. package/dist/openapi-types.d.cts.map +1 -0
  38. package/dist/openapi-types.d.mts.map +1 -0
  39. package/dist/openapi.cjs.map +1 -1
  40. package/dist/openapi.mjs.map +1 -1
  41. package/dist/react-query.cjs +1 -1
  42. package/dist/react-query.cjs.map +1 -1
  43. package/dist/react-query.d.cts +3 -1
  44. package/dist/react-query.d.cts.map +1 -0
  45. package/dist/react-query.d.mts +10 -8
  46. package/dist/react-query.d.mts.map +1 -0
  47. package/dist/react-query.mjs +1 -1
  48. package/dist/react-query.mjs.map +1 -1
  49. package/dist/{types-D4OSWveN.d.cts → types-4K4N-Fl1.d.cts} +8 -6
  50. package/dist/types-4K4N-Fl1.d.cts.map +1 -0
  51. package/dist/{types-Cdv1XAWr.d.mts → types-hhkZWjQn.d.mts} +8 -6
  52. package/dist/types-hhkZWjQn.d.mts.map +1 -0
  53. package/dist/types.d.cts +1 -1
  54. package/dist/types.d.mts +1 -1
  55. package/package.json +6 -5
  56. package/src/__tests__/auth-fetcher.spec.ts +505 -0
  57. package/src/__tests__/endpoint-hooks.spec.tsx +348 -348
  58. package/src/__tests__/fetcher.spec.ts +403 -403
  59. package/src/__tests__/infer.integration.spec.ts +171 -171
  60. package/src/__tests__/infer.spec.ts +182 -182
  61. package/src/__tests__/method-restrictions.spec.tsx +165 -165
  62. package/src/__tests__/openapi-hooks.spec.tsx +536 -537
  63. package/src/__tests__/react-query-infinite.spec.tsx +989 -989
  64. package/src/__tests__/react-query-invalidation.spec.tsx +223 -222
  65. package/src/__tests__/react-query.spec.tsx +567 -567
  66. package/src/__tests__/setup.ts +260 -260
  67. package/src/__tests__/types.spec.ts +127 -127
  68. package/src/__tests__/url-parsing.spec.ts +191 -191
  69. package/src/auth-fetcher.ts +160 -162
  70. package/src/endpoint-hooks.ts +151 -150
  71. package/src/fetcher.ts +163 -163
  72. package/src/infer.ts +64 -63
  73. package/src/openapi-hooks.ts +146 -146
  74. package/src/openapi-types.d.ts +428 -428
  75. package/src/openapi.json +593 -593
  76. package/src/react-query.ts +281 -281
  77. package/src/types.ts +124 -125
  78. package/tsconfig.json +12 -0
  79. package/dist/fetcher-DLDD_7Sa.mjs.map +0 -1
  80. package/dist/fetcher-KdwHgdAl.cjs.map +0 -1
@@ -8,231 +8,232 @@ import React from 'react';
8
8
  import { beforeEach, describe, expect, it, vi } from 'vitest';
9
9
  import type { paths } from '../openapi-types';
10
10
  import { TypedQueryClient, useTypedInvalidateQueries } from '../react-query';
11
+
11
12
  // Mock the fetcher module
12
13
  vi.mock('../fetcher', () => ({
13
- createTypedFetcher: () => vi.fn(),
14
+ createTypedFetcher: () => vi.fn(),
14
15
  }));
15
16
 
16
17
  describe('TypedQueryClient - Query Invalidation', () => {
17
- let queryClient: QueryClient;
18
- let typedClient: TypedQueryClient<paths>;
19
-
20
- beforeEach(() => {
21
- queryClient = new QueryClient({
22
- defaultOptions: {
23
- queries: { retry: false },
24
- },
25
- });
26
- typedClient = new TypedQueryClient({ queryClient });
27
- });
28
-
29
- describe('buildQueryKey', () => {
30
- it('should build query key with endpoint only', () => {
31
- const key = typedClient.buildQueryKey('GET /users');
32
- expect(key).toEqual(['GET /users']);
33
- });
34
-
35
- it('should build query key with params', () => {
36
- const key = typedClient.buildQueryKey('GET /users/{id}', {
37
- params: { id: '123' },
38
- });
39
- expect(key).toEqual(['GET /users/{id}', { params: { id: '123' } }]);
40
- });
41
-
42
- it('should build query key with query params', () => {
43
- const key = typedClient.buildQueryKey('GET /users', {
44
- query: { page: 1, limit: 10 },
45
- });
46
- expect(key).toEqual(['GET /users', { query: { page: 1, limit: 10 } }]);
47
- });
48
-
49
- it('should build query key with params only for paths without query support', () => {
50
- const key = typedClient.buildQueryKey('GET /users/{id}', {
51
- params: { id: '123' },
52
- });
53
- expect(key).toEqual(['GET /users/{id}', { params: { id: '123' } }]);
54
- });
55
- });
56
-
57
- describe('invalidateQueries', () => {
58
- it('should invalidate queries with endpoint only (partial match)', async () => {
59
- const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
60
-
61
- await typedClient.invalidateQueries('GET /users');
62
-
63
- expect(invalidateSpy).toHaveBeenCalledWith({
64
- queryKey: ['GET /users'],
65
- exact: false,
66
- });
67
- });
68
-
69
- it('should invalidate queries with config (exact match)', async () => {
70
- const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
71
-
72
- await typedClient.invalidateQueries('GET /users/{id}', {
73
- params: { id: '123' },
74
- });
75
-
76
- expect(invalidateSpy).toHaveBeenCalledWith({
77
- queryKey: ['GET /users/{id}', { params: { id: '123' } }],
78
- exact: true,
79
- });
80
- });
81
-
82
- it('should invalidate queries with query params', async () => {
83
- const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
84
-
85
- await typedClient.invalidateQueries('GET /posts', {
86
- query: { sort: 'asc' },
87
- });
88
-
89
- expect(invalidateSpy).toHaveBeenCalledWith({
90
- queryKey: ['GET /posts', { query: { sort: 'asc' } }],
91
- exact: true,
92
- });
93
- });
94
- });
95
-
96
- describe('invalidateAllQueries', () => {
97
- it('should invalidate all queries', async () => {
98
- const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
99
-
100
- await typedClient.invalidateAllQueries();
101
-
102
- expect(invalidateSpy).toHaveBeenCalledWith();
103
- });
104
- });
105
-
106
- describe('getQueryClient / setQueryClient', () => {
107
- it('should return the query client when provided in constructor', () => {
108
- const client = typedClient.getQueryClient();
109
- expect(client).toBe(queryClient);
110
- });
111
-
112
- it('should throw error when no query client is set', () => {
113
- const clientWithoutQC = new TypedQueryClient();
114
-
115
- expect(() => clientWithoutQC.getQueryClient()).toThrow(
116
- 'No QueryClient set, please provide a QueryClient via the queryClient option or ensure you are within a QueryClientProvider',
117
- );
118
- });
119
-
120
- it('should allow setting query client after construction', () => {
121
- const clientWithoutQC = new TypedQueryClient();
122
- const newQueryClient = new QueryClient();
123
-
124
- clientWithoutQC.setQueryClient(newQueryClient);
125
-
126
- expect(clientWithoutQC.getQueryClient()).toBe(newQueryClient);
127
- });
128
- });
129
-
130
- describe('useTypedInvalidateQueries hook', () => {
131
- const wrapper = ({ children }: { children: React.ReactNode }) => (
132
- <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
133
- );
134
-
135
- it('should provide invalidateQueries function', async () => {
136
- const { result } = renderHook(
137
- () => useTypedInvalidateQueries(typedClient),
138
- { wrapper },
139
- );
140
-
141
- const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
142
-
143
- await result.current.invalidateQueries('GET /users/{id}', {
144
- params: { id: '456' },
145
- });
146
-
147
- expect(invalidateSpy).toHaveBeenCalledWith({
148
- queryKey: ['GET /users/{id}', { params: { id: '456' } }],
149
- exact: true,
150
- });
151
- });
152
-
153
- it('should provide invalidateAllQueries function', async () => {
154
- const { result } = renderHook(
155
- () => useTypedInvalidateQueries(typedClient),
156
- { wrapper },
157
- );
158
-
159
- const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
160
-
161
- await result.current.invalidateAllQueries();
162
-
163
- expect(invalidateSpy).toHaveBeenCalledWith();
164
- });
165
- });
166
-
167
- describe('Integration test: Query invalidation with real queries', () => {
168
- it('should invalidate matching queries after mutation', async () => {
169
- // Set up some queries in the cache
170
- queryClient.setQueryData(
171
- ['GET /users'],
172
- [
173
- { id: '1', name: 'User 1' },
174
- { id: '2', name: 'User 2' },
175
- ],
176
- );
177
- queryClient.setQueryData(['GET /users/{id}', { params: { id: '1' } }], {
178
- id: '1',
179
- name: 'User 1',
180
- });
181
- queryClient.setQueryData(
182
- ['GET /users', { query: { page: 1 } }],
183
- [{ id: '1', name: 'User 1' }],
184
- );
185
-
186
- // Verify data is in cache
187
- expect(queryClient.getQueryData(['GET /users'])).toBeDefined();
188
- expect(
189
- queryClient.getQueryData(['GET /users/{id}', { params: { id: '1' } }]),
190
- ).toBeDefined();
191
- expect(
192
- queryClient.getQueryData(['GET /users', { query: { page: 1 } }]),
193
- ).toBeDefined();
194
-
195
- // Invalidate all user queries (partial match)
196
- await typedClient.invalidateQueries('GET /users');
197
-
198
- // All queries starting with 'GET /users' should be invalidated
199
- await waitFor(() => {
200
- const cache = queryClient.getQueryCache();
201
- const queries = cache.findAll({ queryKey: ['GET /users'] });
202
- queries.forEach((query) => {
203
- expect(query.state.isInvalidated).toBe(true);
204
- });
205
- });
206
- });
207
-
208
- it('should only invalidate exact matches when config is provided', async () => {
209
- // Set up queries
210
- queryClient.setQueryData(
211
- ['GET /users', { query: { page: 1 } }],
212
- [{ id: '1', name: 'User 1' }],
213
- );
214
- queryClient.setQueryData(
215
- ['GET /users', { query: { page: 2 } }],
216
- [{ id: '2', name: 'User 2' }],
217
- );
218
-
219
- // Invalidate only page 1
220
- await typedClient.invalidateQueries('GET /users', {
221
- query: { page: 1 },
222
- });
223
-
224
- await waitFor(() => {
225
- const cache = queryClient.getQueryCache();
226
- const page1Query = cache.find({
227
- queryKey: ['GET /users', { query: { page: 1 } }],
228
- });
229
- const page2Query = cache.find({
230
- queryKey: ['GET /users', { query: { page: 2 } }],
231
- });
232
-
233
- expect(page1Query?.state.isInvalidated).toBe(true);
234
- expect(page2Query?.state.isInvalidated).toBe(false);
235
- });
236
- });
237
- });
18
+ let queryClient: QueryClient;
19
+ let typedClient: TypedQueryClient<paths>;
20
+
21
+ beforeEach(() => {
22
+ queryClient = new QueryClient({
23
+ defaultOptions: {
24
+ queries: { retry: false },
25
+ },
26
+ });
27
+ typedClient = new TypedQueryClient({ queryClient });
28
+ });
29
+
30
+ describe('buildQueryKey', () => {
31
+ it('should build query key with endpoint only', () => {
32
+ const key = typedClient.buildQueryKey('GET /users');
33
+ expect(key).toEqual(['GET /users']);
34
+ });
35
+
36
+ it('should build query key with params', () => {
37
+ const key = typedClient.buildQueryKey('GET /users/{id}', {
38
+ params: { id: '123' },
39
+ });
40
+ expect(key).toEqual(['GET /users/{id}', { params: { id: '123' } }]);
41
+ });
42
+
43
+ it('should build query key with query params', () => {
44
+ const key = typedClient.buildQueryKey('GET /users', {
45
+ query: { page: 1, limit: 10 },
46
+ });
47
+ expect(key).toEqual(['GET /users', { query: { page: 1, limit: 10 } }]);
48
+ });
49
+
50
+ it('should build query key with params only for paths without query support', () => {
51
+ const key = typedClient.buildQueryKey('GET /users/{id}', {
52
+ params: { id: '123' },
53
+ });
54
+ expect(key).toEqual(['GET /users/{id}', { params: { id: '123' } }]);
55
+ });
56
+ });
57
+
58
+ describe('invalidateQueries', () => {
59
+ it('should invalidate queries with endpoint only (partial match)', async () => {
60
+ const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
61
+
62
+ await typedClient.invalidateQueries('GET /users');
63
+
64
+ expect(invalidateSpy).toHaveBeenCalledWith({
65
+ queryKey: ['GET /users'],
66
+ exact: false,
67
+ });
68
+ });
69
+
70
+ it('should invalidate queries with config (exact match)', async () => {
71
+ const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
72
+
73
+ await typedClient.invalidateQueries('GET /users/{id}', {
74
+ params: { id: '123' },
75
+ });
76
+
77
+ expect(invalidateSpy).toHaveBeenCalledWith({
78
+ queryKey: ['GET /users/{id}', { params: { id: '123' } }],
79
+ exact: true,
80
+ });
81
+ });
82
+
83
+ it('should invalidate queries with query params', async () => {
84
+ const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
85
+
86
+ await typedClient.invalidateQueries('GET /posts', {
87
+ query: { sort: 'asc' },
88
+ });
89
+
90
+ expect(invalidateSpy).toHaveBeenCalledWith({
91
+ queryKey: ['GET /posts', { query: { sort: 'asc' } }],
92
+ exact: true,
93
+ });
94
+ });
95
+ });
96
+
97
+ describe('invalidateAllQueries', () => {
98
+ it('should invalidate all queries', async () => {
99
+ const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
100
+
101
+ await typedClient.invalidateAllQueries();
102
+
103
+ expect(invalidateSpy).toHaveBeenCalledWith();
104
+ });
105
+ });
106
+
107
+ describe('getQueryClient / setQueryClient', () => {
108
+ it('should return the query client when provided in constructor', () => {
109
+ const client = typedClient.getQueryClient();
110
+ expect(client).toBe(queryClient);
111
+ });
112
+
113
+ it('should throw error when no query client is set', () => {
114
+ const clientWithoutQC = new TypedQueryClient();
115
+
116
+ expect(() => clientWithoutQC.getQueryClient()).toThrow(
117
+ 'No QueryClient set, please provide a QueryClient via the queryClient option or ensure you are within a QueryClientProvider',
118
+ );
119
+ });
120
+
121
+ it('should allow setting query client after construction', () => {
122
+ const clientWithoutQC = new TypedQueryClient();
123
+ const newQueryClient = new QueryClient();
124
+
125
+ clientWithoutQC.setQueryClient(newQueryClient);
126
+
127
+ expect(clientWithoutQC.getQueryClient()).toBe(newQueryClient);
128
+ });
129
+ });
130
+
131
+ describe('useTypedInvalidateQueries hook', () => {
132
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
133
+ <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
134
+ );
135
+
136
+ it('should provide invalidateQueries function', async () => {
137
+ const { result } = renderHook(
138
+ () => useTypedInvalidateQueries(typedClient),
139
+ { wrapper },
140
+ );
141
+
142
+ const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
143
+
144
+ await result.current.invalidateQueries('GET /users/{id}', {
145
+ params: { id: '456' },
146
+ });
147
+
148
+ expect(invalidateSpy).toHaveBeenCalledWith({
149
+ queryKey: ['GET /users/{id}', { params: { id: '456' } }],
150
+ exact: true,
151
+ });
152
+ });
153
+
154
+ it('should provide invalidateAllQueries function', async () => {
155
+ const { result } = renderHook(
156
+ () => useTypedInvalidateQueries(typedClient),
157
+ { wrapper },
158
+ );
159
+
160
+ const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries');
161
+
162
+ await result.current.invalidateAllQueries();
163
+
164
+ expect(invalidateSpy).toHaveBeenCalledWith();
165
+ });
166
+ });
167
+
168
+ describe('Integration test: Query invalidation with real queries', () => {
169
+ it('should invalidate matching queries after mutation', async () => {
170
+ // Set up some queries in the cache
171
+ queryClient.setQueryData(
172
+ ['GET /users'],
173
+ [
174
+ { id: '1', name: 'User 1' },
175
+ { id: '2', name: 'User 2' },
176
+ ],
177
+ );
178
+ queryClient.setQueryData(['GET /users/{id}', { params: { id: '1' } }], {
179
+ id: '1',
180
+ name: 'User 1',
181
+ });
182
+ queryClient.setQueryData(
183
+ ['GET /users', { query: { page: 1 } }],
184
+ [{ id: '1', name: 'User 1' }],
185
+ );
186
+
187
+ // Verify data is in cache
188
+ expect(queryClient.getQueryData(['GET /users'])).toBeDefined();
189
+ expect(
190
+ queryClient.getQueryData(['GET /users/{id}', { params: { id: '1' } }]),
191
+ ).toBeDefined();
192
+ expect(
193
+ queryClient.getQueryData(['GET /users', { query: { page: 1 } }]),
194
+ ).toBeDefined();
195
+
196
+ // Invalidate all user queries (partial match)
197
+ await typedClient.invalidateQueries('GET /users');
198
+
199
+ // All queries starting with 'GET /users' should be invalidated
200
+ await waitFor(() => {
201
+ const cache = queryClient.getQueryCache();
202
+ const queries = cache.findAll({ queryKey: ['GET /users'] });
203
+ queries.forEach((query) => {
204
+ expect(query.state.isInvalidated).toBe(true);
205
+ });
206
+ });
207
+ });
208
+
209
+ it('should only invalidate exact matches when config is provided', async () => {
210
+ // Set up queries
211
+ queryClient.setQueryData(
212
+ ['GET /users', { query: { page: 1 } }],
213
+ [{ id: '1', name: 'User 1' }],
214
+ );
215
+ queryClient.setQueryData(
216
+ ['GET /users', { query: { page: 2 } }],
217
+ [{ id: '2', name: 'User 2' }],
218
+ );
219
+
220
+ // Invalidate only page 1
221
+ await typedClient.invalidateQueries('GET /users', {
222
+ query: { page: 1 },
223
+ });
224
+
225
+ await waitFor(() => {
226
+ const cache = queryClient.getQueryCache();
227
+ const page1Query = cache.find({
228
+ queryKey: ['GET /users', { query: { page: 1 } }],
229
+ });
230
+ const page2Query = cache.find({
231
+ queryKey: ['GET /users', { query: { page: 2 } }],
232
+ });
233
+
234
+ expect(page1Query?.state.isInvalidated).toBe(true);
235
+ expect(page2Query?.state.isInvalidated).toBe(false);
236
+ });
237
+ });
238
+ });
238
239
  });