@demokit-ai/tanstack-query 0.2.0 → 0.3.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/LICENSE +190 -0
- package/dist/index.cjs +86 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +36 -10
- package/dist/index.js.map +1 -1
- package/package.json +18 -33
- package/README.md +0 -238
package/LICENSE
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to the Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
Copyright 2025 Kasava, Inc.
|
|
179
|
+
|
|
180
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
181
|
+
you may not use this file except in compliance with the License.
|
|
182
|
+
You may obtain a copy of the License at
|
|
183
|
+
|
|
184
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
185
|
+
|
|
186
|
+
Unless required by applicable law or agreed to in writing, software
|
|
187
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
188
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
189
|
+
See the License for the specific language governing permissions and
|
|
190
|
+
limitations under the License.
|
package/dist/index.cjs
CHANGED
|
@@ -1,13 +1,54 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
2
19
|
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
DemoQueryProvider: () => DemoQueryProvider,
|
|
24
|
+
createDemoQueryClient: () => createDemoQueryClient,
|
|
25
|
+
createDemoQueryFn: () => createDemoQueryFn,
|
|
26
|
+
createMutationOptions: () => createMutationOptions,
|
|
27
|
+
findMatchingFixture: () => findMatchingFixture,
|
|
28
|
+
matchQueryKey: () => import_core.matchQueryKey,
|
|
29
|
+
normalizeFixtureMap: () => normalizeFixtureMap,
|
|
30
|
+
normalizeQueryKey: () => normalizeQueryKey,
|
|
31
|
+
parsePatternString: () => parsePatternString,
|
|
32
|
+
useDemoMutation: () => useDemoMutation,
|
|
33
|
+
useDemoQuery: () => useDemoQuery,
|
|
34
|
+
useIsDemoQueryMode: () => useIsDemoQueryMode
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
7
37
|
|
|
8
38
|
// src/provider.tsx
|
|
9
|
-
var
|
|
39
|
+
var import_react2 = require("react");
|
|
40
|
+
var import_react_query2 = require("@tanstack/react-query");
|
|
41
|
+
|
|
42
|
+
// src/context.ts
|
|
43
|
+
var import_react = require("react");
|
|
44
|
+
var DemoQueryContext = (0, import_react.createContext)(void 0);
|
|
10
45
|
DemoQueryContext.displayName = "DemoQueryContext";
|
|
46
|
+
|
|
47
|
+
// src/client.ts
|
|
48
|
+
var import_react_query = require("@tanstack/react-query");
|
|
49
|
+
|
|
50
|
+
// src/matcher.ts
|
|
51
|
+
var import_core = require("@demokit-ai/core");
|
|
11
52
|
function normalizeQueryKey(queryKey) {
|
|
12
53
|
return queryKey.map((element) => {
|
|
13
54
|
if (element === null || element === void 0) {
|
|
@@ -40,7 +81,7 @@ function normalizeFixtureMap(fixtures) {
|
|
|
40
81
|
}
|
|
41
82
|
function findMatchingFixture(fixtures, queryKey) {
|
|
42
83
|
const normalizedKey = normalizeQueryKey(queryKey);
|
|
43
|
-
const result =
|
|
84
|
+
const result = (0, import_core.findMatchingQueryKeyPattern)(fixtures, normalizedKey);
|
|
44
85
|
if (result) {
|
|
45
86
|
const [, handler, matchResult] = result;
|
|
46
87
|
return [handler, { params: matchResult.params }];
|
|
@@ -105,7 +146,7 @@ function createDemoQueryClient(config = {}) {
|
|
|
105
146
|
fallbackQueryFn,
|
|
106
147
|
isEnabled
|
|
107
148
|
});
|
|
108
|
-
const client = new
|
|
149
|
+
const client = new import_react_query.QueryClient({
|
|
109
150
|
...queryClientConfig,
|
|
110
151
|
defaultOptions: {
|
|
111
152
|
...queryClientConfig.defaultOptions,
|
|
@@ -193,6 +234,9 @@ function createDemoQueryClient(config = {}) {
|
|
|
193
234
|
}
|
|
194
235
|
};
|
|
195
236
|
}
|
|
237
|
+
|
|
238
|
+
// src/provider.tsx
|
|
239
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
196
240
|
function DemoQueryProviderInner({
|
|
197
241
|
children,
|
|
198
242
|
queries = /* @__PURE__ */ new Map(),
|
|
@@ -201,13 +245,13 @@ function DemoQueryProviderInner({
|
|
|
201
245
|
delay = 0,
|
|
202
246
|
staleTime = Infinity
|
|
203
247
|
}) {
|
|
204
|
-
const queryClient =
|
|
205
|
-
const fixturesRef =
|
|
206
|
-
const mutationFixturesRef =
|
|
248
|
+
const queryClient = (0, import_react_query2.useQueryClient)();
|
|
249
|
+
const fixturesRef = (0, import_react2.useRef)(normalizeFixtureMap(queries));
|
|
250
|
+
const mutationFixturesRef = (0, import_react2.useRef)(
|
|
207
251
|
mutations instanceof Map ? mutations : new Map(Object.entries(mutations))
|
|
208
252
|
);
|
|
209
253
|
const isDemoMode = enabledProp ?? false;
|
|
210
|
-
const demoQueryFn =
|
|
254
|
+
const demoQueryFn = (0, import_react2.useMemo)(
|
|
211
255
|
() => createDemoQueryFn({
|
|
212
256
|
fixtures: fixturesRef.current,
|
|
213
257
|
delay,
|
|
@@ -215,7 +259,7 @@ function DemoQueryProviderInner({
|
|
|
215
259
|
}),
|
|
216
260
|
[delay, isDemoMode]
|
|
217
261
|
);
|
|
218
|
-
|
|
262
|
+
(0, import_react2.useEffect)(() => {
|
|
219
263
|
if (isDemoMode) {
|
|
220
264
|
queryClient.setDefaultOptions({
|
|
221
265
|
...queryClient.getDefaultOptions(),
|
|
@@ -228,7 +272,7 @@ function DemoQueryProviderInner({
|
|
|
228
272
|
});
|
|
229
273
|
}
|
|
230
274
|
}, [isDemoMode, demoQueryFn, queryClient, staleTime]);
|
|
231
|
-
const contextValue =
|
|
275
|
+
const contextValue = (0, import_react2.useMemo)(
|
|
232
276
|
() => ({
|
|
233
277
|
isDemoMode,
|
|
234
278
|
setQueryFixture: (pattern, handler) => {
|
|
@@ -252,24 +296,27 @@ function DemoQueryProviderInner({
|
|
|
252
296
|
}),
|
|
253
297
|
[isDemoMode, queryClient]
|
|
254
298
|
);
|
|
255
|
-
return /* @__PURE__ */
|
|
299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DemoQueryContext.Provider, { value: contextValue, children });
|
|
256
300
|
}
|
|
257
301
|
function DemoQueryProvider({
|
|
258
302
|
children,
|
|
259
303
|
client,
|
|
260
304
|
...config
|
|
261
305
|
}) {
|
|
262
|
-
const { client: demoClient } =
|
|
306
|
+
const { client: demoClient } = (0, import_react2.useMemo)(() => {
|
|
263
307
|
if (client) {
|
|
264
308
|
return { client };
|
|
265
309
|
}
|
|
266
310
|
return createDemoQueryClient(config);
|
|
267
311
|
}, [client, config.enabled]);
|
|
268
312
|
const queryClient = client ?? demoClient;
|
|
269
|
-
return /* @__PURE__ */
|
|
313
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_query2.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DemoQueryProviderInner, { ...config, children }) });
|
|
270
314
|
}
|
|
315
|
+
|
|
316
|
+
// src/hooks.ts
|
|
317
|
+
var import_react3 = require("react");
|
|
271
318
|
function useDemoQuery() {
|
|
272
|
-
const context =
|
|
319
|
+
const context = (0, import_react3.useContext)(DemoQueryContext);
|
|
273
320
|
if (context === void 0) {
|
|
274
321
|
throw new Error(
|
|
275
322
|
"useDemoQuery must be used within a DemoQueryProvider. Make sure to wrap your app with <DemoQueryProvider>."
|
|
@@ -280,16 +327,20 @@ function useDemoQuery() {
|
|
|
280
327
|
function useIsDemoQueryMode() {
|
|
281
328
|
return useDemoQuery().isDemoMode;
|
|
282
329
|
}
|
|
330
|
+
|
|
331
|
+
// src/mutation.ts
|
|
332
|
+
var import_react_query3 = require("@tanstack/react-query");
|
|
333
|
+
var import_react4 = require("react");
|
|
283
334
|
function useDemoMutation(options) {
|
|
284
335
|
const { mutationFn, demoName, demoFixture, demoDelay = 0, ...mutationOptions } = options;
|
|
285
|
-
const queryClient =
|
|
336
|
+
const queryClient = (0, import_react_query3.useQueryClient)();
|
|
286
337
|
let isDemoMode = false;
|
|
287
338
|
try {
|
|
288
339
|
const demoState = useDemoQuery();
|
|
289
340
|
isDemoMode = demoState.isDemoMode;
|
|
290
341
|
} catch {
|
|
291
342
|
}
|
|
292
|
-
const demoAwareMutationFn =
|
|
343
|
+
const demoAwareMutationFn = (0, import_react4.useCallback)(
|
|
293
344
|
async (variables) => {
|
|
294
345
|
if (!isDemoMode) {
|
|
295
346
|
return mutationFn(variables);
|
|
@@ -316,7 +367,7 @@ function useDemoMutation(options) {
|
|
|
316
367
|
},
|
|
317
368
|
[isDemoMode, mutationFn, demoFixture, demoDelay, demoName, mutationOptions.mutationKey, queryClient]
|
|
318
369
|
);
|
|
319
|
-
return
|
|
370
|
+
return (0, import_react_query3.useMutation)({
|
|
320
371
|
...mutationOptions,
|
|
321
372
|
mutationFn: demoAwareMutationFn
|
|
322
373
|
});
|
|
@@ -328,21 +379,19 @@ function createMutationOptions(config) {
|
|
|
328
379
|
demoDelay: config.delay
|
|
329
380
|
};
|
|
330
381
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
382
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
383
|
+
0 && (module.exports = {
|
|
384
|
+
DemoQueryProvider,
|
|
385
|
+
createDemoQueryClient,
|
|
386
|
+
createDemoQueryFn,
|
|
387
|
+
createMutationOptions,
|
|
388
|
+
findMatchingFixture,
|
|
389
|
+
matchQueryKey,
|
|
390
|
+
normalizeFixtureMap,
|
|
391
|
+
normalizeQueryKey,
|
|
392
|
+
parsePatternString,
|
|
393
|
+
useDemoMutation,
|
|
394
|
+
useDemoQuery,
|
|
395
|
+
useIsDemoQueryMode
|
|
335
396
|
});
|
|
336
|
-
exports.DemoQueryProvider = DemoQueryProvider;
|
|
337
|
-
exports.createDemoQueryClient = createDemoQueryClient;
|
|
338
|
-
exports.createDemoQueryFn = createDemoQueryFn;
|
|
339
|
-
exports.createMutationOptions = createMutationOptions;
|
|
340
|
-
exports.findMatchingFixture = findMatchingFixture;
|
|
341
|
-
exports.normalizeFixtureMap = normalizeFixtureMap;
|
|
342
|
-
exports.normalizeQueryKey = normalizeQueryKey;
|
|
343
|
-
exports.parsePatternString = parsePatternString;
|
|
344
|
-
exports.useDemoMutation = useDemoMutation;
|
|
345
|
-
exports.useDemoQuery = useDemoQuery;
|
|
346
|
-
exports.useIsDemoQueryMode = useIsDemoQueryMode;
|
|
347
|
-
//# sourceMappingURL=index.cjs.map
|
|
348
397
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.ts","../src/matcher.ts","../src/client.ts","../src/provider.tsx","../src/hooks.ts","../src/mutation.ts"],"names":["createContext","findMatchingQueryKeyPattern","QueryClient","useQueryClient","useRef","useMemo","useEffect","jsx","QueryClientProvider","useContext","useCallback","useMutation"],"mappings":"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","file":"index.cjs","sourcesContent":["'use client'\n\nimport { createContext } from 'react'\nimport type { DemoQueryState } from './types'\n\n/**\n * Context for DemoQuery state\n * @internal\n */\nexport const DemoQueryContext = createContext<DemoQueryState | undefined>(undefined)\n\nDemoQueryContext.displayName = 'DemoQueryContext'\n","import { matchQueryKey, findMatchingQueryKeyPattern } from '@demokit-ai/core'\nimport type { QueryKey } from '@demokit-ai/core'\nimport type { QueryKey as TanStackQueryKey } from '@tanstack/react-query'\nimport type { QueryFixtureHandler, QueryFixtureMap, QueryFixtureMapObject } from './types'\n\n/**\n * Convert TanStack Query key to DemoKit QueryKey\n * TanStack Query keys can contain any value, so we normalize them\n */\nexport function normalizeQueryKey(queryKey: TanStackQueryKey): QueryKey {\n return queryKey.map((element) => {\n if (element === null || element === undefined) {\n return element\n }\n if (typeof element === 'object') {\n // Keep objects as-is for matching\n return element as Record<string, unknown>\n }\n // Primitives are kept as-is\n return element as string | number | boolean\n })\n}\n\n/**\n * Parse a JSON string pattern into a QueryKey\n * Handles both array notation and simple string patterns\n *\n * @example\n * parsePatternString('[\"users\"]') // ['users']\n * parsePatternString('[\"users\", \":id\"]') // ['users', ':id']\n * parsePatternString('users') // ['users']\n */\nexport function parsePatternString(pattern: string): QueryKey {\n // Try to parse as JSON array\n if (pattern.startsWith('[')) {\n try {\n return JSON.parse(pattern) as QueryKey\n } catch {\n // Fall through to simple string\n }\n }\n\n // Simple string becomes single-element array\n return [pattern]\n}\n\n/**\n * Convert object-based fixture map to Map-based fixture map\n */\nexport function normalizeFixtureMap(fixtures: QueryFixtureMapObject | QueryFixtureMap): QueryFixtureMap {\n if (fixtures instanceof Map) {\n return fixtures\n }\n\n const map = new Map<QueryKey, QueryFixtureHandler>()\n for (const [pattern, handler] of Object.entries(fixtures)) {\n map.set(parsePatternString(pattern), handler)\n }\n return map\n}\n\n/**\n * Find a matching fixture for a query key\n *\n * @param fixtures - Map of query key patterns to handlers\n * @param queryKey - The query key to match\n * @returns Tuple of [handler, match result] or null if no match\n */\nexport function findMatchingFixture(\n fixtures: QueryFixtureMap,\n queryKey: TanStackQueryKey\n): [QueryFixtureHandler, { params: Record<string, unknown> }] | null {\n const normalizedKey = normalizeQueryKey(queryKey)\n const result = findMatchingQueryKeyPattern(fixtures, normalizedKey)\n\n if (result) {\n const [, handler, matchResult] = result\n return [handler, { params: matchResult.params }]\n }\n\n return null\n}\n\n/**\n * Re-export the matchQueryKey function for direct use\n */\nexport { matchQueryKey }\n","import { QueryClient, type QueryClientConfig } from '@tanstack/react-query'\nimport type { QueryKey } from '@demokit-ai/core'\nimport type { QueryFixtureMap, DemoQueryProviderConfig, QueryFixtureHandler } from './types'\nimport { findMatchingFixture, normalizeFixtureMap } from './matcher'\n\n/**\n * Configuration for creating a demo-aware QueryClient\n */\nexport interface DemoQueryClientConfig extends DemoQueryProviderConfig {\n /**\n * Base QueryClient config to extend\n */\n queryClientConfig?: QueryClientConfig\n}\n\n/**\n * Create a demo-aware query function\n *\n * This wraps the default query function to intercept demo queries\n * and return fixture data when demo mode is enabled.\n */\nexport function createDemoQueryFn(config: {\n fixtures: QueryFixtureMap\n delay?: number\n fallbackQueryFn?: DemoQueryProviderConfig['fallbackQueryFn']\n isEnabled: () => boolean\n}) {\n const { fixtures, delay = 0, fallbackQueryFn, isEnabled } = config\n\n return async function demoQueryFn({\n queryKey,\n signal,\n }: {\n queryKey: readonly unknown[]\n signal?: AbortSignal\n }) {\n // If demo mode is not enabled, use fallback\n if (!isEnabled()) {\n if (fallbackQueryFn) {\n return fallbackQueryFn({ queryKey, signal })\n }\n throw new Error(\n `[DemoKit] No fallback query function provided and demo mode is disabled. ` +\n `Query key: ${JSON.stringify(queryKey)}`\n )\n }\n\n // Find matching fixture\n const match = findMatchingFixture(fixtures, queryKey as unknown[])\n\n if (!match) {\n // No fixture found, try fallback\n if (fallbackQueryFn) {\n return fallbackQueryFn({ queryKey, signal })\n }\n throw new Error(\n `[DemoKit] No fixture found for query key: ${JSON.stringify(queryKey)}`\n )\n }\n\n const [handler, { params }] = match\n\n // Apply delay if configured\n if (delay > 0) {\n await new Promise((resolve) => setTimeout(resolve, delay))\n }\n\n // Execute handler\n if (typeof handler === 'function') {\n return handler({\n queryKey: queryKey as unknown[],\n params,\n match: { matched: true, params },\n signal,\n })\n }\n\n // Return static value\n return handler\n }\n}\n\n/**\n * Create a demo-aware QueryClient\n *\n * This creates a QueryClient configured to intercept queries when demo mode\n * is enabled and return fixture data instead of making real API calls.\n *\n * @example\n * const { client, enable, disable, isEnabled } = createDemoQueryClient({\n * queries: {\n * '[\"users\"]': [{ id: '1', name: 'Demo User' }],\n * '[\"users\", \":id\"]': ({ params }) => ({ id: params.id, name: 'Demo User' }),\n * },\n * delay: 100, // Simulate 100ms latency\n * })\n *\n * // Use with QueryClientProvider\n * <QueryClientProvider client={client}>\n * <App />\n * </QueryClientProvider>\n */\nexport function createDemoQueryClient(config: DemoQueryClientConfig = {}) {\n const {\n queries = new Map(),\n delay = 0,\n staleTime = Infinity,\n fallbackQueryFn,\n queryClientConfig = {},\n prepopulateCache = false,\n } = config\n\n let enabled = config.enabled ?? false\n const fixtures = normalizeFixtureMap(queries)\n\n const isEnabled = () => enabled\n\n const demoQueryFn = createDemoQueryFn({\n fixtures,\n delay,\n fallbackQueryFn,\n isEnabled,\n })\n\n const client = new QueryClient({\n ...queryClientConfig,\n defaultOptions: {\n ...queryClientConfig.defaultOptions,\n queries: {\n ...queryClientConfig.defaultOptions?.queries,\n queryFn: demoQueryFn,\n staleTime: enabled ? staleTime : queryClientConfig.defaultOptions?.queries?.staleTime,\n retry: enabled ? false : queryClientConfig.defaultOptions?.queries?.retry,\n },\n },\n })\n\n // Pre-populate cache if configured\n const prepopulate = () => {\n if (!prepopulateCache || !enabled) return\n\n for (const [pattern, handler] of fixtures) {\n // Only pre-populate static values (not functions)\n if (typeof handler !== 'function') {\n // Use pattern as query key for static fixtures\n client.setQueryData(pattern, handler)\n }\n }\n }\n\n return {\n /**\n * The QueryClient instance\n */\n client,\n\n /**\n * Enable demo mode\n */\n enable: () => {\n enabled = true\n client.setDefaultOptions({\n ...client.getDefaultOptions(),\n queries: {\n ...client.getDefaultOptions().queries,\n staleTime,\n retry: false,\n },\n })\n prepopulate()\n },\n\n /**\n * Disable demo mode\n */\n disable: () => {\n enabled = false\n client.setDefaultOptions({\n ...client.getDefaultOptions(),\n queries: {\n ...client.getDefaultOptions().queries,\n staleTime: queryClientConfig.defaultOptions?.queries?.staleTime,\n retry: queryClientConfig.defaultOptions?.queries?.retry,\n },\n })\n },\n\n /**\n * Check if demo mode is enabled\n */\n isEnabled,\n\n /**\n * Get the fixture map\n */\n getFixtures: () => fixtures,\n\n /**\n * Add or update a fixture\n */\n setFixture: (pattern: QueryKey, handler: QueryFixtureHandler) => {\n fixtures.set(pattern, handler)\n },\n\n /**\n * Remove a fixture\n */\n removeFixture: (pattern: QueryKey) => {\n fixtures.delete(pattern)\n },\n\n /**\n * Clear all query cache\n */\n clearCache: () => {\n client.clear()\n },\n\n /**\n * Invalidate all queries\n */\n invalidateAll: () => {\n client.invalidateQueries()\n },\n }\n}\n\nexport type DemoQueryClient = ReturnType<typeof createDemoQueryClient>\n","'use client'\n\nimport { useMemo, useRef, useEffect } from 'react'\nimport { QueryClientProvider, useQueryClient } from '@tanstack/react-query'\nimport type { QueryKey } from '@demokit-ai/core'\nimport { DemoQueryContext } from './context'\nimport { createDemoQueryFn, createDemoQueryClient } from './client'\nimport { normalizeFixtureMap } from './matcher'\nimport type {\n DemoQueryProviderProps,\n QueryFixtureHandler,\n QueryFixtureMap,\n MutationFixtureHandler,\n MutationFixtureMap,\n DemoQueryState,\n} from './types'\n\n/**\n * Internal provider component that wraps existing QueryClient\n */\nfunction DemoQueryProviderInner({\n children,\n queries = new Map(),\n mutations = new Map(),\n enabled: enabledProp,\n delay = 0,\n staleTime = Infinity,\n}: Omit<DemoQueryProviderProps, 'client'>) {\n const queryClient = useQueryClient()\n const fixturesRef = useRef<QueryFixtureMap>(normalizeFixtureMap(queries))\n const mutationFixturesRef = useRef<MutationFixtureMap>(\n mutations instanceof Map ? mutations : new Map(Object.entries(mutations))\n )\n\n // Use enabled prop directly - demo mode is controlled by parent\n const isDemoMode = enabledProp ?? false\n\n // Create demo-aware query function\n const demoQueryFn = useMemo(\n () =>\n createDemoQueryFn({\n fixtures: fixturesRef.current,\n delay,\n isEnabled: () => isDemoMode,\n }),\n [delay, isDemoMode]\n )\n\n // Update query client defaults when demo mode changes\n useEffect(() => {\n if (isDemoMode) {\n queryClient.setDefaultOptions({\n ...queryClient.getDefaultOptions(),\n queries: {\n ...queryClient.getDefaultOptions().queries,\n queryFn: demoQueryFn,\n staleTime,\n retry: false,\n },\n })\n }\n }, [isDemoMode, demoQueryFn, queryClient, staleTime])\n\n // Create context value\n const contextValue = useMemo<DemoQueryState>(\n () => ({\n isDemoMode,\n\n setQueryFixture: (pattern: QueryKey, handler: QueryFixtureHandler) => {\n fixturesRef.current.set(pattern, handler)\n },\n\n removeQueryFixture: (pattern: QueryKey) => {\n fixturesRef.current.delete(pattern)\n },\n\n setMutationFixture: (name: string, handler: MutationFixtureHandler) => {\n mutationFixturesRef.current.set(name, handler)\n },\n\n removeMutationFixture: (name: string) => {\n mutationFixturesRef.current.delete(name)\n },\n\n invalidateAll: () => {\n queryClient.invalidateQueries()\n },\n\n resetCache: () => {\n queryClient.clear()\n },\n }),\n [isDemoMode, queryClient]\n )\n\n return (\n <DemoQueryContext.Provider value={contextValue}>\n {children}\n </DemoQueryContext.Provider>\n )\n}\n\n/**\n * Provider component for DemoKit TanStack Query integration\n *\n * Wraps QueryClientProvider and intercepts queries when demo mode is enabled.\n *\n * @example\n * // With new QueryClient\n * <DemoQueryProvider\n * queries={{\n * '[\"users\"]': [{ id: '1', name: 'Demo User' }],\n * '[\"users\", \":id\"]': ({ params }) => ({ id: params.id, name: 'Demo User' }),\n * }}\n * >\n * <App />\n * </DemoQueryProvider>\n *\n * @example\n * // With existing QueryClient\n * const queryClient = new QueryClient()\n *\n * <DemoQueryProvider client={queryClient} queries={...}>\n * <App />\n * </DemoQueryProvider>\n *\n * @example\n * // With DemoKitProvider (auto-detects demo mode)\n * <DemoKitProvider fixtures={...}>\n * <DemoQueryProvider queries={...}>\n * <App />\n * </DemoQueryProvider>\n * </DemoKitProvider>\n */\nexport function DemoQueryProvider({\n children,\n client,\n ...config\n}: DemoQueryProviderProps) {\n // If no client provided, create one\n const { client: demoClient } = useMemo(() => {\n if (client) {\n return { client }\n }\n return createDemoQueryClient(config)\n }, [client, config.enabled])\n\n const queryClient = client ?? demoClient\n\n return (\n <QueryClientProvider client={queryClient}>\n <DemoQueryProviderInner {...config}>{children}</DemoQueryProviderInner>\n </QueryClientProvider>\n )\n}\n","'use client'\n\nimport { useContext } from 'react'\nimport { DemoQueryContext } from './context'\nimport type { DemoQueryState } from './types'\n\n/**\n * Hook to access DemoQuery state and controls\n *\n * @returns DemoQuery context value\n * @throws Error if used outside of DemoQueryProvider\n *\n * @example\n * function MyComponent() {\n * const { isDemoMode, setQueryFixture, invalidateAll } = useDemoQuery()\n *\n * // Dynamically add a fixture\n * const handleAddFixture = () => {\n * setQueryFixture(['users', 'custom'], { id: 'custom', name: 'Custom User' })\n * invalidateAll() // Trigger refetch\n * }\n *\n * return (\n * <button onClick={handleAddFixture}>Add Custom Fixture</button>\n * )\n * }\n */\nexport function useDemoQuery(): DemoQueryState {\n const context = useContext(DemoQueryContext)\n\n if (context === undefined) {\n throw new Error(\n 'useDemoQuery must be used within a DemoQueryProvider. ' +\n 'Make sure to wrap your app with <DemoQueryProvider>.'\n )\n }\n\n return context\n}\n\n/**\n * Hook to check if demo mode is enabled\n * Shorthand for useDemoQuery().isDemoMode\n *\n * @example\n * function MyComponent() {\n * const isDemoMode = useIsDemoQueryMode()\n *\n * return isDemoMode ? <DemoBadge /> : null\n * }\n */\nexport function useIsDemoQueryMode(): boolean {\n return useDemoQuery().isDemoMode\n}\n","'use client'\n\nimport { useMutation, useQueryClient, type UseMutationOptions, type UseMutationResult } from '@tanstack/react-query'\nimport { useCallback, useMemo } from 'react'\nimport type { MutationFixtureContext, MutationFixtureHandler } from './types'\nimport { useDemoQuery } from './hooks'\n\n/**\n * Options for useDemoMutation hook\n */\nexport interface UseDemoMutationOptions<TData, TError, TVariables, TContext>\n extends Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn'> {\n /**\n * The real mutation function to use when demo mode is disabled\n */\n mutationFn: (variables: TVariables) => Promise<TData>\n\n /**\n * Name used to look up the demo fixture\n * If not provided, uses mutationKey as string\n */\n demoName?: string\n\n /**\n * Demo fixture handler for this mutation\n * If provided, overrides the fixture from DemoQueryProvider\n */\n demoFixture?: MutationFixtureHandler<TData, TVariables>\n\n /**\n * Delay in ms before returning demo data\n * @default 0\n */\n demoDelay?: number\n}\n\n/**\n * A mutation hook that automatically uses demo fixtures when demo mode is enabled\n *\n * @example\n * const createUser = useDemoMutation({\n * mutationFn: async (data) => api.createUser(data),\n * demoName: 'createUser',\n * demoFixture: ({ variables, queryClient }) => {\n * // Create demo user\n * const newUser = { id: crypto.randomUUID(), ...variables }\n *\n * // Update the users query cache\n * queryClient.setQueryData(['users'], (old: User[] = []) => [...old, newUser])\n *\n * return newUser\n * },\n * onSuccess: (data) => {\n * console.log('Created user:', data)\n * },\n * })\n *\n * // Use like normal useMutation\n * createUser.mutate({ name: 'New User', email: 'user@example.com' })\n */\nexport function useDemoMutation<\n TData = unknown,\n TError = unknown,\n TVariables = void,\n TContext = unknown,\n>(\n options: UseDemoMutationOptions<TData, TError, TVariables, TContext>\n): UseMutationResult<TData, TError, TVariables, TContext> {\n const { mutationFn, demoName, demoFixture, demoDelay = 0, ...mutationOptions } = options\n\n const queryClient = useQueryClient()\n\n // Try to get demo state - may not be in DemoQueryProvider context\n let isDemoMode = false\n try {\n const demoState = useDemoQuery()\n isDemoMode = demoState.isDemoMode\n } catch {\n // Not in DemoQueryProvider context, use real mutation\n }\n\n // Create the demo-aware mutation function\n const demoAwareMutationFn = useCallback(\n async (variables: TVariables): Promise<TData> => {\n // If not in demo mode, use real mutation\n if (!isDemoMode) {\n return mutationFn(variables)\n }\n\n // Apply delay if configured\n if (demoDelay > 0) {\n await new Promise((resolve) => setTimeout(resolve, demoDelay))\n }\n\n // If a demo fixture is provided, use it\n if (demoFixture !== undefined) {\n const context: MutationFixtureContext<TVariables> = {\n mutationKey: mutationOptions.mutationKey,\n variables,\n queryClient,\n }\n\n if (typeof demoFixture === 'function') {\n // Cast to the function type to help TypeScript understand\n const fixtureFn = demoFixture as (context: MutationFixtureContext<TVariables>) => TData | Promise<TData>\n return fixtureFn(context)\n }\n return demoFixture as TData\n }\n\n // No fixture found, fall back to real mutation\n console.warn(\n `[DemoKit] No mutation fixture found for \"${demoName || mutationOptions.mutationKey?.join('/') || 'unknown'}\". ` +\n 'Using real mutation function.'\n )\n return mutationFn(variables)\n },\n [isDemoMode, mutationFn, demoFixture, demoDelay, demoName, mutationOptions.mutationKey, queryClient]\n )\n\n return useMutation({\n ...mutationOptions,\n mutationFn: demoAwareMutationFn,\n })\n}\n\n/**\n * Create a set of demo mutations with fixtures\n *\n * @example\n * const mutations = createDemoMutations({\n * createUser: {\n * mutationFn: api.createUser,\n * fixture: ({ variables, queryClient }) => {\n * const newUser = { id: 'demo-1', ...variables }\n * queryClient.setQueryData(['users'], (old = []) => [...old, newUser])\n * return newUser\n * },\n * },\n * deleteUser: {\n * mutationFn: api.deleteUser,\n * fixture: ({ variables, queryClient }) => {\n * queryClient.setQueryData(['users'], (old: User[] = []) =>\n * old.filter(u => u.id !== variables.id)\n * )\n * return { success: true }\n * },\n * },\n * })\n *\n * // Use in components\n * const { createUser, deleteUser } = mutations\n */\nexport type DemoMutationConfig<TData, TVariables> = {\n mutationFn: (variables: TVariables) => Promise<TData>\n fixture: MutationFixtureHandler<TData, TVariables>\n delay?: number\n}\n\n/**\n * Helper to create mutation options with demo fixture\n */\nexport function createMutationOptions<TData, TVariables>(\n config: DemoMutationConfig<TData, TVariables>\n): Pick<UseDemoMutationOptions<TData, unknown, TVariables, unknown>, 'mutationFn' | 'demoFixture' | 'demoDelay'> {\n return {\n mutationFn: config.mutationFn,\n demoFixture: config.fixture,\n demoDelay: config.delay,\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/context.ts","../src/client.ts","../src/matcher.ts","../src/hooks.ts","../src/mutation.ts"],"sourcesContent":["/**\n * @demokit-ai/tanstack-query\n *\n * TanStack Query v5 adapter for DemoKit.\n * Mock queries and mutations when demo mode is enabled.\n *\n * @example\n * import { DemoQueryProvider } from '@demokit-ai/tanstack-query'\n *\n * // Define query fixtures\n * const queryFixtures = {\n * '[\"users\"]': [\n * { id: '1', name: 'Demo User' },\n * { id: '2', name: 'Another User' },\n * ],\n * '[\"users\", \":id\"]': ({ params }) => ({\n * id: params.id,\n * name: `User ${params.id}`,\n * }),\n * '[\"projects\", { status: \":status\" }]': ({ params }) => [\n * { id: '1', name: 'Project', status: params.status },\n * ],\n * }\n *\n * // Wrap your app\n * <DemoQueryProvider queries={queryFixtures} enabled={true}>\n * <App />\n * </DemoQueryProvider>\n *\n * @packageDocumentation\n */\n\n// Provider\nexport { DemoQueryProvider } from './provider'\n\n// Hooks\nexport { useDemoQuery, useIsDemoQueryMode } from './hooks'\nexport { useDemoMutation, createMutationOptions } from './mutation'\nexport type { UseDemoMutationOptions, DemoMutationConfig } from './mutation'\n\n// Client utilities\nexport { createDemoQueryClient, createDemoQueryFn, type DemoQueryClient } from './client'\n\n// Matcher utilities\nexport {\n findMatchingFixture,\n normalizeQueryKey,\n normalizeFixtureMap,\n parsePatternString,\n matchQueryKey,\n} from './matcher'\n\n// Types\nexport type {\n QueryFixtureContext,\n QueryFixtureHandler,\n QueryFixtureMap,\n QueryFixtureMapObject,\n MutationFixtureContext,\n MutationFixtureHandler,\n MutationFixtureMap,\n MutationFixtureMapObject,\n DemoQueryProviderConfig,\n DemoQueryProviderProps,\n DemoQueryState,\n} from './types'\n","'use client'\n\nimport { useMemo, useRef, useEffect } from 'react'\nimport { QueryClientProvider, useQueryClient } from '@tanstack/react-query'\nimport type { QueryKey } from '@demokit-ai/core'\nimport { DemoQueryContext } from './context'\nimport { createDemoQueryFn, createDemoQueryClient } from './client'\nimport { normalizeFixtureMap } from './matcher'\nimport type {\n DemoQueryProviderProps,\n QueryFixtureHandler,\n QueryFixtureMap,\n MutationFixtureHandler,\n MutationFixtureMap,\n DemoQueryState,\n} from './types'\n\n/**\n * Internal provider component that wraps existing QueryClient\n */\nfunction DemoQueryProviderInner({\n children,\n queries = new Map(),\n mutations = new Map(),\n enabled: enabledProp,\n delay = 0,\n staleTime = Infinity,\n}: Omit<DemoQueryProviderProps, 'client'>) {\n const queryClient = useQueryClient()\n const fixturesRef = useRef<QueryFixtureMap>(normalizeFixtureMap(queries))\n const mutationFixturesRef = useRef<MutationFixtureMap>(\n mutations instanceof Map ? mutations : new Map(Object.entries(mutations))\n )\n\n // Use enabled prop directly - demo mode is controlled by parent\n const isDemoMode = enabledProp ?? false\n\n // Create demo-aware query function\n const demoQueryFn = useMemo(\n () =>\n createDemoQueryFn({\n fixtures: fixturesRef.current,\n delay,\n isEnabled: () => isDemoMode,\n }),\n [delay, isDemoMode]\n )\n\n // Update query client defaults when demo mode changes\n useEffect(() => {\n if (isDemoMode) {\n queryClient.setDefaultOptions({\n ...queryClient.getDefaultOptions(),\n queries: {\n ...queryClient.getDefaultOptions().queries,\n queryFn: demoQueryFn,\n staleTime,\n retry: false,\n },\n })\n }\n }, [isDemoMode, demoQueryFn, queryClient, staleTime])\n\n // Create context value\n const contextValue = useMemo<DemoQueryState>(\n () => ({\n isDemoMode,\n\n setQueryFixture: (pattern: QueryKey, handler: QueryFixtureHandler) => {\n fixturesRef.current.set(pattern, handler)\n },\n\n removeQueryFixture: (pattern: QueryKey) => {\n fixturesRef.current.delete(pattern)\n },\n\n setMutationFixture: (name: string, handler: MutationFixtureHandler) => {\n mutationFixturesRef.current.set(name, handler)\n },\n\n removeMutationFixture: (name: string) => {\n mutationFixturesRef.current.delete(name)\n },\n\n invalidateAll: () => {\n queryClient.invalidateQueries()\n },\n\n resetCache: () => {\n queryClient.clear()\n },\n }),\n [isDemoMode, queryClient]\n )\n\n return (\n <DemoQueryContext.Provider value={contextValue}>\n {children}\n </DemoQueryContext.Provider>\n )\n}\n\n/**\n * Provider component for DemoKit TanStack Query integration\n *\n * Wraps QueryClientProvider and intercepts queries when demo mode is enabled.\n *\n * @example\n * // With new QueryClient\n * <DemoQueryProvider\n * queries={{\n * '[\"users\"]': [{ id: '1', name: 'Demo User' }],\n * '[\"users\", \":id\"]': ({ params }) => ({ id: params.id, name: 'Demo User' }),\n * }}\n * >\n * <App />\n * </DemoQueryProvider>\n *\n * @example\n * // With existing QueryClient\n * const queryClient = new QueryClient()\n *\n * <DemoQueryProvider client={queryClient} queries={...}>\n * <App />\n * </DemoQueryProvider>\n *\n * @example\n * // With DemoKitProvider (auto-detects demo mode)\n * <DemoKitProvider fixtures={...}>\n * <DemoQueryProvider queries={...}>\n * <App />\n * </DemoQueryProvider>\n * </DemoKitProvider>\n */\nexport function DemoQueryProvider({\n children,\n client,\n ...config\n}: DemoQueryProviderProps) {\n // If no client provided, create one\n const { client: demoClient } = useMemo(() => {\n if (client) {\n return { client }\n }\n return createDemoQueryClient(config)\n }, [client, config.enabled])\n\n const queryClient = client ?? demoClient\n\n return (\n <QueryClientProvider client={queryClient}>\n <DemoQueryProviderInner {...config}>{children}</DemoQueryProviderInner>\n </QueryClientProvider>\n )\n}\n","'use client'\n\nimport { createContext } from 'react'\nimport type { DemoQueryState } from './types'\n\n/**\n * Context for DemoQuery state\n * @internal\n */\nexport const DemoQueryContext = createContext<DemoQueryState | undefined>(undefined)\n\nDemoQueryContext.displayName = 'DemoQueryContext'\n","import { QueryClient, type QueryClientConfig } from '@tanstack/react-query'\nimport type { QueryKey } from '@demokit-ai/core'\nimport type { QueryFixtureMap, DemoQueryProviderConfig, QueryFixtureHandler } from './types'\nimport { findMatchingFixture, normalizeFixtureMap } from './matcher'\n\n/**\n * Configuration for creating a demo-aware QueryClient\n */\nexport interface DemoQueryClientConfig extends DemoQueryProviderConfig {\n /**\n * Base QueryClient config to extend\n */\n queryClientConfig?: QueryClientConfig\n}\n\n/**\n * Create a demo-aware query function\n *\n * This wraps the default query function to intercept demo queries\n * and return fixture data when demo mode is enabled.\n */\nexport function createDemoQueryFn(config: {\n fixtures: QueryFixtureMap\n delay?: number\n fallbackQueryFn?: DemoQueryProviderConfig['fallbackQueryFn']\n isEnabled: () => boolean\n}) {\n const { fixtures, delay = 0, fallbackQueryFn, isEnabled } = config\n\n return async function demoQueryFn({\n queryKey,\n signal,\n }: {\n queryKey: readonly unknown[]\n signal?: AbortSignal\n }) {\n // If demo mode is not enabled, use fallback\n if (!isEnabled()) {\n if (fallbackQueryFn) {\n return fallbackQueryFn({ queryKey, signal })\n }\n throw new Error(\n `[DemoKit] No fallback query function provided and demo mode is disabled. ` +\n `Query key: ${JSON.stringify(queryKey)}`\n )\n }\n\n // Find matching fixture\n const match = findMatchingFixture(fixtures, queryKey as unknown[])\n\n if (!match) {\n // No fixture found, try fallback\n if (fallbackQueryFn) {\n return fallbackQueryFn({ queryKey, signal })\n }\n throw new Error(\n `[DemoKit] No fixture found for query key: ${JSON.stringify(queryKey)}`\n )\n }\n\n const [handler, { params }] = match\n\n // Apply delay if configured\n if (delay > 0) {\n await new Promise((resolve) => setTimeout(resolve, delay))\n }\n\n // Execute handler\n if (typeof handler === 'function') {\n return handler({\n queryKey: queryKey as unknown[],\n params,\n match: { matched: true, params },\n signal,\n })\n }\n\n // Return static value\n return handler\n }\n}\n\n/**\n * Create a demo-aware QueryClient\n *\n * This creates a QueryClient configured to intercept queries when demo mode\n * is enabled and return fixture data instead of making real API calls.\n *\n * @example\n * const { client, enable, disable, isEnabled } = createDemoQueryClient({\n * queries: {\n * '[\"users\"]': [{ id: '1', name: 'Demo User' }],\n * '[\"users\", \":id\"]': ({ params }) => ({ id: params.id, name: 'Demo User' }),\n * },\n * delay: 100, // Simulate 100ms latency\n * })\n *\n * // Use with QueryClientProvider\n * <QueryClientProvider client={client}>\n * <App />\n * </QueryClientProvider>\n */\nexport function createDemoQueryClient(config: DemoQueryClientConfig = {}) {\n const {\n queries = new Map(),\n delay = 0,\n staleTime = Infinity,\n fallbackQueryFn,\n queryClientConfig = {},\n prepopulateCache = false,\n } = config\n\n let enabled = config.enabled ?? false\n const fixtures = normalizeFixtureMap(queries)\n\n const isEnabled = () => enabled\n\n const demoQueryFn = createDemoQueryFn({\n fixtures,\n delay,\n fallbackQueryFn,\n isEnabled,\n })\n\n const client = new QueryClient({\n ...queryClientConfig,\n defaultOptions: {\n ...queryClientConfig.defaultOptions,\n queries: {\n ...queryClientConfig.defaultOptions?.queries,\n queryFn: demoQueryFn,\n staleTime: enabled ? staleTime : queryClientConfig.defaultOptions?.queries?.staleTime,\n retry: enabled ? false : queryClientConfig.defaultOptions?.queries?.retry,\n },\n },\n })\n\n // Pre-populate cache if configured\n const prepopulate = () => {\n if (!prepopulateCache || !enabled) return\n\n for (const [pattern, handler] of fixtures) {\n // Only pre-populate static values (not functions)\n if (typeof handler !== 'function') {\n // Use pattern as query key for static fixtures\n client.setQueryData(pattern, handler)\n }\n }\n }\n\n return {\n /**\n * The QueryClient instance\n */\n client,\n\n /**\n * Enable demo mode\n */\n enable: () => {\n enabled = true\n client.setDefaultOptions({\n ...client.getDefaultOptions(),\n queries: {\n ...client.getDefaultOptions().queries,\n staleTime,\n retry: false,\n },\n })\n prepopulate()\n },\n\n /**\n * Disable demo mode\n */\n disable: () => {\n enabled = false\n client.setDefaultOptions({\n ...client.getDefaultOptions(),\n queries: {\n ...client.getDefaultOptions().queries,\n staleTime: queryClientConfig.defaultOptions?.queries?.staleTime,\n retry: queryClientConfig.defaultOptions?.queries?.retry,\n },\n })\n },\n\n /**\n * Check if demo mode is enabled\n */\n isEnabled,\n\n /**\n * Get the fixture map\n */\n getFixtures: () => fixtures,\n\n /**\n * Add or update a fixture\n */\n setFixture: (pattern: QueryKey, handler: QueryFixtureHandler) => {\n fixtures.set(pattern, handler)\n },\n\n /**\n * Remove a fixture\n */\n removeFixture: (pattern: QueryKey) => {\n fixtures.delete(pattern)\n },\n\n /**\n * Clear all query cache\n */\n clearCache: () => {\n client.clear()\n },\n\n /**\n * Invalidate all queries\n */\n invalidateAll: () => {\n client.invalidateQueries()\n },\n }\n}\n\nexport type DemoQueryClient = ReturnType<typeof createDemoQueryClient>\n","import { matchQueryKey, findMatchingQueryKeyPattern } from '@demokit-ai/core'\nimport type { QueryKey } from '@demokit-ai/core'\nimport type { QueryKey as TanStackQueryKey } from '@tanstack/react-query'\nimport type { QueryFixtureHandler, QueryFixtureMap, QueryFixtureMapObject } from './types'\n\n/**\n * Convert TanStack Query key to DemoKit QueryKey\n * TanStack Query keys can contain any value, so we normalize them\n */\nexport function normalizeQueryKey(queryKey: TanStackQueryKey): QueryKey {\n return queryKey.map((element) => {\n if (element === null || element === undefined) {\n return element\n }\n if (typeof element === 'object') {\n // Keep objects as-is for matching\n return element as Record<string, unknown>\n }\n // Primitives are kept as-is\n return element as string | number | boolean\n })\n}\n\n/**\n * Parse a JSON string pattern into a QueryKey\n * Handles both array notation and simple string patterns\n *\n * @example\n * parsePatternString('[\"users\"]') // ['users']\n * parsePatternString('[\"users\", \":id\"]') // ['users', ':id']\n * parsePatternString('users') // ['users']\n */\nexport function parsePatternString(pattern: string): QueryKey {\n // Try to parse as JSON array\n if (pattern.startsWith('[')) {\n try {\n return JSON.parse(pattern) as QueryKey\n } catch {\n // Fall through to simple string\n }\n }\n\n // Simple string becomes single-element array\n return [pattern]\n}\n\n/**\n * Convert object-based fixture map to Map-based fixture map\n */\nexport function normalizeFixtureMap(fixtures: QueryFixtureMapObject | QueryFixtureMap): QueryFixtureMap {\n if (fixtures instanceof Map) {\n return fixtures\n }\n\n const map = new Map<QueryKey, QueryFixtureHandler>()\n for (const [pattern, handler] of Object.entries(fixtures)) {\n map.set(parsePatternString(pattern), handler)\n }\n return map\n}\n\n/**\n * Find a matching fixture for a query key\n *\n * @param fixtures - Map of query key patterns to handlers\n * @param queryKey - The query key to match\n * @returns Tuple of [handler, match result] or null if no match\n */\nexport function findMatchingFixture(\n fixtures: QueryFixtureMap,\n queryKey: TanStackQueryKey\n): [QueryFixtureHandler, { params: Record<string, unknown> }] | null {\n const normalizedKey = normalizeQueryKey(queryKey)\n const result = findMatchingQueryKeyPattern(fixtures, normalizedKey)\n\n if (result) {\n const [, handler, matchResult] = result\n return [handler, { params: matchResult.params }]\n }\n\n return null\n}\n\n/**\n * Re-export the matchQueryKey function for direct use\n */\nexport { matchQueryKey }\n","'use client'\n\nimport { useContext } from 'react'\nimport { DemoQueryContext } from './context'\nimport type { DemoQueryState } from './types'\n\n/**\n * Hook to access DemoQuery state and controls\n *\n * @returns DemoQuery context value\n * @throws Error if used outside of DemoQueryProvider\n *\n * @example\n * function MyComponent() {\n * const { isDemoMode, setQueryFixture, invalidateAll } = useDemoQuery()\n *\n * // Dynamically add a fixture\n * const handleAddFixture = () => {\n * setQueryFixture(['users', 'custom'], { id: 'custom', name: 'Custom User' })\n * invalidateAll() // Trigger refetch\n * }\n *\n * return (\n * <button onClick={handleAddFixture}>Add Custom Fixture</button>\n * )\n * }\n */\nexport function useDemoQuery(): DemoQueryState {\n const context = useContext(DemoQueryContext)\n\n if (context === undefined) {\n throw new Error(\n 'useDemoQuery must be used within a DemoQueryProvider. ' +\n 'Make sure to wrap your app with <DemoQueryProvider>.'\n )\n }\n\n return context\n}\n\n/**\n * Hook to check if demo mode is enabled\n * Shorthand for useDemoQuery().isDemoMode\n *\n * @example\n * function MyComponent() {\n * const isDemoMode = useIsDemoQueryMode()\n *\n * return isDemoMode ? <DemoBadge /> : null\n * }\n */\nexport function useIsDemoQueryMode(): boolean {\n return useDemoQuery().isDemoMode\n}\n","'use client'\n\nimport { useMutation, useQueryClient, type UseMutationOptions, type UseMutationResult } from '@tanstack/react-query'\nimport { useCallback } from 'react'\nimport type { MutationFixtureContext, MutationFixtureHandler } from './types'\nimport { useDemoQuery } from './hooks'\n\n/**\n * Options for useDemoMutation hook\n */\nexport interface UseDemoMutationOptions<TData, TError, TVariables, TContext>\n extends Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn'> {\n /**\n * The real mutation function to use when demo mode is disabled\n */\n mutationFn: (variables: TVariables) => Promise<TData>\n\n /**\n * Name used to look up the demo fixture\n * If not provided, uses mutationKey as string\n */\n demoName?: string\n\n /**\n * Demo fixture handler for this mutation\n * If provided, overrides the fixture from DemoQueryProvider\n */\n demoFixture?: MutationFixtureHandler<TData, TVariables>\n\n /**\n * Delay in ms before returning demo data\n * @default 0\n */\n demoDelay?: number\n}\n\n/**\n * A mutation hook that automatically uses demo fixtures when demo mode is enabled\n *\n * @example\n * const createUser = useDemoMutation({\n * mutationFn: async (data) => api.createUser(data),\n * demoName: 'createUser',\n * demoFixture: ({ variables, queryClient }) => {\n * // Create demo user\n * const newUser = { id: crypto.randomUUID(), ...variables }\n *\n * // Update the users query cache\n * queryClient.setQueryData(['users'], (old: User[] = []) => [...old, newUser])\n *\n * return newUser\n * },\n * onSuccess: (data) => {\n * console.log('Created user:', data)\n * },\n * })\n *\n * // Use like normal useMutation\n * createUser.mutate({ name: 'New User', email: 'user@example.com' })\n */\nexport function useDemoMutation<\n TData = unknown,\n TError = unknown,\n TVariables = void,\n TContext = unknown,\n>(\n options: UseDemoMutationOptions<TData, TError, TVariables, TContext>\n): UseMutationResult<TData, TError, TVariables, TContext> {\n const { mutationFn, demoName, demoFixture, demoDelay = 0, ...mutationOptions } = options\n\n const queryClient = useQueryClient()\n\n // Try to get demo state - may not be in DemoQueryProvider context\n let isDemoMode = false\n try {\n const demoState = useDemoQuery()\n isDemoMode = demoState.isDemoMode\n } catch {\n // Not in DemoQueryProvider context, use real mutation\n }\n\n // Create the demo-aware mutation function\n const demoAwareMutationFn = useCallback(\n async (variables: TVariables): Promise<TData> => {\n // If not in demo mode, use real mutation\n if (!isDemoMode) {\n return mutationFn(variables)\n }\n\n // Apply delay if configured\n if (demoDelay > 0) {\n await new Promise((resolve) => setTimeout(resolve, demoDelay))\n }\n\n // If a demo fixture is provided, use it\n if (demoFixture !== undefined) {\n const context: MutationFixtureContext<TVariables> = {\n mutationKey: mutationOptions.mutationKey,\n variables,\n queryClient,\n }\n\n if (typeof demoFixture === 'function') {\n // Cast to the function type to help TypeScript understand\n const fixtureFn = demoFixture as (context: MutationFixtureContext<TVariables>) => TData | Promise<TData>\n return fixtureFn(context)\n }\n return demoFixture as TData\n }\n\n // No fixture found, fall back to real mutation\n console.warn(\n `[DemoKit] No mutation fixture found for \"${demoName || mutationOptions.mutationKey?.join('/') || 'unknown'}\". ` +\n 'Using real mutation function.'\n )\n return mutationFn(variables)\n },\n [isDemoMode, mutationFn, demoFixture, demoDelay, demoName, mutationOptions.mutationKey, queryClient]\n )\n\n return useMutation({\n ...mutationOptions,\n mutationFn: demoAwareMutationFn,\n })\n}\n\n/**\n * Create a set of demo mutations with fixtures\n *\n * @example\n * const mutations = createDemoMutations({\n * createUser: {\n * mutationFn: api.createUser,\n * fixture: ({ variables, queryClient }) => {\n * const newUser = { id: 'demo-1', ...variables }\n * queryClient.setQueryData(['users'], (old = []) => [...old, newUser])\n * return newUser\n * },\n * },\n * deleteUser: {\n * mutationFn: api.deleteUser,\n * fixture: ({ variables, queryClient }) => {\n * queryClient.setQueryData(['users'], (old: User[] = []) =>\n * old.filter(u => u.id !== variables.id)\n * )\n * return { success: true }\n * },\n * },\n * })\n *\n * // Use in components\n * const { createUser, deleteUser } = mutations\n */\nexport type DemoMutationConfig<TData, TVariables> = {\n mutationFn: (variables: TVariables) => Promise<TData>\n fixture: MutationFixtureHandler<TData, TVariables>\n delay?: number\n}\n\n/**\n * Helper to create mutation options with demo fixture\n */\nexport function createMutationOptions<TData, TVariables>(\n config: DemoMutationConfig<TData, TVariables>\n): Pick<UseDemoMutationOptions<TData, unknown, TVariables, unknown>, 'mutationFn' | 'demoFixture' | 'demoDelay'> {\n return {\n mutationFn: config.mutationFn,\n demoFixture: config.fixture,\n demoDelay: config.delay,\n }\n}\n"],"mappings":"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","names":["import_react","import_react_query","import_react","import_react_query","import_react"]}
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import { createContext, useMemo, useContext, useCallback, useRef, useEffect } from 'react';
|
|
2
|
-
import { QueryClient, QueryClientProvider, useQueryClient, useMutation } from '@tanstack/react-query';
|
|
3
|
-
import { findMatchingQueryKeyPattern } from '@demokit-ai/core';
|
|
4
|
-
export { matchQueryKey } from '@demokit-ai/core';
|
|
5
|
-
import { jsx } from 'react/jsx-runtime';
|
|
6
|
-
|
|
7
1
|
// src/provider.tsx
|
|
2
|
+
import { useMemo, useRef, useEffect } from "react";
|
|
3
|
+
import { QueryClientProvider, useQueryClient } from "@tanstack/react-query";
|
|
4
|
+
|
|
5
|
+
// src/context.ts
|
|
6
|
+
import { createContext } from "react";
|
|
8
7
|
var DemoQueryContext = createContext(void 0);
|
|
9
8
|
DemoQueryContext.displayName = "DemoQueryContext";
|
|
9
|
+
|
|
10
|
+
// src/client.ts
|
|
11
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
12
|
+
|
|
13
|
+
// src/matcher.ts
|
|
14
|
+
import { matchQueryKey, findMatchingQueryKeyPattern } from "@demokit-ai/core";
|
|
10
15
|
function normalizeQueryKey(queryKey) {
|
|
11
16
|
return queryKey.map((element) => {
|
|
12
17
|
if (element === null || element === void 0) {
|
|
@@ -192,6 +197,9 @@ function createDemoQueryClient(config = {}) {
|
|
|
192
197
|
}
|
|
193
198
|
};
|
|
194
199
|
}
|
|
200
|
+
|
|
201
|
+
// src/provider.tsx
|
|
202
|
+
import { jsx } from "react/jsx-runtime";
|
|
195
203
|
function DemoQueryProviderInner({
|
|
196
204
|
children,
|
|
197
205
|
queries = /* @__PURE__ */ new Map(),
|
|
@@ -267,6 +275,9 @@ function DemoQueryProvider({
|
|
|
267
275
|
const queryClient = client ?? demoClient;
|
|
268
276
|
return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(DemoQueryProviderInner, { ...config, children }) });
|
|
269
277
|
}
|
|
278
|
+
|
|
279
|
+
// src/hooks.ts
|
|
280
|
+
import { useContext } from "react";
|
|
270
281
|
function useDemoQuery() {
|
|
271
282
|
const context = useContext(DemoQueryContext);
|
|
272
283
|
if (context === void 0) {
|
|
@@ -279,9 +290,13 @@ function useDemoQuery() {
|
|
|
279
290
|
function useIsDemoQueryMode() {
|
|
280
291
|
return useDemoQuery().isDemoMode;
|
|
281
292
|
}
|
|
293
|
+
|
|
294
|
+
// src/mutation.ts
|
|
295
|
+
import { useMutation, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
|
|
296
|
+
import { useCallback } from "react";
|
|
282
297
|
function useDemoMutation(options) {
|
|
283
298
|
const { mutationFn, demoName, demoFixture, demoDelay = 0, ...mutationOptions } = options;
|
|
284
|
-
const queryClient =
|
|
299
|
+
const queryClient = useQueryClient2();
|
|
285
300
|
let isDemoMode = false;
|
|
286
301
|
try {
|
|
287
302
|
const demoState = useDemoQuery();
|
|
@@ -327,7 +342,18 @@ function createMutationOptions(config) {
|
|
|
327
342
|
demoDelay: config.delay
|
|
328
343
|
};
|
|
329
344
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
345
|
+
export {
|
|
346
|
+
DemoQueryProvider,
|
|
347
|
+
createDemoQueryClient,
|
|
348
|
+
createDemoQueryFn,
|
|
349
|
+
createMutationOptions,
|
|
350
|
+
findMatchingFixture,
|
|
351
|
+
matchQueryKey,
|
|
352
|
+
normalizeFixtureMap,
|
|
353
|
+
normalizeQueryKey,
|
|
354
|
+
parsePatternString,
|
|
355
|
+
useDemoMutation,
|
|
356
|
+
useDemoQuery,
|
|
357
|
+
useIsDemoQueryMode
|
|
358
|
+
};
|
|
333
359
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.ts","../src/matcher.ts","../src/client.ts","../src/provider.tsx","../src/hooks.ts","../src/mutation.ts"],"names":["useQueryClient"],"mappings":"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","file":"index.js","sourcesContent":["'use client'\n\nimport { createContext } from 'react'\nimport type { DemoQueryState } from './types'\n\n/**\n * Context for DemoQuery state\n * @internal\n */\nexport const DemoQueryContext = createContext<DemoQueryState | undefined>(undefined)\n\nDemoQueryContext.displayName = 'DemoQueryContext'\n","import { matchQueryKey, findMatchingQueryKeyPattern } from '@demokit-ai/core'\nimport type { QueryKey } from '@demokit-ai/core'\nimport type { QueryKey as TanStackQueryKey } from '@tanstack/react-query'\nimport type { QueryFixtureHandler, QueryFixtureMap, QueryFixtureMapObject } from './types'\n\n/**\n * Convert TanStack Query key to DemoKit QueryKey\n * TanStack Query keys can contain any value, so we normalize them\n */\nexport function normalizeQueryKey(queryKey: TanStackQueryKey): QueryKey {\n return queryKey.map((element) => {\n if (element === null || element === undefined) {\n return element\n }\n if (typeof element === 'object') {\n // Keep objects as-is for matching\n return element as Record<string, unknown>\n }\n // Primitives are kept as-is\n return element as string | number | boolean\n })\n}\n\n/**\n * Parse a JSON string pattern into a QueryKey\n * Handles both array notation and simple string patterns\n *\n * @example\n * parsePatternString('[\"users\"]') // ['users']\n * parsePatternString('[\"users\", \":id\"]') // ['users', ':id']\n * parsePatternString('users') // ['users']\n */\nexport function parsePatternString(pattern: string): QueryKey {\n // Try to parse as JSON array\n if (pattern.startsWith('[')) {\n try {\n return JSON.parse(pattern) as QueryKey\n } catch {\n // Fall through to simple string\n }\n }\n\n // Simple string becomes single-element array\n return [pattern]\n}\n\n/**\n * Convert object-based fixture map to Map-based fixture map\n */\nexport function normalizeFixtureMap(fixtures: QueryFixtureMapObject | QueryFixtureMap): QueryFixtureMap {\n if (fixtures instanceof Map) {\n return fixtures\n }\n\n const map = new Map<QueryKey, QueryFixtureHandler>()\n for (const [pattern, handler] of Object.entries(fixtures)) {\n map.set(parsePatternString(pattern), handler)\n }\n return map\n}\n\n/**\n * Find a matching fixture for a query key\n *\n * @param fixtures - Map of query key patterns to handlers\n * @param queryKey - The query key to match\n * @returns Tuple of [handler, match result] or null if no match\n */\nexport function findMatchingFixture(\n fixtures: QueryFixtureMap,\n queryKey: TanStackQueryKey\n): [QueryFixtureHandler, { params: Record<string, unknown> }] | null {\n const normalizedKey = normalizeQueryKey(queryKey)\n const result = findMatchingQueryKeyPattern(fixtures, normalizedKey)\n\n if (result) {\n const [, handler, matchResult] = result\n return [handler, { params: matchResult.params }]\n }\n\n return null\n}\n\n/**\n * Re-export the matchQueryKey function for direct use\n */\nexport { matchQueryKey }\n","import { QueryClient, type QueryClientConfig } from '@tanstack/react-query'\nimport type { QueryKey } from '@demokit-ai/core'\nimport type { QueryFixtureMap, DemoQueryProviderConfig, QueryFixtureHandler } from './types'\nimport { findMatchingFixture, normalizeFixtureMap } from './matcher'\n\n/**\n * Configuration for creating a demo-aware QueryClient\n */\nexport interface DemoQueryClientConfig extends DemoQueryProviderConfig {\n /**\n * Base QueryClient config to extend\n */\n queryClientConfig?: QueryClientConfig\n}\n\n/**\n * Create a demo-aware query function\n *\n * This wraps the default query function to intercept demo queries\n * and return fixture data when demo mode is enabled.\n */\nexport function createDemoQueryFn(config: {\n fixtures: QueryFixtureMap\n delay?: number\n fallbackQueryFn?: DemoQueryProviderConfig['fallbackQueryFn']\n isEnabled: () => boolean\n}) {\n const { fixtures, delay = 0, fallbackQueryFn, isEnabled } = config\n\n return async function demoQueryFn({\n queryKey,\n signal,\n }: {\n queryKey: readonly unknown[]\n signal?: AbortSignal\n }) {\n // If demo mode is not enabled, use fallback\n if (!isEnabled()) {\n if (fallbackQueryFn) {\n return fallbackQueryFn({ queryKey, signal })\n }\n throw new Error(\n `[DemoKit] No fallback query function provided and demo mode is disabled. ` +\n `Query key: ${JSON.stringify(queryKey)}`\n )\n }\n\n // Find matching fixture\n const match = findMatchingFixture(fixtures, queryKey as unknown[])\n\n if (!match) {\n // No fixture found, try fallback\n if (fallbackQueryFn) {\n return fallbackQueryFn({ queryKey, signal })\n }\n throw new Error(\n `[DemoKit] No fixture found for query key: ${JSON.stringify(queryKey)}`\n )\n }\n\n const [handler, { params }] = match\n\n // Apply delay if configured\n if (delay > 0) {\n await new Promise((resolve) => setTimeout(resolve, delay))\n }\n\n // Execute handler\n if (typeof handler === 'function') {\n return handler({\n queryKey: queryKey as unknown[],\n params,\n match: { matched: true, params },\n signal,\n })\n }\n\n // Return static value\n return handler\n }\n}\n\n/**\n * Create a demo-aware QueryClient\n *\n * This creates a QueryClient configured to intercept queries when demo mode\n * is enabled and return fixture data instead of making real API calls.\n *\n * @example\n * const { client, enable, disable, isEnabled } = createDemoQueryClient({\n * queries: {\n * '[\"users\"]': [{ id: '1', name: 'Demo User' }],\n * '[\"users\", \":id\"]': ({ params }) => ({ id: params.id, name: 'Demo User' }),\n * },\n * delay: 100, // Simulate 100ms latency\n * })\n *\n * // Use with QueryClientProvider\n * <QueryClientProvider client={client}>\n * <App />\n * </QueryClientProvider>\n */\nexport function createDemoQueryClient(config: DemoQueryClientConfig = {}) {\n const {\n queries = new Map(),\n delay = 0,\n staleTime = Infinity,\n fallbackQueryFn,\n queryClientConfig = {},\n prepopulateCache = false,\n } = config\n\n let enabled = config.enabled ?? false\n const fixtures = normalizeFixtureMap(queries)\n\n const isEnabled = () => enabled\n\n const demoQueryFn = createDemoQueryFn({\n fixtures,\n delay,\n fallbackQueryFn,\n isEnabled,\n })\n\n const client = new QueryClient({\n ...queryClientConfig,\n defaultOptions: {\n ...queryClientConfig.defaultOptions,\n queries: {\n ...queryClientConfig.defaultOptions?.queries,\n queryFn: demoQueryFn,\n staleTime: enabled ? staleTime : queryClientConfig.defaultOptions?.queries?.staleTime,\n retry: enabled ? false : queryClientConfig.defaultOptions?.queries?.retry,\n },\n },\n })\n\n // Pre-populate cache if configured\n const prepopulate = () => {\n if (!prepopulateCache || !enabled) return\n\n for (const [pattern, handler] of fixtures) {\n // Only pre-populate static values (not functions)\n if (typeof handler !== 'function') {\n // Use pattern as query key for static fixtures\n client.setQueryData(pattern, handler)\n }\n }\n }\n\n return {\n /**\n * The QueryClient instance\n */\n client,\n\n /**\n * Enable demo mode\n */\n enable: () => {\n enabled = true\n client.setDefaultOptions({\n ...client.getDefaultOptions(),\n queries: {\n ...client.getDefaultOptions().queries,\n staleTime,\n retry: false,\n },\n })\n prepopulate()\n },\n\n /**\n * Disable demo mode\n */\n disable: () => {\n enabled = false\n client.setDefaultOptions({\n ...client.getDefaultOptions(),\n queries: {\n ...client.getDefaultOptions().queries,\n staleTime: queryClientConfig.defaultOptions?.queries?.staleTime,\n retry: queryClientConfig.defaultOptions?.queries?.retry,\n },\n })\n },\n\n /**\n * Check if demo mode is enabled\n */\n isEnabled,\n\n /**\n * Get the fixture map\n */\n getFixtures: () => fixtures,\n\n /**\n * Add or update a fixture\n */\n setFixture: (pattern: QueryKey, handler: QueryFixtureHandler) => {\n fixtures.set(pattern, handler)\n },\n\n /**\n * Remove a fixture\n */\n removeFixture: (pattern: QueryKey) => {\n fixtures.delete(pattern)\n },\n\n /**\n * Clear all query cache\n */\n clearCache: () => {\n client.clear()\n },\n\n /**\n * Invalidate all queries\n */\n invalidateAll: () => {\n client.invalidateQueries()\n },\n }\n}\n\nexport type DemoQueryClient = ReturnType<typeof createDemoQueryClient>\n","'use client'\n\nimport { useMemo, useRef, useEffect } from 'react'\nimport { QueryClientProvider, useQueryClient } from '@tanstack/react-query'\nimport type { QueryKey } from '@demokit-ai/core'\nimport { DemoQueryContext } from './context'\nimport { createDemoQueryFn, createDemoQueryClient } from './client'\nimport { normalizeFixtureMap } from './matcher'\nimport type {\n DemoQueryProviderProps,\n QueryFixtureHandler,\n QueryFixtureMap,\n MutationFixtureHandler,\n MutationFixtureMap,\n DemoQueryState,\n} from './types'\n\n/**\n * Internal provider component that wraps existing QueryClient\n */\nfunction DemoQueryProviderInner({\n children,\n queries = new Map(),\n mutations = new Map(),\n enabled: enabledProp,\n delay = 0,\n staleTime = Infinity,\n}: Omit<DemoQueryProviderProps, 'client'>) {\n const queryClient = useQueryClient()\n const fixturesRef = useRef<QueryFixtureMap>(normalizeFixtureMap(queries))\n const mutationFixturesRef = useRef<MutationFixtureMap>(\n mutations instanceof Map ? mutations : new Map(Object.entries(mutations))\n )\n\n // Use enabled prop directly - demo mode is controlled by parent\n const isDemoMode = enabledProp ?? false\n\n // Create demo-aware query function\n const demoQueryFn = useMemo(\n () =>\n createDemoQueryFn({\n fixtures: fixturesRef.current,\n delay,\n isEnabled: () => isDemoMode,\n }),\n [delay, isDemoMode]\n )\n\n // Update query client defaults when demo mode changes\n useEffect(() => {\n if (isDemoMode) {\n queryClient.setDefaultOptions({\n ...queryClient.getDefaultOptions(),\n queries: {\n ...queryClient.getDefaultOptions().queries,\n queryFn: demoQueryFn,\n staleTime,\n retry: false,\n },\n })\n }\n }, [isDemoMode, demoQueryFn, queryClient, staleTime])\n\n // Create context value\n const contextValue = useMemo<DemoQueryState>(\n () => ({\n isDemoMode,\n\n setQueryFixture: (pattern: QueryKey, handler: QueryFixtureHandler) => {\n fixturesRef.current.set(pattern, handler)\n },\n\n removeQueryFixture: (pattern: QueryKey) => {\n fixturesRef.current.delete(pattern)\n },\n\n setMutationFixture: (name: string, handler: MutationFixtureHandler) => {\n mutationFixturesRef.current.set(name, handler)\n },\n\n removeMutationFixture: (name: string) => {\n mutationFixturesRef.current.delete(name)\n },\n\n invalidateAll: () => {\n queryClient.invalidateQueries()\n },\n\n resetCache: () => {\n queryClient.clear()\n },\n }),\n [isDemoMode, queryClient]\n )\n\n return (\n <DemoQueryContext.Provider value={contextValue}>\n {children}\n </DemoQueryContext.Provider>\n )\n}\n\n/**\n * Provider component for DemoKit TanStack Query integration\n *\n * Wraps QueryClientProvider and intercepts queries when demo mode is enabled.\n *\n * @example\n * // With new QueryClient\n * <DemoQueryProvider\n * queries={{\n * '[\"users\"]': [{ id: '1', name: 'Demo User' }],\n * '[\"users\", \":id\"]': ({ params }) => ({ id: params.id, name: 'Demo User' }),\n * }}\n * >\n * <App />\n * </DemoQueryProvider>\n *\n * @example\n * // With existing QueryClient\n * const queryClient = new QueryClient()\n *\n * <DemoQueryProvider client={queryClient} queries={...}>\n * <App />\n * </DemoQueryProvider>\n *\n * @example\n * // With DemoKitProvider (auto-detects demo mode)\n * <DemoKitProvider fixtures={...}>\n * <DemoQueryProvider queries={...}>\n * <App />\n * </DemoQueryProvider>\n * </DemoKitProvider>\n */\nexport function DemoQueryProvider({\n children,\n client,\n ...config\n}: DemoQueryProviderProps) {\n // If no client provided, create one\n const { client: demoClient } = useMemo(() => {\n if (client) {\n return { client }\n }\n return createDemoQueryClient(config)\n }, [client, config.enabled])\n\n const queryClient = client ?? demoClient\n\n return (\n <QueryClientProvider client={queryClient}>\n <DemoQueryProviderInner {...config}>{children}</DemoQueryProviderInner>\n </QueryClientProvider>\n )\n}\n","'use client'\n\nimport { useContext } from 'react'\nimport { DemoQueryContext } from './context'\nimport type { DemoQueryState } from './types'\n\n/**\n * Hook to access DemoQuery state and controls\n *\n * @returns DemoQuery context value\n * @throws Error if used outside of DemoQueryProvider\n *\n * @example\n * function MyComponent() {\n * const { isDemoMode, setQueryFixture, invalidateAll } = useDemoQuery()\n *\n * // Dynamically add a fixture\n * const handleAddFixture = () => {\n * setQueryFixture(['users', 'custom'], { id: 'custom', name: 'Custom User' })\n * invalidateAll() // Trigger refetch\n * }\n *\n * return (\n * <button onClick={handleAddFixture}>Add Custom Fixture</button>\n * )\n * }\n */\nexport function useDemoQuery(): DemoQueryState {\n const context = useContext(DemoQueryContext)\n\n if (context === undefined) {\n throw new Error(\n 'useDemoQuery must be used within a DemoQueryProvider. ' +\n 'Make sure to wrap your app with <DemoQueryProvider>.'\n )\n }\n\n return context\n}\n\n/**\n * Hook to check if demo mode is enabled\n * Shorthand for useDemoQuery().isDemoMode\n *\n * @example\n * function MyComponent() {\n * const isDemoMode = useIsDemoQueryMode()\n *\n * return isDemoMode ? <DemoBadge /> : null\n * }\n */\nexport function useIsDemoQueryMode(): boolean {\n return useDemoQuery().isDemoMode\n}\n","'use client'\n\nimport { useMutation, useQueryClient, type UseMutationOptions, type UseMutationResult } from '@tanstack/react-query'\nimport { useCallback, useMemo } from 'react'\nimport type { MutationFixtureContext, MutationFixtureHandler } from './types'\nimport { useDemoQuery } from './hooks'\n\n/**\n * Options for useDemoMutation hook\n */\nexport interface UseDemoMutationOptions<TData, TError, TVariables, TContext>\n extends Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn'> {\n /**\n * The real mutation function to use when demo mode is disabled\n */\n mutationFn: (variables: TVariables) => Promise<TData>\n\n /**\n * Name used to look up the demo fixture\n * If not provided, uses mutationKey as string\n */\n demoName?: string\n\n /**\n * Demo fixture handler for this mutation\n * If provided, overrides the fixture from DemoQueryProvider\n */\n demoFixture?: MutationFixtureHandler<TData, TVariables>\n\n /**\n * Delay in ms before returning demo data\n * @default 0\n */\n demoDelay?: number\n}\n\n/**\n * A mutation hook that automatically uses demo fixtures when demo mode is enabled\n *\n * @example\n * const createUser = useDemoMutation({\n * mutationFn: async (data) => api.createUser(data),\n * demoName: 'createUser',\n * demoFixture: ({ variables, queryClient }) => {\n * // Create demo user\n * const newUser = { id: crypto.randomUUID(), ...variables }\n *\n * // Update the users query cache\n * queryClient.setQueryData(['users'], (old: User[] = []) => [...old, newUser])\n *\n * return newUser\n * },\n * onSuccess: (data) => {\n * console.log('Created user:', data)\n * },\n * })\n *\n * // Use like normal useMutation\n * createUser.mutate({ name: 'New User', email: 'user@example.com' })\n */\nexport function useDemoMutation<\n TData = unknown,\n TError = unknown,\n TVariables = void,\n TContext = unknown,\n>(\n options: UseDemoMutationOptions<TData, TError, TVariables, TContext>\n): UseMutationResult<TData, TError, TVariables, TContext> {\n const { mutationFn, demoName, demoFixture, demoDelay = 0, ...mutationOptions } = options\n\n const queryClient = useQueryClient()\n\n // Try to get demo state - may not be in DemoQueryProvider context\n let isDemoMode = false\n try {\n const demoState = useDemoQuery()\n isDemoMode = demoState.isDemoMode\n } catch {\n // Not in DemoQueryProvider context, use real mutation\n }\n\n // Create the demo-aware mutation function\n const demoAwareMutationFn = useCallback(\n async (variables: TVariables): Promise<TData> => {\n // If not in demo mode, use real mutation\n if (!isDemoMode) {\n return mutationFn(variables)\n }\n\n // Apply delay if configured\n if (demoDelay > 0) {\n await new Promise((resolve) => setTimeout(resolve, demoDelay))\n }\n\n // If a demo fixture is provided, use it\n if (demoFixture !== undefined) {\n const context: MutationFixtureContext<TVariables> = {\n mutationKey: mutationOptions.mutationKey,\n variables,\n queryClient,\n }\n\n if (typeof demoFixture === 'function') {\n // Cast to the function type to help TypeScript understand\n const fixtureFn = demoFixture as (context: MutationFixtureContext<TVariables>) => TData | Promise<TData>\n return fixtureFn(context)\n }\n return demoFixture as TData\n }\n\n // No fixture found, fall back to real mutation\n console.warn(\n `[DemoKit] No mutation fixture found for \"${demoName || mutationOptions.mutationKey?.join('/') || 'unknown'}\". ` +\n 'Using real mutation function.'\n )\n return mutationFn(variables)\n },\n [isDemoMode, mutationFn, demoFixture, demoDelay, demoName, mutationOptions.mutationKey, queryClient]\n )\n\n return useMutation({\n ...mutationOptions,\n mutationFn: demoAwareMutationFn,\n })\n}\n\n/**\n * Create a set of demo mutations with fixtures\n *\n * @example\n * const mutations = createDemoMutations({\n * createUser: {\n * mutationFn: api.createUser,\n * fixture: ({ variables, queryClient }) => {\n * const newUser = { id: 'demo-1', ...variables }\n * queryClient.setQueryData(['users'], (old = []) => [...old, newUser])\n * return newUser\n * },\n * },\n * deleteUser: {\n * mutationFn: api.deleteUser,\n * fixture: ({ variables, queryClient }) => {\n * queryClient.setQueryData(['users'], (old: User[] = []) =>\n * old.filter(u => u.id !== variables.id)\n * )\n * return { success: true }\n * },\n * },\n * })\n *\n * // Use in components\n * const { createUser, deleteUser } = mutations\n */\nexport type DemoMutationConfig<TData, TVariables> = {\n mutationFn: (variables: TVariables) => Promise<TData>\n fixture: MutationFixtureHandler<TData, TVariables>\n delay?: number\n}\n\n/**\n * Helper to create mutation options with demo fixture\n */\nexport function createMutationOptions<TData, TVariables>(\n config: DemoMutationConfig<TData, TVariables>\n): Pick<UseDemoMutationOptions<TData, unknown, TVariables, unknown>, 'mutationFn' | 'demoFixture' | 'demoDelay'> {\n return {\n mutationFn: config.mutationFn,\n demoFixture: config.fixture,\n demoDelay: config.delay,\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/provider.tsx","../src/context.ts","../src/client.ts","../src/matcher.ts","../src/hooks.ts","../src/mutation.ts"],"sourcesContent":["'use client'\n\nimport { useMemo, useRef, useEffect } from 'react'\nimport { QueryClientProvider, useQueryClient } from '@tanstack/react-query'\nimport type { QueryKey } from '@demokit-ai/core'\nimport { DemoQueryContext } from './context'\nimport { createDemoQueryFn, createDemoQueryClient } from './client'\nimport { normalizeFixtureMap } from './matcher'\nimport type {\n DemoQueryProviderProps,\n QueryFixtureHandler,\n QueryFixtureMap,\n MutationFixtureHandler,\n MutationFixtureMap,\n DemoQueryState,\n} from './types'\n\n/**\n * Internal provider component that wraps existing QueryClient\n */\nfunction DemoQueryProviderInner({\n children,\n queries = new Map(),\n mutations = new Map(),\n enabled: enabledProp,\n delay = 0,\n staleTime = Infinity,\n}: Omit<DemoQueryProviderProps, 'client'>) {\n const queryClient = useQueryClient()\n const fixturesRef = useRef<QueryFixtureMap>(normalizeFixtureMap(queries))\n const mutationFixturesRef = useRef<MutationFixtureMap>(\n mutations instanceof Map ? mutations : new Map(Object.entries(mutations))\n )\n\n // Use enabled prop directly - demo mode is controlled by parent\n const isDemoMode = enabledProp ?? false\n\n // Create demo-aware query function\n const demoQueryFn = useMemo(\n () =>\n createDemoQueryFn({\n fixtures: fixturesRef.current,\n delay,\n isEnabled: () => isDemoMode,\n }),\n [delay, isDemoMode]\n )\n\n // Update query client defaults when demo mode changes\n useEffect(() => {\n if (isDemoMode) {\n queryClient.setDefaultOptions({\n ...queryClient.getDefaultOptions(),\n queries: {\n ...queryClient.getDefaultOptions().queries,\n queryFn: demoQueryFn,\n staleTime,\n retry: false,\n },\n })\n }\n }, [isDemoMode, demoQueryFn, queryClient, staleTime])\n\n // Create context value\n const contextValue = useMemo<DemoQueryState>(\n () => ({\n isDemoMode,\n\n setQueryFixture: (pattern: QueryKey, handler: QueryFixtureHandler) => {\n fixturesRef.current.set(pattern, handler)\n },\n\n removeQueryFixture: (pattern: QueryKey) => {\n fixturesRef.current.delete(pattern)\n },\n\n setMutationFixture: (name: string, handler: MutationFixtureHandler) => {\n mutationFixturesRef.current.set(name, handler)\n },\n\n removeMutationFixture: (name: string) => {\n mutationFixturesRef.current.delete(name)\n },\n\n invalidateAll: () => {\n queryClient.invalidateQueries()\n },\n\n resetCache: () => {\n queryClient.clear()\n },\n }),\n [isDemoMode, queryClient]\n )\n\n return (\n <DemoQueryContext.Provider value={contextValue}>\n {children}\n </DemoQueryContext.Provider>\n )\n}\n\n/**\n * Provider component for DemoKit TanStack Query integration\n *\n * Wraps QueryClientProvider and intercepts queries when demo mode is enabled.\n *\n * @example\n * // With new QueryClient\n * <DemoQueryProvider\n * queries={{\n * '[\"users\"]': [{ id: '1', name: 'Demo User' }],\n * '[\"users\", \":id\"]': ({ params }) => ({ id: params.id, name: 'Demo User' }),\n * }}\n * >\n * <App />\n * </DemoQueryProvider>\n *\n * @example\n * // With existing QueryClient\n * const queryClient = new QueryClient()\n *\n * <DemoQueryProvider client={queryClient} queries={...}>\n * <App />\n * </DemoQueryProvider>\n *\n * @example\n * // With DemoKitProvider (auto-detects demo mode)\n * <DemoKitProvider fixtures={...}>\n * <DemoQueryProvider queries={...}>\n * <App />\n * </DemoQueryProvider>\n * </DemoKitProvider>\n */\nexport function DemoQueryProvider({\n children,\n client,\n ...config\n}: DemoQueryProviderProps) {\n // If no client provided, create one\n const { client: demoClient } = useMemo(() => {\n if (client) {\n return { client }\n }\n return createDemoQueryClient(config)\n }, [client, config.enabled])\n\n const queryClient = client ?? demoClient\n\n return (\n <QueryClientProvider client={queryClient}>\n <DemoQueryProviderInner {...config}>{children}</DemoQueryProviderInner>\n </QueryClientProvider>\n )\n}\n","'use client'\n\nimport { createContext } from 'react'\nimport type { DemoQueryState } from './types'\n\n/**\n * Context for DemoQuery state\n * @internal\n */\nexport const DemoQueryContext = createContext<DemoQueryState | undefined>(undefined)\n\nDemoQueryContext.displayName = 'DemoQueryContext'\n","import { QueryClient, type QueryClientConfig } from '@tanstack/react-query'\nimport type { QueryKey } from '@demokit-ai/core'\nimport type { QueryFixtureMap, DemoQueryProviderConfig, QueryFixtureHandler } from './types'\nimport { findMatchingFixture, normalizeFixtureMap } from './matcher'\n\n/**\n * Configuration for creating a demo-aware QueryClient\n */\nexport interface DemoQueryClientConfig extends DemoQueryProviderConfig {\n /**\n * Base QueryClient config to extend\n */\n queryClientConfig?: QueryClientConfig\n}\n\n/**\n * Create a demo-aware query function\n *\n * This wraps the default query function to intercept demo queries\n * and return fixture data when demo mode is enabled.\n */\nexport function createDemoQueryFn(config: {\n fixtures: QueryFixtureMap\n delay?: number\n fallbackQueryFn?: DemoQueryProviderConfig['fallbackQueryFn']\n isEnabled: () => boolean\n}) {\n const { fixtures, delay = 0, fallbackQueryFn, isEnabled } = config\n\n return async function demoQueryFn({\n queryKey,\n signal,\n }: {\n queryKey: readonly unknown[]\n signal?: AbortSignal\n }) {\n // If demo mode is not enabled, use fallback\n if (!isEnabled()) {\n if (fallbackQueryFn) {\n return fallbackQueryFn({ queryKey, signal })\n }\n throw new Error(\n `[DemoKit] No fallback query function provided and demo mode is disabled. ` +\n `Query key: ${JSON.stringify(queryKey)}`\n )\n }\n\n // Find matching fixture\n const match = findMatchingFixture(fixtures, queryKey as unknown[])\n\n if (!match) {\n // No fixture found, try fallback\n if (fallbackQueryFn) {\n return fallbackQueryFn({ queryKey, signal })\n }\n throw new Error(\n `[DemoKit] No fixture found for query key: ${JSON.stringify(queryKey)}`\n )\n }\n\n const [handler, { params }] = match\n\n // Apply delay if configured\n if (delay > 0) {\n await new Promise((resolve) => setTimeout(resolve, delay))\n }\n\n // Execute handler\n if (typeof handler === 'function') {\n return handler({\n queryKey: queryKey as unknown[],\n params,\n match: { matched: true, params },\n signal,\n })\n }\n\n // Return static value\n return handler\n }\n}\n\n/**\n * Create a demo-aware QueryClient\n *\n * This creates a QueryClient configured to intercept queries when demo mode\n * is enabled and return fixture data instead of making real API calls.\n *\n * @example\n * const { client, enable, disable, isEnabled } = createDemoQueryClient({\n * queries: {\n * '[\"users\"]': [{ id: '1', name: 'Demo User' }],\n * '[\"users\", \":id\"]': ({ params }) => ({ id: params.id, name: 'Demo User' }),\n * },\n * delay: 100, // Simulate 100ms latency\n * })\n *\n * // Use with QueryClientProvider\n * <QueryClientProvider client={client}>\n * <App />\n * </QueryClientProvider>\n */\nexport function createDemoQueryClient(config: DemoQueryClientConfig = {}) {\n const {\n queries = new Map(),\n delay = 0,\n staleTime = Infinity,\n fallbackQueryFn,\n queryClientConfig = {},\n prepopulateCache = false,\n } = config\n\n let enabled = config.enabled ?? false\n const fixtures = normalizeFixtureMap(queries)\n\n const isEnabled = () => enabled\n\n const demoQueryFn = createDemoQueryFn({\n fixtures,\n delay,\n fallbackQueryFn,\n isEnabled,\n })\n\n const client = new QueryClient({\n ...queryClientConfig,\n defaultOptions: {\n ...queryClientConfig.defaultOptions,\n queries: {\n ...queryClientConfig.defaultOptions?.queries,\n queryFn: demoQueryFn,\n staleTime: enabled ? staleTime : queryClientConfig.defaultOptions?.queries?.staleTime,\n retry: enabled ? false : queryClientConfig.defaultOptions?.queries?.retry,\n },\n },\n })\n\n // Pre-populate cache if configured\n const prepopulate = () => {\n if (!prepopulateCache || !enabled) return\n\n for (const [pattern, handler] of fixtures) {\n // Only pre-populate static values (not functions)\n if (typeof handler !== 'function') {\n // Use pattern as query key for static fixtures\n client.setQueryData(pattern, handler)\n }\n }\n }\n\n return {\n /**\n * The QueryClient instance\n */\n client,\n\n /**\n * Enable demo mode\n */\n enable: () => {\n enabled = true\n client.setDefaultOptions({\n ...client.getDefaultOptions(),\n queries: {\n ...client.getDefaultOptions().queries,\n staleTime,\n retry: false,\n },\n })\n prepopulate()\n },\n\n /**\n * Disable demo mode\n */\n disable: () => {\n enabled = false\n client.setDefaultOptions({\n ...client.getDefaultOptions(),\n queries: {\n ...client.getDefaultOptions().queries,\n staleTime: queryClientConfig.defaultOptions?.queries?.staleTime,\n retry: queryClientConfig.defaultOptions?.queries?.retry,\n },\n })\n },\n\n /**\n * Check if demo mode is enabled\n */\n isEnabled,\n\n /**\n * Get the fixture map\n */\n getFixtures: () => fixtures,\n\n /**\n * Add or update a fixture\n */\n setFixture: (pattern: QueryKey, handler: QueryFixtureHandler) => {\n fixtures.set(pattern, handler)\n },\n\n /**\n * Remove a fixture\n */\n removeFixture: (pattern: QueryKey) => {\n fixtures.delete(pattern)\n },\n\n /**\n * Clear all query cache\n */\n clearCache: () => {\n client.clear()\n },\n\n /**\n * Invalidate all queries\n */\n invalidateAll: () => {\n client.invalidateQueries()\n },\n }\n}\n\nexport type DemoQueryClient = ReturnType<typeof createDemoQueryClient>\n","import { matchQueryKey, findMatchingQueryKeyPattern } from '@demokit-ai/core'\nimport type { QueryKey } from '@demokit-ai/core'\nimport type { QueryKey as TanStackQueryKey } from '@tanstack/react-query'\nimport type { QueryFixtureHandler, QueryFixtureMap, QueryFixtureMapObject } from './types'\n\n/**\n * Convert TanStack Query key to DemoKit QueryKey\n * TanStack Query keys can contain any value, so we normalize them\n */\nexport function normalizeQueryKey(queryKey: TanStackQueryKey): QueryKey {\n return queryKey.map((element) => {\n if (element === null || element === undefined) {\n return element\n }\n if (typeof element === 'object') {\n // Keep objects as-is for matching\n return element as Record<string, unknown>\n }\n // Primitives are kept as-is\n return element as string | number | boolean\n })\n}\n\n/**\n * Parse a JSON string pattern into a QueryKey\n * Handles both array notation and simple string patterns\n *\n * @example\n * parsePatternString('[\"users\"]') // ['users']\n * parsePatternString('[\"users\", \":id\"]') // ['users', ':id']\n * parsePatternString('users') // ['users']\n */\nexport function parsePatternString(pattern: string): QueryKey {\n // Try to parse as JSON array\n if (pattern.startsWith('[')) {\n try {\n return JSON.parse(pattern) as QueryKey\n } catch {\n // Fall through to simple string\n }\n }\n\n // Simple string becomes single-element array\n return [pattern]\n}\n\n/**\n * Convert object-based fixture map to Map-based fixture map\n */\nexport function normalizeFixtureMap(fixtures: QueryFixtureMapObject | QueryFixtureMap): QueryFixtureMap {\n if (fixtures instanceof Map) {\n return fixtures\n }\n\n const map = new Map<QueryKey, QueryFixtureHandler>()\n for (const [pattern, handler] of Object.entries(fixtures)) {\n map.set(parsePatternString(pattern), handler)\n }\n return map\n}\n\n/**\n * Find a matching fixture for a query key\n *\n * @param fixtures - Map of query key patterns to handlers\n * @param queryKey - The query key to match\n * @returns Tuple of [handler, match result] or null if no match\n */\nexport function findMatchingFixture(\n fixtures: QueryFixtureMap,\n queryKey: TanStackQueryKey\n): [QueryFixtureHandler, { params: Record<string, unknown> }] | null {\n const normalizedKey = normalizeQueryKey(queryKey)\n const result = findMatchingQueryKeyPattern(fixtures, normalizedKey)\n\n if (result) {\n const [, handler, matchResult] = result\n return [handler, { params: matchResult.params }]\n }\n\n return null\n}\n\n/**\n * Re-export the matchQueryKey function for direct use\n */\nexport { matchQueryKey }\n","'use client'\n\nimport { useContext } from 'react'\nimport { DemoQueryContext } from './context'\nimport type { DemoQueryState } from './types'\n\n/**\n * Hook to access DemoQuery state and controls\n *\n * @returns DemoQuery context value\n * @throws Error if used outside of DemoQueryProvider\n *\n * @example\n * function MyComponent() {\n * const { isDemoMode, setQueryFixture, invalidateAll } = useDemoQuery()\n *\n * // Dynamically add a fixture\n * const handleAddFixture = () => {\n * setQueryFixture(['users', 'custom'], { id: 'custom', name: 'Custom User' })\n * invalidateAll() // Trigger refetch\n * }\n *\n * return (\n * <button onClick={handleAddFixture}>Add Custom Fixture</button>\n * )\n * }\n */\nexport function useDemoQuery(): DemoQueryState {\n const context = useContext(DemoQueryContext)\n\n if (context === undefined) {\n throw new Error(\n 'useDemoQuery must be used within a DemoQueryProvider. ' +\n 'Make sure to wrap your app with <DemoQueryProvider>.'\n )\n }\n\n return context\n}\n\n/**\n * Hook to check if demo mode is enabled\n * Shorthand for useDemoQuery().isDemoMode\n *\n * @example\n * function MyComponent() {\n * const isDemoMode = useIsDemoQueryMode()\n *\n * return isDemoMode ? <DemoBadge /> : null\n * }\n */\nexport function useIsDemoQueryMode(): boolean {\n return useDemoQuery().isDemoMode\n}\n","'use client'\n\nimport { useMutation, useQueryClient, type UseMutationOptions, type UseMutationResult } from '@tanstack/react-query'\nimport { useCallback } from 'react'\nimport type { MutationFixtureContext, MutationFixtureHandler } from './types'\nimport { useDemoQuery } from './hooks'\n\n/**\n * Options for useDemoMutation hook\n */\nexport interface UseDemoMutationOptions<TData, TError, TVariables, TContext>\n extends Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn'> {\n /**\n * The real mutation function to use when demo mode is disabled\n */\n mutationFn: (variables: TVariables) => Promise<TData>\n\n /**\n * Name used to look up the demo fixture\n * If not provided, uses mutationKey as string\n */\n demoName?: string\n\n /**\n * Demo fixture handler for this mutation\n * If provided, overrides the fixture from DemoQueryProvider\n */\n demoFixture?: MutationFixtureHandler<TData, TVariables>\n\n /**\n * Delay in ms before returning demo data\n * @default 0\n */\n demoDelay?: number\n}\n\n/**\n * A mutation hook that automatically uses demo fixtures when demo mode is enabled\n *\n * @example\n * const createUser = useDemoMutation({\n * mutationFn: async (data) => api.createUser(data),\n * demoName: 'createUser',\n * demoFixture: ({ variables, queryClient }) => {\n * // Create demo user\n * const newUser = { id: crypto.randomUUID(), ...variables }\n *\n * // Update the users query cache\n * queryClient.setQueryData(['users'], (old: User[] = []) => [...old, newUser])\n *\n * return newUser\n * },\n * onSuccess: (data) => {\n * console.log('Created user:', data)\n * },\n * })\n *\n * // Use like normal useMutation\n * createUser.mutate({ name: 'New User', email: 'user@example.com' })\n */\nexport function useDemoMutation<\n TData = unknown,\n TError = unknown,\n TVariables = void,\n TContext = unknown,\n>(\n options: UseDemoMutationOptions<TData, TError, TVariables, TContext>\n): UseMutationResult<TData, TError, TVariables, TContext> {\n const { mutationFn, demoName, demoFixture, demoDelay = 0, ...mutationOptions } = options\n\n const queryClient = useQueryClient()\n\n // Try to get demo state - may not be in DemoQueryProvider context\n let isDemoMode = false\n try {\n const demoState = useDemoQuery()\n isDemoMode = demoState.isDemoMode\n } catch {\n // Not in DemoQueryProvider context, use real mutation\n }\n\n // Create the demo-aware mutation function\n const demoAwareMutationFn = useCallback(\n async (variables: TVariables): Promise<TData> => {\n // If not in demo mode, use real mutation\n if (!isDemoMode) {\n return mutationFn(variables)\n }\n\n // Apply delay if configured\n if (demoDelay > 0) {\n await new Promise((resolve) => setTimeout(resolve, demoDelay))\n }\n\n // If a demo fixture is provided, use it\n if (demoFixture !== undefined) {\n const context: MutationFixtureContext<TVariables> = {\n mutationKey: mutationOptions.mutationKey,\n variables,\n queryClient,\n }\n\n if (typeof demoFixture === 'function') {\n // Cast to the function type to help TypeScript understand\n const fixtureFn = demoFixture as (context: MutationFixtureContext<TVariables>) => TData | Promise<TData>\n return fixtureFn(context)\n }\n return demoFixture as TData\n }\n\n // No fixture found, fall back to real mutation\n console.warn(\n `[DemoKit] No mutation fixture found for \"${demoName || mutationOptions.mutationKey?.join('/') || 'unknown'}\". ` +\n 'Using real mutation function.'\n )\n return mutationFn(variables)\n },\n [isDemoMode, mutationFn, demoFixture, demoDelay, demoName, mutationOptions.mutationKey, queryClient]\n )\n\n return useMutation({\n ...mutationOptions,\n mutationFn: demoAwareMutationFn,\n })\n}\n\n/**\n * Create a set of demo mutations with fixtures\n *\n * @example\n * const mutations = createDemoMutations({\n * createUser: {\n * mutationFn: api.createUser,\n * fixture: ({ variables, queryClient }) => {\n * const newUser = { id: 'demo-1', ...variables }\n * queryClient.setQueryData(['users'], (old = []) => [...old, newUser])\n * return newUser\n * },\n * },\n * deleteUser: {\n * mutationFn: api.deleteUser,\n * fixture: ({ variables, queryClient }) => {\n * queryClient.setQueryData(['users'], (old: User[] = []) =>\n * old.filter(u => u.id !== variables.id)\n * )\n * return { success: true }\n * },\n * },\n * })\n *\n * // Use in components\n * const { createUser, deleteUser } = mutations\n */\nexport type DemoMutationConfig<TData, TVariables> = {\n mutationFn: (variables: TVariables) => Promise<TData>\n fixture: MutationFixtureHandler<TData, TVariables>\n delay?: number\n}\n\n/**\n * Helper to create mutation options with demo fixture\n */\nexport function createMutationOptions<TData, TVariables>(\n config: DemoMutationConfig<TData, TVariables>\n): Pick<UseDemoMutationOptions<TData, unknown, TVariables, unknown>, 'mutationFn' | 'demoFixture' | 'demoDelay'> {\n return {\n mutationFn: config.mutationFn,\n demoFixture: config.fixture,\n demoDelay: config.delay,\n }\n}\n"],"mappings":"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","names":["useQueryClient","useQueryClient"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@demokit-ai/tanstack-query",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "TanStack Query
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "TanStack Query integration for DemoKit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -21,44 +21,29 @@
|
|
|
21
21
|
"files": [
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
|
-
"scripts": {
|
|
25
|
-
"build": "tsup",
|
|
26
|
-
"dev": "tsup --watch",
|
|
27
|
-
"test": "vitest",
|
|
28
|
-
"typecheck": "tsc --noEmit"
|
|
29
|
-
},
|
|
30
24
|
"dependencies": {
|
|
31
|
-
"@demokit-ai/
|
|
32
|
-
"@demokit-ai/
|
|
25
|
+
"@demokit-ai/react": "0.3.0",
|
|
26
|
+
"@demokit-ai/core": "0.3.0"
|
|
33
27
|
},
|
|
34
28
|
"devDependencies": {
|
|
35
|
-
"@tanstack/react-query": "^5.
|
|
29
|
+
"@tanstack/react-query": "^5.81.5",
|
|
36
30
|
"@types/react": "^19.0.0",
|
|
37
|
-
"@types/react-dom": "^19.0.0",
|
|
38
|
-
"react": "^19.0.0",
|
|
39
|
-
"react-dom": "^19.0.0",
|
|
40
31
|
"tsup": "^8.3.5",
|
|
41
|
-
"typescript": "^5.7.2"
|
|
42
|
-
"vitest": "^2.1.8"
|
|
32
|
+
"typescript": "^5.7.2"
|
|
43
33
|
},
|
|
44
34
|
"peerDependencies": {
|
|
45
35
|
"@tanstack/react-query": ">=5.0.0",
|
|
46
|
-
"react": ">=17.0.0"
|
|
47
|
-
"react-dom": ">=17.0.0"
|
|
36
|
+
"react": ">=17.0.0"
|
|
48
37
|
},
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"mock",
|
|
52
|
-
"tanstack-query",
|
|
53
|
-
"react-query",
|
|
54
|
-
"fixtures",
|
|
55
|
-
"testing"
|
|
56
|
-
],
|
|
57
|
-
"license": "MIT",
|
|
58
|
-
"repository": {
|
|
59
|
-
"type": "git",
|
|
60
|
-
"url": "https://github.com/your-org/demokit",
|
|
61
|
-
"directory": "packages/tanstack-query"
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
62
40
|
},
|
|
63
|
-
"
|
|
64
|
-
|
|
41
|
+
"license": "Apache-2.0",
|
|
42
|
+
"sideEffects": false,
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsup",
|
|
45
|
+
"dev": "tsup --watch --no-dts",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"clean": "rm -rf dist"
|
|
48
|
+
}
|
|
49
|
+
}
|
package/README.md
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
# @demokit-ai/tanstack-query
|
|
2
|
-
|
|
3
|
-

|
|
4
|
-

|
|
5
|
-
|
|
6
|
-
TanStack Query v5 adapter for DemoKit - mock queries and mutations for demo mode.
|
|
7
|
-
|
|
8
|
-
## Installation
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npm install @demokit-ai/tanstack-query @demokit-ai/core @demokit-ai/react @tanstack/react-query
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Features
|
|
15
|
-
|
|
16
|
-
- **Demo Query Client** - Intercept queries and return fixtures
|
|
17
|
-
- **Mutation Mocking** - Mock mutation operations in demo mode
|
|
18
|
-
- **Key Matching** - Pattern-based query key matching
|
|
19
|
-
- **Provider Pattern** - Centralized fixture management
|
|
20
|
-
- **Optimistic Updates** - Demo-aware optimistic update handling
|
|
21
|
-
- Full TypeScript support
|
|
22
|
-
|
|
23
|
-
## Usage
|
|
24
|
-
|
|
25
|
-
### Demo Query Client
|
|
26
|
-
|
|
27
|
-
```tsx
|
|
28
|
-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
29
|
-
import { createDemoQueryClient } from '@demokit-ai/tanstack-query'
|
|
30
|
-
|
|
31
|
-
const queryClient = createDemoQueryClient({
|
|
32
|
-
isEnabled: () => localStorage.getItem('demoMode') === 'true',
|
|
33
|
-
fixtures: {
|
|
34
|
-
users: [
|
|
35
|
-
{ id: '1', name: 'Demo User' },
|
|
36
|
-
{ id: '2', name: 'Another User' },
|
|
37
|
-
],
|
|
38
|
-
'users/:id': ({ params }) => ({
|
|
39
|
-
id: params.id,
|
|
40
|
-
name: 'Demo User',
|
|
41
|
-
email: 'demo@example.com',
|
|
42
|
-
}),
|
|
43
|
-
},
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
function App() {
|
|
47
|
-
return (
|
|
48
|
-
<QueryClientProvider client={queryClient}>
|
|
49
|
-
<YourApp />
|
|
50
|
-
</QueryClientProvider>
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Using with useQuery
|
|
56
|
-
|
|
57
|
-
```tsx
|
|
58
|
-
import { useQuery } from '@tanstack/react-query'
|
|
59
|
-
|
|
60
|
-
function UserList() {
|
|
61
|
-
const { data, isLoading } = useQuery({
|
|
62
|
-
queryKey: ['users'],
|
|
63
|
-
queryFn: () => fetch('/api/users').then((r) => r.json()),
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
// In demo mode, returns fixtures automatically
|
|
67
|
-
if (isLoading) return <div>Loading...</div>
|
|
68
|
-
return <ul>{data?.map((u) => <li key={u.id}>{u.name}</li>)}</ul>
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Provider Pattern
|
|
73
|
-
|
|
74
|
-
```tsx
|
|
75
|
-
import { DemoQueryProvider, useDemoQuery } from '@demokit-ai/tanstack-query'
|
|
76
|
-
|
|
77
|
-
const fixtures = {
|
|
78
|
-
users: [{ id: '1', name: 'Demo User' }],
|
|
79
|
-
products: [{ id: '1', name: 'Demo Product', price: 99.99 }],
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function App() {
|
|
83
|
-
return (
|
|
84
|
-
<DemoQueryProvider fixtures={fixtures} enabled>
|
|
85
|
-
<YourApp />
|
|
86
|
-
<DemoControls />
|
|
87
|
-
</DemoQueryProvider>
|
|
88
|
-
)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function DemoControls() {
|
|
92
|
-
const { enabled, toggle, setFixture } = useDemoQuery()
|
|
93
|
-
|
|
94
|
-
return (
|
|
95
|
-
<div>
|
|
96
|
-
<button onClick={toggle}>Demo: {enabled ? 'ON' : 'OFF'}</button>
|
|
97
|
-
<button onClick={() => setFixture('custom', { custom: true })}>
|
|
98
|
-
Add Custom Fixture
|
|
99
|
-
</button>
|
|
100
|
-
</div>
|
|
101
|
-
)
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Mutation Mocking
|
|
106
|
-
|
|
107
|
-
```tsx
|
|
108
|
-
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
109
|
-
import { createDemoMutation } from '@demokit-ai/tanstack-query'
|
|
110
|
-
|
|
111
|
-
function CreateUser() {
|
|
112
|
-
const queryClient = useQueryClient()
|
|
113
|
-
|
|
114
|
-
const mutation = useMutation({
|
|
115
|
-
mutationFn: createDemoMutation({
|
|
116
|
-
mutationFn: (data) =>
|
|
117
|
-
fetch('/api/users', {
|
|
118
|
-
method: 'POST',
|
|
119
|
-
body: JSON.stringify(data),
|
|
120
|
-
}).then((r) => r.json()),
|
|
121
|
-
isEnabled: () => true,
|
|
122
|
-
fixture: (variables) => ({
|
|
123
|
-
id: 'new-id',
|
|
124
|
-
...variables,
|
|
125
|
-
created: true,
|
|
126
|
-
}),
|
|
127
|
-
}),
|
|
128
|
-
onSuccess: () => {
|
|
129
|
-
queryClient.invalidateQueries({ queryKey: ['users'] })
|
|
130
|
-
},
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
return (
|
|
134
|
-
<button
|
|
135
|
-
onClick={() => mutation.mutate({ name: 'New User' })}
|
|
136
|
-
disabled={mutation.isPending}
|
|
137
|
-
>
|
|
138
|
-
Create User
|
|
139
|
-
</button>
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Dynamic Fixtures
|
|
145
|
-
|
|
146
|
-
```tsx
|
|
147
|
-
const fixtures = {
|
|
148
|
-
// Static fixture
|
|
149
|
-
config: { version: '1.0', features: ['demo'] },
|
|
150
|
-
|
|
151
|
-
// Dynamic fixture based on query key
|
|
152
|
-
'users/:id': ({ params }) => ({
|
|
153
|
-
id: params.id,
|
|
154
|
-
name: `User ${params.id}`,
|
|
155
|
-
email: `user${params.id}@example.com`,
|
|
156
|
-
}),
|
|
157
|
-
|
|
158
|
-
// Function fixture with full context
|
|
159
|
-
search: ({ queryKey }) => {
|
|
160
|
-
const [, { query }] = queryKey
|
|
161
|
-
return [
|
|
162
|
-
{ id: '1', title: `Result for: ${query}` },
|
|
163
|
-
]
|
|
164
|
-
},
|
|
165
|
-
}
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### Query Key Matching
|
|
169
|
-
|
|
170
|
-
```tsx
|
|
171
|
-
const fixtures = {
|
|
172
|
-
// Exact match
|
|
173
|
-
users: [...],
|
|
174
|
-
|
|
175
|
-
// Parameter matching
|
|
176
|
-
'users/:id': ({ params }) => ({ id: params.id }),
|
|
177
|
-
|
|
178
|
-
// Nested keys (arrays)
|
|
179
|
-
'users/:id/orders': ({ params }) => [
|
|
180
|
-
{ id: '1', userId: params.id, total: 99.99 },
|
|
181
|
-
],
|
|
182
|
-
|
|
183
|
-
// Wildcard matching
|
|
184
|
-
'users/*': ({ queryKey }) => ({
|
|
185
|
-
path: queryKey.join('/'),
|
|
186
|
-
}),
|
|
187
|
-
}
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
## API Reference
|
|
191
|
-
|
|
192
|
-
### `createDemoQueryClient(options)`
|
|
193
|
-
|
|
194
|
-
Create a demo-aware QueryClient.
|
|
195
|
-
|
|
196
|
-
Options:
|
|
197
|
-
- `isEnabled` - Function to check if demo mode is enabled
|
|
198
|
-
- `fixtures` - Fixture definitions by query key pattern
|
|
199
|
-
- `delay` - Simulated delay in milliseconds
|
|
200
|
-
- `defaultOptions` - Default QueryClient options
|
|
201
|
-
|
|
202
|
-
### `DemoQueryProvider`
|
|
203
|
-
|
|
204
|
-
Props:
|
|
205
|
-
- `fixtures` - Fixture definitions
|
|
206
|
-
- `enabled` - Whether demo mode is enabled
|
|
207
|
-
- `delay` - Simulated delay in milliseconds
|
|
208
|
-
- `children` - React children
|
|
209
|
-
|
|
210
|
-
### `useDemoQuery()`
|
|
211
|
-
|
|
212
|
-
Returns:
|
|
213
|
-
- `enabled` - Whether demo mode is enabled
|
|
214
|
-
- `toggle()` - Toggle demo mode
|
|
215
|
-
- `fixtures` - Current fixtures
|
|
216
|
-
- `setFixture(key, fixture)` - Set a fixture
|
|
217
|
-
- `removeFixture(key)` - Remove a fixture
|
|
218
|
-
- `clearFixtures()` - Clear all fixtures
|
|
219
|
-
|
|
220
|
-
### `createDemoMutation(options)`
|
|
221
|
-
|
|
222
|
-
Create a demo-aware mutation function.
|
|
223
|
-
|
|
224
|
-
Options:
|
|
225
|
-
- `mutationFn` - The real mutation function
|
|
226
|
-
- `isEnabled` - Function to check if demo mode is enabled
|
|
227
|
-
- `fixture` - Mutation fixture (static or function)
|
|
228
|
-
- `delay` - Simulated delay in milliseconds
|
|
229
|
-
|
|
230
|
-
### `createQueryKeyMatcher(fixtures)`
|
|
231
|
-
|
|
232
|
-
Create a matcher function for query keys.
|
|
233
|
-
|
|
234
|
-
Returns a function that takes a query key and returns the matching fixture.
|
|
235
|
-
|
|
236
|
-
## License
|
|
237
|
-
|
|
238
|
-
MIT
|