@demokit-ai/tanstack-query 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,333 @@
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
+ // src/provider.tsx
8
+ var DemoQueryContext = createContext(void 0);
9
+ DemoQueryContext.displayName = "DemoQueryContext";
10
+ function normalizeQueryKey(queryKey) {
11
+ return queryKey.map((element) => {
12
+ if (element === null || element === void 0) {
13
+ return element;
14
+ }
15
+ if (typeof element === "object") {
16
+ return element;
17
+ }
18
+ return element;
19
+ });
20
+ }
21
+ function parsePatternString(pattern) {
22
+ if (pattern.startsWith("[")) {
23
+ try {
24
+ return JSON.parse(pattern);
25
+ } catch {
26
+ }
27
+ }
28
+ return [pattern];
29
+ }
30
+ function normalizeFixtureMap(fixtures) {
31
+ if (fixtures instanceof Map) {
32
+ return fixtures;
33
+ }
34
+ const map = /* @__PURE__ */ new Map();
35
+ for (const [pattern, handler] of Object.entries(fixtures)) {
36
+ map.set(parsePatternString(pattern), handler);
37
+ }
38
+ return map;
39
+ }
40
+ function findMatchingFixture(fixtures, queryKey) {
41
+ const normalizedKey = normalizeQueryKey(queryKey);
42
+ const result = findMatchingQueryKeyPattern(fixtures, normalizedKey);
43
+ if (result) {
44
+ const [, handler, matchResult] = result;
45
+ return [handler, { params: matchResult.params }];
46
+ }
47
+ return null;
48
+ }
49
+
50
+ // src/client.ts
51
+ function createDemoQueryFn(config) {
52
+ const { fixtures, delay = 0, fallbackQueryFn, isEnabled } = config;
53
+ return async function demoQueryFn({
54
+ queryKey,
55
+ signal
56
+ }) {
57
+ if (!isEnabled()) {
58
+ if (fallbackQueryFn) {
59
+ return fallbackQueryFn({ queryKey, signal });
60
+ }
61
+ throw new Error(
62
+ `[DemoKit] No fallback query function provided and demo mode is disabled. Query key: ${JSON.stringify(queryKey)}`
63
+ );
64
+ }
65
+ const match = findMatchingFixture(fixtures, queryKey);
66
+ if (!match) {
67
+ if (fallbackQueryFn) {
68
+ return fallbackQueryFn({ queryKey, signal });
69
+ }
70
+ throw new Error(
71
+ `[DemoKit] No fixture found for query key: ${JSON.stringify(queryKey)}`
72
+ );
73
+ }
74
+ const [handler, { params }] = match;
75
+ if (delay > 0) {
76
+ await new Promise((resolve) => setTimeout(resolve, delay));
77
+ }
78
+ if (typeof handler === "function") {
79
+ return handler({
80
+ queryKey,
81
+ params,
82
+ match: { matched: true, params },
83
+ signal
84
+ });
85
+ }
86
+ return handler;
87
+ };
88
+ }
89
+ function createDemoQueryClient(config = {}) {
90
+ const {
91
+ queries = /* @__PURE__ */ new Map(),
92
+ delay = 0,
93
+ staleTime = Infinity,
94
+ fallbackQueryFn,
95
+ queryClientConfig = {},
96
+ prepopulateCache = false
97
+ } = config;
98
+ let enabled = config.enabled ?? false;
99
+ const fixtures = normalizeFixtureMap(queries);
100
+ const isEnabled = () => enabled;
101
+ const demoQueryFn = createDemoQueryFn({
102
+ fixtures,
103
+ delay,
104
+ fallbackQueryFn,
105
+ isEnabled
106
+ });
107
+ const client = new QueryClient({
108
+ ...queryClientConfig,
109
+ defaultOptions: {
110
+ ...queryClientConfig.defaultOptions,
111
+ queries: {
112
+ ...queryClientConfig.defaultOptions?.queries,
113
+ queryFn: demoQueryFn,
114
+ staleTime: enabled ? staleTime : queryClientConfig.defaultOptions?.queries?.staleTime,
115
+ retry: enabled ? false : queryClientConfig.defaultOptions?.queries?.retry
116
+ }
117
+ }
118
+ });
119
+ const prepopulate = () => {
120
+ if (!prepopulateCache || !enabled) return;
121
+ for (const [pattern, handler] of fixtures) {
122
+ if (typeof handler !== "function") {
123
+ client.setQueryData(pattern, handler);
124
+ }
125
+ }
126
+ };
127
+ return {
128
+ /**
129
+ * The QueryClient instance
130
+ */
131
+ client,
132
+ /**
133
+ * Enable demo mode
134
+ */
135
+ enable: () => {
136
+ enabled = true;
137
+ client.setDefaultOptions({
138
+ ...client.getDefaultOptions(),
139
+ queries: {
140
+ ...client.getDefaultOptions().queries,
141
+ staleTime,
142
+ retry: false
143
+ }
144
+ });
145
+ prepopulate();
146
+ },
147
+ /**
148
+ * Disable demo mode
149
+ */
150
+ disable: () => {
151
+ enabled = false;
152
+ client.setDefaultOptions({
153
+ ...client.getDefaultOptions(),
154
+ queries: {
155
+ ...client.getDefaultOptions().queries,
156
+ staleTime: queryClientConfig.defaultOptions?.queries?.staleTime,
157
+ retry: queryClientConfig.defaultOptions?.queries?.retry
158
+ }
159
+ });
160
+ },
161
+ /**
162
+ * Check if demo mode is enabled
163
+ */
164
+ isEnabled,
165
+ /**
166
+ * Get the fixture map
167
+ */
168
+ getFixtures: () => fixtures,
169
+ /**
170
+ * Add or update a fixture
171
+ */
172
+ setFixture: (pattern, handler) => {
173
+ fixtures.set(pattern, handler);
174
+ },
175
+ /**
176
+ * Remove a fixture
177
+ */
178
+ removeFixture: (pattern) => {
179
+ fixtures.delete(pattern);
180
+ },
181
+ /**
182
+ * Clear all query cache
183
+ */
184
+ clearCache: () => {
185
+ client.clear();
186
+ },
187
+ /**
188
+ * Invalidate all queries
189
+ */
190
+ invalidateAll: () => {
191
+ client.invalidateQueries();
192
+ }
193
+ };
194
+ }
195
+ function DemoQueryProviderInner({
196
+ children,
197
+ queries = /* @__PURE__ */ new Map(),
198
+ mutations = /* @__PURE__ */ new Map(),
199
+ enabled: enabledProp,
200
+ delay = 0,
201
+ staleTime = Infinity
202
+ }) {
203
+ const queryClient = useQueryClient();
204
+ const fixturesRef = useRef(normalizeFixtureMap(queries));
205
+ const mutationFixturesRef = useRef(
206
+ mutations instanceof Map ? mutations : new Map(Object.entries(mutations))
207
+ );
208
+ const isDemoMode = enabledProp ?? false;
209
+ const demoQueryFn = useMemo(
210
+ () => createDemoQueryFn({
211
+ fixtures: fixturesRef.current,
212
+ delay,
213
+ isEnabled: () => isDemoMode
214
+ }),
215
+ [delay, isDemoMode]
216
+ );
217
+ useEffect(() => {
218
+ if (isDemoMode) {
219
+ queryClient.setDefaultOptions({
220
+ ...queryClient.getDefaultOptions(),
221
+ queries: {
222
+ ...queryClient.getDefaultOptions().queries,
223
+ queryFn: demoQueryFn,
224
+ staleTime,
225
+ retry: false
226
+ }
227
+ });
228
+ }
229
+ }, [isDemoMode, demoQueryFn, queryClient, staleTime]);
230
+ const contextValue = useMemo(
231
+ () => ({
232
+ isDemoMode,
233
+ setQueryFixture: (pattern, handler) => {
234
+ fixturesRef.current.set(pattern, handler);
235
+ },
236
+ removeQueryFixture: (pattern) => {
237
+ fixturesRef.current.delete(pattern);
238
+ },
239
+ setMutationFixture: (name, handler) => {
240
+ mutationFixturesRef.current.set(name, handler);
241
+ },
242
+ removeMutationFixture: (name) => {
243
+ mutationFixturesRef.current.delete(name);
244
+ },
245
+ invalidateAll: () => {
246
+ queryClient.invalidateQueries();
247
+ },
248
+ resetCache: () => {
249
+ queryClient.clear();
250
+ }
251
+ }),
252
+ [isDemoMode, queryClient]
253
+ );
254
+ return /* @__PURE__ */ jsx(DemoQueryContext.Provider, { value: contextValue, children });
255
+ }
256
+ function DemoQueryProvider({
257
+ children,
258
+ client,
259
+ ...config
260
+ }) {
261
+ const { client: demoClient } = useMemo(() => {
262
+ if (client) {
263
+ return { client };
264
+ }
265
+ return createDemoQueryClient(config);
266
+ }, [client, config.enabled]);
267
+ const queryClient = client ?? demoClient;
268
+ return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(DemoQueryProviderInner, { ...config, children }) });
269
+ }
270
+ function useDemoQuery() {
271
+ const context = useContext(DemoQueryContext);
272
+ if (context === void 0) {
273
+ throw new Error(
274
+ "useDemoQuery must be used within a DemoQueryProvider. Make sure to wrap your app with <DemoQueryProvider>."
275
+ );
276
+ }
277
+ return context;
278
+ }
279
+ function useIsDemoQueryMode() {
280
+ return useDemoQuery().isDemoMode;
281
+ }
282
+ function useDemoMutation(options) {
283
+ const { mutationFn, demoName, demoFixture, demoDelay = 0, ...mutationOptions } = options;
284
+ const queryClient = useQueryClient();
285
+ let isDemoMode = false;
286
+ try {
287
+ const demoState = useDemoQuery();
288
+ isDemoMode = demoState.isDemoMode;
289
+ } catch {
290
+ }
291
+ const demoAwareMutationFn = useCallback(
292
+ async (variables) => {
293
+ if (!isDemoMode) {
294
+ return mutationFn(variables);
295
+ }
296
+ if (demoDelay > 0) {
297
+ await new Promise((resolve) => setTimeout(resolve, demoDelay));
298
+ }
299
+ if (demoFixture !== void 0) {
300
+ const context = {
301
+ mutationKey: mutationOptions.mutationKey,
302
+ variables,
303
+ queryClient
304
+ };
305
+ if (typeof demoFixture === "function") {
306
+ const fixtureFn = demoFixture;
307
+ return fixtureFn(context);
308
+ }
309
+ return demoFixture;
310
+ }
311
+ console.warn(
312
+ `[DemoKit] No mutation fixture found for "${demoName || mutationOptions.mutationKey?.join("/") || "unknown"}". Using real mutation function.`
313
+ );
314
+ return mutationFn(variables);
315
+ },
316
+ [isDemoMode, mutationFn, demoFixture, demoDelay, demoName, mutationOptions.mutationKey, queryClient]
317
+ );
318
+ return useMutation({
319
+ ...mutationOptions,
320
+ mutationFn: demoAwareMutationFn
321
+ });
322
+ }
323
+ function createMutationOptions(config) {
324
+ return {
325
+ mutationFn: config.mutationFn,
326
+ demoFixture: config.fixture,
327
+ demoDelay: config.delay
328
+ };
329
+ }
330
+
331
+ export { DemoQueryProvider, createDemoQueryClient, createDemoQueryFn, createMutationOptions, findMatchingFixture, normalizeFixtureMap, normalizeQueryKey, parsePatternString, useDemoMutation, useDemoQuery, useIsDemoQueryMode };
332
+ //# sourceMappingURL=index.js.map
333
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"]}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@demokit-ai/tanstack-query",
3
+ "version": "0.0.1",
4
+ "description": "TanStack Query v5 adapter for DemoKit - mock queries and mutations",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "dev": "tsup --watch",
27
+ "test": "vitest",
28
+ "typecheck": "tsc --noEmit"
29
+ },
30
+ "dependencies": {
31
+ "@demokit-ai/core": "*",
32
+ "@demokit-ai/react": "*"
33
+ },
34
+ "devDependencies": {
35
+ "@tanstack/react-query": "^5.62.3",
36
+ "@types/react": "^19.0.0",
37
+ "@types/react-dom": "^19.0.0",
38
+ "react": "^19.0.0",
39
+ "react-dom": "^19.0.0",
40
+ "tsup": "^8.3.5",
41
+ "typescript": "^5.7.2",
42
+ "vitest": "^2.1.8"
43
+ },
44
+ "peerDependencies": {
45
+ "@tanstack/react-query": ">=5.0.0",
46
+ "react": ">=17.0.0",
47
+ "react-dom": ">=17.0.0"
48
+ },
49
+ "keywords": [
50
+ "demo",
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"
62
+ },
63
+ "sideEffects": false
64
+ }