@classytic/arc-next 0.1.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 +21 -0
- package/README.md +185 -0
- package/dist/api.d.ts +225 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +167 -0
- package/dist/api.js.map +1 -0
- package/dist/client.d.ts +172 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +242 -0
- package/dist/client.js.map +1 -0
- package/dist/hooks.d.ts +143 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +357 -0
- package/dist/hooks.js.map +1 -0
- package/dist/mutation.d.ts +118 -0
- package/dist/mutation.d.ts.map +1 -0
- package/dist/mutation.js +160 -0
- package/dist/mutation.js.map +1 -0
- package/dist/prefetch.d.ts +64 -0
- package/dist/prefetch.d.ts.map +1 -0
- package/dist/prefetch.js +76 -0
- package/dist/prefetch.js.map +1 -0
- package/dist/query-client.d.ts +25 -0
- package/dist/query-client.d.ts.map +1 -0
- package/dist/query-client.js +46 -0
- package/dist/query-client.js.map +1 -0
- package/dist/query.d.ts +177 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +203 -0
- package/dist/query.js.map +1 -0
- package/package.json +91 -0
package/dist/mutation.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { isArcApiError } from "./client.js";
|
|
4
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
5
|
+
import { useTransition } from "react";
|
|
6
|
+
|
|
7
|
+
//#region src/mutation.ts
|
|
8
|
+
let toastHandler = {
|
|
9
|
+
success: (msg) => console.log("[Success]", msg),
|
|
10
|
+
error: (msg) => console.error("[Error]", msg)
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Configure toast handler. Call once at app init.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* import { toast } from "sonner";
|
|
17
|
+
* configureToast({ success: toast.success, error: toast.error });
|
|
18
|
+
*/
|
|
19
|
+
function configureToast(handler) {
|
|
20
|
+
toastHandler = handler;
|
|
21
|
+
}
|
|
22
|
+
function showToast(type, messages, data, variables, error, handler) {
|
|
23
|
+
const activeHandler = handler ?? toastHandler;
|
|
24
|
+
if (type === "success") {
|
|
25
|
+
const msg = messages?.success;
|
|
26
|
+
if (!msg) return;
|
|
27
|
+
const text = typeof msg === "function" ? msg(data, variables) : msg;
|
|
28
|
+
activeHandler.success(text);
|
|
29
|
+
} else {
|
|
30
|
+
const msg = messages?.error;
|
|
31
|
+
let defaultMsg = error?.message || "An error occurred";
|
|
32
|
+
if (isArcApiError(error) && error.fieldErrors) {
|
|
33
|
+
const fields = Object.entries(error.fieldErrors);
|
|
34
|
+
if (fields.length > 0) defaultMsg = fields.map(([k, v]) => `${k}: ${v}`).join(", ");
|
|
35
|
+
}
|
|
36
|
+
const text = typeof msg === "function" ? msg(error, variables) : msg || defaultMsg;
|
|
37
|
+
activeHandler.error(text);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function useMutationWithTransition(config) {
|
|
41
|
+
const { mutationFn, invalidateQueries = [], onSuccess, onError, onSettled, messages, useTransition: withTransition = true, showToast: toast = true, toastHandler: instanceToast } = config;
|
|
42
|
+
const queryClient = useQueryClient();
|
|
43
|
+
const [isTransitioning, startTransition] = useTransition();
|
|
44
|
+
const mutation = useMutation({
|
|
45
|
+
mutationFn,
|
|
46
|
+
onSuccess: (data, variables) => {
|
|
47
|
+
const invalidate = () => {
|
|
48
|
+
invalidateQueries.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));
|
|
49
|
+
};
|
|
50
|
+
if (withTransition && invalidateQueries.length > 0) startTransition(invalidate);
|
|
51
|
+
else invalidate();
|
|
52
|
+
if (toast) showToast("success", messages, data, variables, void 0, instanceToast);
|
|
53
|
+
onSuccess?.(data, variables);
|
|
54
|
+
},
|
|
55
|
+
onError: (error, variables) => {
|
|
56
|
+
if (toast) showToast("error", messages, null, variables, error, instanceToast);
|
|
57
|
+
onError?.(error, variables);
|
|
58
|
+
},
|
|
59
|
+
onSettled: (data, error, variables) => {
|
|
60
|
+
onSettled?.(data, error, variables);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return {
|
|
64
|
+
mutate: mutation.mutate,
|
|
65
|
+
mutateAsync: mutation.mutateAsync,
|
|
66
|
+
isPending: mutation.isPending || isTransitioning,
|
|
67
|
+
isSuccess: mutation.isSuccess,
|
|
68
|
+
isError: mutation.isError,
|
|
69
|
+
error: mutation.error,
|
|
70
|
+
data: mutation.data,
|
|
71
|
+
reset: mutation.reset
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function useMutationWithOptimistic(config) {
|
|
75
|
+
const { mutationFn, queryKeys = [], optimisticUpdate, onSuccess, onError, onSettled, messages, showToast: toast = true, toastHandler: instanceToast } = config;
|
|
76
|
+
const queryClient = useQueryClient();
|
|
77
|
+
const mutation = useMutation({
|
|
78
|
+
mutationFn,
|
|
79
|
+
onMutate: async (variables) => {
|
|
80
|
+
await Promise.all(queryKeys.map((key) => queryClient.cancelQueries({ queryKey: key })));
|
|
81
|
+
const previous = queryKeys.map((key) => ({
|
|
82
|
+
key,
|
|
83
|
+
data: queryClient.getQueryData(key)
|
|
84
|
+
}));
|
|
85
|
+
if (optimisticUpdate) queryKeys.forEach((key) => {
|
|
86
|
+
queryClient.setQueryData(key, (old) => optimisticUpdate(old, variables));
|
|
87
|
+
});
|
|
88
|
+
return { previous };
|
|
89
|
+
},
|
|
90
|
+
onSuccess: (data, variables) => {
|
|
91
|
+
queryKeys.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));
|
|
92
|
+
if (toast) showToast("success", messages, data, variables, void 0, instanceToast);
|
|
93
|
+
onSuccess?.(data, variables);
|
|
94
|
+
},
|
|
95
|
+
onError: (error, variables, context) => {
|
|
96
|
+
context?.previous?.forEach(({ key, data }) => queryClient.setQueryData(key, data));
|
|
97
|
+
if (toast) showToast("error", messages, null, variables, error, instanceToast);
|
|
98
|
+
onError?.(error, variables);
|
|
99
|
+
},
|
|
100
|
+
onSettled: (data, error, variables) => {
|
|
101
|
+
onSettled?.(data, error, variables);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return {
|
|
105
|
+
mutate: mutation.mutate,
|
|
106
|
+
mutateAsync: mutation.mutateAsync,
|
|
107
|
+
isPending: mutation.isPending,
|
|
108
|
+
isSuccess: mutation.isSuccess,
|
|
109
|
+
isError: mutation.isError,
|
|
110
|
+
error: mutation.error,
|
|
111
|
+
data: mutation.data,
|
|
112
|
+
reset: mutation.reset
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function createOptimisticMutation({ mutationFn, queryClient, queryKeys, optimisticUpdate, onSuccess, onError, messages, toastHandler: instanceToast }) {
|
|
116
|
+
return useMutation({
|
|
117
|
+
mutationFn,
|
|
118
|
+
onMutate: async (variables) => {
|
|
119
|
+
await Promise.all(queryKeys.map((key) => queryClient.cancelQueries({
|
|
120
|
+
queryKey: key,
|
|
121
|
+
exact: false
|
|
122
|
+
})));
|
|
123
|
+
const previous = queryKeys.map((key) => ({
|
|
124
|
+
key,
|
|
125
|
+
data: queryClient.getQueriesData({ queryKey: key })
|
|
126
|
+
}));
|
|
127
|
+
if (optimisticUpdate) queryKeys.forEach((key) => {
|
|
128
|
+
queryClient.getQueriesData({ queryKey: key }).forEach(([qKey, qData]) => {
|
|
129
|
+
queryClient.setQueryData(qKey, optimisticUpdate(qData, variables));
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
return { previous };
|
|
133
|
+
},
|
|
134
|
+
onSuccess: (data, variables) => {
|
|
135
|
+
if (messages?.success) showToast("success", messages, data, variables, void 0, instanceToast);
|
|
136
|
+
queryKeys.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));
|
|
137
|
+
onSuccess?.(data, variables);
|
|
138
|
+
},
|
|
139
|
+
onError: (error, variables, context) => {
|
|
140
|
+
context?.previous?.forEach(({ data }) => {
|
|
141
|
+
data.forEach(([qKey, qData]) => queryClient.setQueryData(qKey, qData));
|
|
142
|
+
});
|
|
143
|
+
showToast("error", messages, null, variables, error, instanceToast);
|
|
144
|
+
onError?.(error, variables);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
const QUERY_CONFIGS = {
|
|
149
|
+
realtime: {
|
|
150
|
+
staleTime: 2e4,
|
|
151
|
+
refetchInterval: 3e4
|
|
152
|
+
},
|
|
153
|
+
frequent: { staleTime: 6e4 },
|
|
154
|
+
stable: { staleTime: 3e5 },
|
|
155
|
+
static: { staleTime: 6e5 }
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
//#endregion
|
|
159
|
+
export { QUERY_CONFIGS, configureToast, createOptimisticMutation, useMutationWithOptimistic, useMutationWithTransition };
|
|
160
|
+
//# sourceMappingURL=mutation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutation.js","names":[],"sources":["../src/mutation.ts"],"sourcesContent":["\"use client\";\n\nimport { useMutation, useQueryClient, type QueryClient, type QueryKey } from \"@tanstack/react-query\";\nimport { useTransition } from \"react\";\nimport { isArcApiError } from \"./client.js\";\nimport type { ToastHandler } from \"./client.js\";\n\n// Re-export for backward compatibility\nexport type { ToastHandler } from \"./client.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface MutationMessages {\n success?: string | ((data: unknown, variables: unknown) => string);\n error?: string | ((error: Error, variables: unknown) => string);\n}\n\nexport interface MutationCallbacks<TData, TVariables, TContext = unknown> {\n onMutate?: (variables: TVariables) => TContext | Promise<TContext>;\n onSuccess?: (data: TData, variables: TVariables, context: TContext) => void | Promise<void>;\n onError?: (error: Error, variables: TVariables, context: TContext) => void | Promise<void>;\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables, context: TContext) => void | Promise<void>;\n}\n\n// ============================================================================\n// Toast Configuration\n// ============================================================================\n\nlet toastHandler: ToastHandler = {\n success: (msg) => console.log(\"[Success]\", msg),\n error: (msg) => console.error(\"[Error]\", msg),\n};\n\n/**\n * Configure toast handler. Call once at app init.\n *\n * @example\n * import { toast } from \"sonner\";\n * configureToast({ success: toast.success, error: toast.error });\n */\nexport function configureToast(handler: ToastHandler): void {\n toastHandler = handler;\n}\n\nfunction showToast(\n type: \"success\" | \"error\",\n messages: MutationMessages | undefined,\n data: unknown,\n variables: unknown,\n error?: Error,\n handler?: ToastHandler,\n) {\n const activeHandler = handler ?? toastHandler;\n\n if (type === \"success\") {\n const msg = messages?.success;\n if (!msg) return;\n\n const text = typeof msg === \"function\" ? msg(data, variables) : msg;\n activeHandler.success(text);\n } else {\n const msg = messages?.error;\n let defaultMsg = error?.message || \"An error occurred\";\n if (isArcApiError(error) && error.fieldErrors) {\n const fields = Object.entries(error.fieldErrors);\n if (fields.length > 0) {\n defaultMsg = fields.map(([k, v]) => `${k}: ${v}`).join(', ');\n }\n }\n const text = typeof msg === \"function\"\n ? msg(error as Error, variables)\n : msg || defaultMsg;\n\n activeHandler.error(text);\n }\n}\n\n// ============================================================================\n// Mutation with React 19 Transitions\n// ============================================================================\n\nexport interface TransitionMutationConfig<TData, TVariables> {\n mutationFn: (variables: TVariables) => Promise<TData>;\n invalidateQueries?: QueryKey[];\n onSuccess?: (data: TData, variables: TVariables) => void;\n onError?: (error: Error, variables: TVariables) => void;\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;\n messages?: MutationMessages;\n useTransition?: boolean;\n showToast?: boolean;\n toastHandler?: ToastHandler;\n}\n\nexport function useMutationWithTransition<TData, TVariables>(config: TransitionMutationConfig<TData, TVariables>) {\n const {\n mutationFn,\n invalidateQueries = [],\n onSuccess,\n onError,\n onSettled,\n messages,\n useTransition: withTransition = true,\n showToast: toast = true,\n toastHandler: instanceToast,\n } = config;\n\n const queryClient = useQueryClient();\n const [isTransitioning, startTransition] = useTransition();\n\n const mutation = useMutation({\n mutationFn,\n\n onSuccess: (data, variables) => {\n const invalidate = () => {\n invalidateQueries.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));\n };\n\n if (withTransition && invalidateQueries.length > 0) {\n startTransition(invalidate);\n } else {\n invalidate();\n }\n\n if (toast) showToast(\"success\", messages, data, variables, undefined, instanceToast);\n onSuccess?.(data, variables);\n },\n\n onError: (error, variables) => {\n if (toast) showToast(\"error\", messages, null, variables, error as Error, instanceToast);\n onError?.(error as Error, variables);\n },\n\n onSettled: (data, error, variables) => {\n onSettled?.(data, error as Error | null, variables);\n },\n });\n\n return {\n mutate: mutation.mutate,\n mutateAsync: mutation.mutateAsync,\n isPending: mutation.isPending || isTransitioning,\n isSuccess: mutation.isSuccess,\n isError: mutation.isError,\n error: mutation.error as Error | null,\n data: mutation.data,\n reset: mutation.reset,\n };\n}\n\n// ============================================================================\n// Mutation with Optimistic Updates\n// ============================================================================\n\nexport interface OptimisticMutationConfig<TData, TVariables> {\n mutationFn: (variables: TVariables) => Promise<TData>;\n queryKeys?: QueryKey[];\n optimisticUpdate?: (oldData: unknown, variables: TVariables) => unknown;\n onSuccess?: (data: TData, variables: TVariables) => void;\n onError?: (error: Error, variables: TVariables) => void;\n onSettled?: (data: TData | undefined, error: Error | null, variables: TVariables) => void;\n messages?: MutationMessages;\n showToast?: boolean;\n toastHandler?: ToastHandler;\n}\n\nexport function useMutationWithOptimistic<TData, TVariables>(config: OptimisticMutationConfig<TData, TVariables>) {\n const {\n mutationFn,\n queryKeys = [],\n optimisticUpdate,\n onSuccess,\n onError,\n onSettled,\n messages,\n showToast: toast = true,\n toastHandler: instanceToast,\n } = config;\n\n const queryClient = useQueryClient();\n\n const mutation = useMutation({\n mutationFn,\n\n onMutate: async (variables) => {\n await Promise.all(queryKeys.map((key) => queryClient.cancelQueries({ queryKey: key })));\n\n const previous = queryKeys.map((key) => ({\n key,\n data: queryClient.getQueryData(key),\n }));\n\n if (optimisticUpdate) {\n queryKeys.forEach((key) => {\n queryClient.setQueryData(key, (old: unknown) => optimisticUpdate(old, variables));\n });\n }\n\n return { previous };\n },\n\n onSuccess: (data, variables) => {\n queryKeys.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));\n if (toast) showToast(\"success\", messages, data, variables, undefined, instanceToast);\n onSuccess?.(data, variables);\n },\n\n onError: (error, variables, context) => {\n const ctx = context as { previous?: Array<{ key: QueryKey; data: unknown }> };\n ctx?.previous?.forEach(({ key, data }) => queryClient.setQueryData(key, data));\n\n if (toast) showToast(\"error\", messages, null, variables, error as Error, instanceToast);\n onError?.(error as Error, variables);\n },\n\n onSettled: (data, error, variables) => {\n onSettled?.(data, error as Error | null, variables);\n },\n });\n\n return {\n mutate: mutation.mutate,\n mutateAsync: mutation.mutateAsync,\n isPending: mutation.isPending,\n isSuccess: mutation.isSuccess,\n isError: mutation.isError,\n error: mutation.error as Error | null,\n data: mutation.data,\n reset: mutation.reset,\n };\n}\n\n// ============================================================================\n// Optimistic Mutation for CRUD Factory (handles multiple matching queries)\n// ============================================================================\n\nexport interface CreateOptimisticMutationConfig<TData, TVariables> {\n mutationFn: (variables: TVariables) => Promise<TData>;\n queryClient: QueryClient;\n queryKeys: QueryKey[];\n optimisticUpdate?: (oldData: unknown, variables: TVariables) => unknown;\n onSuccess?: (data: TData, variables: TVariables) => void;\n onError?: (error: Error, variables: TVariables) => void;\n messages?: MutationMessages;\n toastHandler?: ToastHandler;\n}\n\nexport function createOptimisticMutation<TData, TVariables>({\n mutationFn,\n queryClient,\n queryKeys,\n optimisticUpdate,\n onSuccess,\n onError,\n messages,\n toastHandler: instanceToast,\n}: CreateOptimisticMutationConfig<TData, TVariables>) {\n return useMutation({\n mutationFn,\n\n onMutate: async (variables) => {\n await Promise.all(queryKeys.map((key) => queryClient.cancelQueries({ queryKey: key, exact: false })));\n\n const previous = queryKeys.map((key) => ({\n key,\n data: queryClient.getQueriesData({ queryKey: key }),\n }));\n\n if (optimisticUpdate) {\n queryKeys.forEach((key) => {\n queryClient.getQueriesData({ queryKey: key }).forEach(([qKey, qData]) => {\n queryClient.setQueryData(qKey, optimisticUpdate(qData, variables));\n });\n });\n }\n\n return { previous };\n },\n\n onSuccess: (data, variables) => {\n if (messages?.success) showToast(\"success\", messages, data, variables, undefined, instanceToast);\n queryKeys.forEach((key) => queryClient.invalidateQueries({ queryKey: key }));\n onSuccess?.(data, variables);\n },\n\n onError: (error, variables, context) => {\n const ctx = context as { previous?: Array<{ key: QueryKey; data: Array<[QueryKey, unknown]> }> };\n ctx?.previous?.forEach(({ data }) => {\n data.forEach(([qKey, qData]) => queryClient.setQueryData(qKey, qData));\n });\n\n showToast(\"error\", messages, null, variables, error as Error, instanceToast);\n onError?.(error as Error, variables);\n },\n });\n}\n\n// ============================================================================\n// Query Config Presets\n// ============================================================================\n\nexport const QUERY_CONFIGS = {\n realtime: { staleTime: 20_000, refetchInterval: 30_000 },\n frequent: { staleTime: 60_000 },\n stable: { staleTime: 300_000 },\n static: { staleTime: 600_000 },\n} as const;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { QueryClient, dehydrate } from "@tanstack/react-query";
|
|
2
|
+
|
|
3
|
+
//#region src/prefetch.d.ts
|
|
4
|
+
interface PrefetchOptions {
|
|
5
|
+
staleTime?: number;
|
|
6
|
+
}
|
|
7
|
+
interface CrudPrefetcher {
|
|
8
|
+
/**
|
|
9
|
+
* Prefetch a list query on the server. Uses the same query keys as useList.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const queryClient = getQueryClient();
|
|
13
|
+
* await productsPrefetcher.prefetchList(queryClient, { limit: 20 });
|
|
14
|
+
*/
|
|
15
|
+
prefetchList: (queryClient: QueryClient, params?: Record<string, unknown>, options?: PrefetchOptions) => Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Prefetch a detail query on the server. Uses the same query keys as useDetail.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const queryClient = getQueryClient();
|
|
21
|
+
* await productsPrefetcher.prefetchDetail(queryClient, productId);
|
|
22
|
+
*/
|
|
23
|
+
prefetchDetail: (queryClient: QueryClient, id: string, options?: PrefetchOptions) => Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create server-safe prefetch helpers for CRUD queries.
|
|
27
|
+
* Use in Next.js server components to pre-populate the query cache before rendering.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* // products-prefetch.ts
|
|
31
|
+
* import { productsApi } from '@/api/products-api';
|
|
32
|
+
* import { createCrudPrefetcher } from '@classytic/arc-next/prefetch';
|
|
33
|
+
* export const productsPrefetcher = createCrudPrefetcher(productsApi, 'products');
|
|
34
|
+
*
|
|
35
|
+
* // app/products/page.tsx (server component)
|
|
36
|
+
* import { getQueryClient } from '@classytic/arc-next/query-client';
|
|
37
|
+
* import { dehydrate } from '@classytic/arc-next/prefetch';
|
|
38
|
+
* import { HydrationBoundary } from '@tanstack/react-query';
|
|
39
|
+
*
|
|
40
|
+
* export default async function ProductsPage() {
|
|
41
|
+
* const queryClient = getQueryClient();
|
|
42
|
+
* await productsPrefetcher.prefetchList(queryClient, { limit: 20 });
|
|
43
|
+
* return (
|
|
44
|
+
* <HydrationBoundary state={dehydrate(queryClient)}>
|
|
45
|
+
* <ProductsList />
|
|
46
|
+
* </HydrationBoundary>
|
|
47
|
+
* );
|
|
48
|
+
* }
|
|
49
|
+
*/
|
|
50
|
+
declare function createCrudPrefetcher(api: {
|
|
51
|
+
getAll: (opts: {
|
|
52
|
+
params?: Record<string, unknown>;
|
|
53
|
+
token?: string | null;
|
|
54
|
+
organizationId?: string | null;
|
|
55
|
+
}) => Promise<unknown>;
|
|
56
|
+
getById: (opts: {
|
|
57
|
+
id: string;
|
|
58
|
+
token?: string | null;
|
|
59
|
+
organizationId?: string | null;
|
|
60
|
+
}) => Promise<unknown>;
|
|
61
|
+
}, entityKey: string): CrudPrefetcher;
|
|
62
|
+
//#endregion
|
|
63
|
+
export { CrudPrefetcher, PrefetchOptions, createCrudPrefetcher, dehydrate };
|
|
64
|
+
//# sourceMappingURL=prefetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefetch.d.ts","names":[],"sources":["../src/prefetch.ts"],"mappings":";;;UASiB,eAAA;EACf,SAAA;AAAA;AAAA,UAGe,cAAA;EAHf;;AAGF;;;;;EAQE,YAAA,GACE,WAAA,EAAa,WAAA,EACb,MAAA,GAAS,MAAA,mBACT,OAAA,GAAU,eAAA,KACP,OAAA;EAAA;;;;;;;EASL,cAAA,GACE,WAAA,EAAa,WAAA,EACb,EAAA,UACA,OAAA,GAAU,eAAA,KACP,OAAA;AAAA;;;;;;;;;;;;;;;AA4CP;;;;;;;;;;;iBAAgB,oBAAA,CACd,GAAA;EACE,MAAA,GAAS,IAAA;IACP,MAAA,GAAS,MAAA;IACT,KAAA;IACA,cAAA;EAAA,MACI,OAAA;EACN,OAAA,GAAU,IAAA;IACR,EAAA;IACA,KAAA;IACA,cAAA;EAAA,MACI,OAAA;AAAA,GAER,SAAA,WACC,cAAA"}
|
package/dist/prefetch.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { dehydrate } from "@tanstack/react-query";
|
|
2
|
+
|
|
3
|
+
//#region src/prefetch.ts
|
|
4
|
+
function scopedListKey(entityKey, scope, params) {
|
|
5
|
+
return [
|
|
6
|
+
entityKey,
|
|
7
|
+
"list",
|
|
8
|
+
{
|
|
9
|
+
_scope: scope,
|
|
10
|
+
...params || {}
|
|
11
|
+
}
|
|
12
|
+
];
|
|
13
|
+
}
|
|
14
|
+
function detailKey(entityKey, id) {
|
|
15
|
+
return [
|
|
16
|
+
entityKey,
|
|
17
|
+
"detail",
|
|
18
|
+
id
|
|
19
|
+
];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create server-safe prefetch helpers for CRUD queries.
|
|
23
|
+
* Use in Next.js server components to pre-populate the query cache before rendering.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // products-prefetch.ts
|
|
27
|
+
* import { productsApi } from '@/api/products-api';
|
|
28
|
+
* import { createCrudPrefetcher } from '@classytic/arc-next/prefetch';
|
|
29
|
+
* export const productsPrefetcher = createCrudPrefetcher(productsApi, 'products');
|
|
30
|
+
*
|
|
31
|
+
* // app/products/page.tsx (server component)
|
|
32
|
+
* import { getQueryClient } from '@classytic/arc-next/query-client';
|
|
33
|
+
* import { dehydrate } from '@classytic/arc-next/prefetch';
|
|
34
|
+
* import { HydrationBoundary } from '@tanstack/react-query';
|
|
35
|
+
*
|
|
36
|
+
* export default async function ProductsPage() {
|
|
37
|
+
* const queryClient = getQueryClient();
|
|
38
|
+
* await productsPrefetcher.prefetchList(queryClient, { limit: 20 });
|
|
39
|
+
* return (
|
|
40
|
+
* <HydrationBoundary state={dehydrate(queryClient)}>
|
|
41
|
+
* <ProductsList />
|
|
42
|
+
* </HydrationBoundary>
|
|
43
|
+
* );
|
|
44
|
+
* }
|
|
45
|
+
*/
|
|
46
|
+
function createCrudPrefetcher(api, entityKey) {
|
|
47
|
+
return {
|
|
48
|
+
async prefetchList(queryClient, params = {}, options = {}) {
|
|
49
|
+
const { organizationId, ...restParams } = params;
|
|
50
|
+
const queryKey = scopedListKey(entityKey, organizationId ? "tenant" : "super-admin", {
|
|
51
|
+
organizationId,
|
|
52
|
+
...restParams
|
|
53
|
+
});
|
|
54
|
+
await queryClient.prefetchQuery({
|
|
55
|
+
queryKey,
|
|
56
|
+
queryFn: () => api.getAll({
|
|
57
|
+
params: restParams,
|
|
58
|
+
organizationId: organizationId ?? null
|
|
59
|
+
}),
|
|
60
|
+
staleTime: options.staleTime
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
async prefetchDetail(queryClient, id, options = {}) {
|
|
64
|
+
const queryKey = detailKey(entityKey, id);
|
|
65
|
+
await queryClient.prefetchQuery({
|
|
66
|
+
queryKey,
|
|
67
|
+
queryFn: () => api.getById({ id }),
|
|
68
|
+
staleTime: options.staleTime
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
export { createCrudPrefetcher, dehydrate };
|
|
76
|
+
//# sourceMappingURL=prefetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefetch.js","names":[],"sources":["../src/prefetch.ts"],"sourcesContent":["import { dehydrate, type QueryClient, type QueryKey } from '@tanstack/react-query';\n\n// Re-export for convenience in server components\nexport { dehydrate } from '@tanstack/react-query';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface PrefetchOptions {\n staleTime?: number;\n}\n\nexport interface CrudPrefetcher {\n /**\n * Prefetch a list query on the server. Uses the same query keys as useList.\n *\n * @example\n * const queryClient = getQueryClient();\n * await productsPrefetcher.prefetchList(queryClient, { limit: 20 });\n */\n prefetchList: (\n queryClient: QueryClient,\n params?: Record<string, unknown>,\n options?: PrefetchOptions,\n ) => Promise<void>;\n\n /**\n * Prefetch a detail query on the server. Uses the same query keys as useDetail.\n *\n * @example\n * const queryClient = getQueryClient();\n * await productsPrefetcher.prefetchDetail(queryClient, productId);\n */\n prefetchDetail: (\n queryClient: QueryClient,\n id: string,\n options?: PrefetchOptions,\n ) => Promise<void>;\n}\n\n// ============================================================================\n// Query Key Generators (must match createQueryKeys in query.ts)\n// ============================================================================\n\nfunction scopedListKey(entityKey: string, scope: string, params?: Record<string, unknown>): QueryKey {\n return [entityKey, 'list', { _scope: scope, ...(params || {}) }];\n}\n\nfunction detailKey(entityKey: string, id: string): QueryKey {\n return [entityKey, 'detail', id];\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/**\n * Create server-safe prefetch helpers for CRUD queries.\n * Use in Next.js server components to pre-populate the query cache before rendering.\n *\n * @example\n * // products-prefetch.ts\n * import { productsApi } from '@/api/products-api';\n * import { createCrudPrefetcher } from '@classytic/arc-next/prefetch';\n * export const productsPrefetcher = createCrudPrefetcher(productsApi, 'products');\n *\n * // app/products/page.tsx (server component)\n * import { getQueryClient } from '@classytic/arc-next/query-client';\n * import { dehydrate } from '@classytic/arc-next/prefetch';\n * import { HydrationBoundary } from '@tanstack/react-query';\n *\n * export default async function ProductsPage() {\n * const queryClient = getQueryClient();\n * await productsPrefetcher.prefetchList(queryClient, { limit: 20 });\n * return (\n * <HydrationBoundary state={dehydrate(queryClient)}>\n * <ProductsList />\n * </HydrationBoundary>\n * );\n * }\n */\nexport function createCrudPrefetcher(\n api: {\n getAll: (opts: {\n params?: Record<string, unknown>;\n token?: string | null;\n organizationId?: string | null;\n }) => Promise<unknown>;\n getById: (opts: {\n id: string;\n token?: string | null;\n organizationId?: string | null;\n }) => Promise<unknown>;\n },\n entityKey: string,\n): CrudPrefetcher {\n return {\n async prefetchList(queryClient, params = {}, options = {}) {\n const { organizationId, ...restParams } = params;\n const scope = organizationId ? 'tenant' : 'super-admin';\n const queryKey = scopedListKey(entityKey, scope, { organizationId, ...restParams });\n\n await queryClient.prefetchQuery({\n queryKey,\n queryFn: () => api.getAll({\n params: restParams,\n organizationId: (organizationId as string | null) ?? null,\n }),\n staleTime: options.staleTime,\n });\n },\n\n async prefetchDetail(queryClient, id, options = {}) {\n const queryKey = detailKey(entityKey, id);\n\n await queryClient.prefetchQuery({\n queryKey,\n queryFn: () => api.getById({ id }),\n staleTime: options.staleTime,\n });\n },\n };\n}\n"],"mappings":";;;AA6CA,SAAS,cAAc,WAAmB,OAAe,QAA4C;AACnG,QAAO;EAAC;EAAW;EAAQ;GAAE,QAAQ;GAAO,GAAI,UAAU,EAAE;GAAG;EAAC;;AAGlE,SAAS,UAAU,WAAmB,IAAsB;AAC1D,QAAO;EAAC;EAAW;EAAU;EAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgClC,SAAgB,qBACd,KAYA,WACgB;AAChB,QAAO;EACL,MAAM,aAAa,aAAa,SAAS,EAAE,EAAE,UAAU,EAAE,EAAE;GACzD,MAAM,EAAE,gBAAgB,GAAG,eAAe;GAE1C,MAAM,WAAW,cAAc,WADjB,iBAAiB,WAAW,eACO;IAAE;IAAgB,GAAG;IAAY,CAAC;AAEnF,SAAM,YAAY,cAAc;IAC9B;IACA,eAAe,IAAI,OAAO;KACxB,QAAQ;KACR,gBAAiB,kBAAoC;KACtD,CAAC;IACF,WAAW,QAAQ;IACpB,CAAC;;EAGJ,MAAM,eAAe,aAAa,IAAI,UAAU,EAAE,EAAE;GAClD,MAAM,WAAW,UAAU,WAAW,GAAG;AAEzC,SAAM,YAAY,cAAc;IAC9B;IACA,eAAe,IAAI,QAAQ,EAAE,IAAI,CAAC;IAClC,WAAW,QAAQ;IACpB,CAAC;;EAEL"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
2
|
+
|
|
3
|
+
//#region src/query-client.d.ts
|
|
4
|
+
interface QueryClientOverrides {
|
|
5
|
+
staleTime?: number;
|
|
6
|
+
gcTime?: number;
|
|
7
|
+
retry?: number | boolean;
|
|
8
|
+
refetchOnWindowFocus?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* SSR-safe QueryClient singleton factory.
|
|
12
|
+
* Server: always creates a new instance (one per request).
|
|
13
|
+
* Browser: reuses a singleton (survives Suspense re-renders).
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // In layout.tsx or providers
|
|
17
|
+
* const queryClient = getQueryClient();
|
|
18
|
+
*
|
|
19
|
+
* // With overrides
|
|
20
|
+
* const queryClient = getQueryClient({ staleTime: 60_000 });
|
|
21
|
+
*/
|
|
22
|
+
declare function getQueryClient(overrides?: QueryClientOverrides): QueryClient;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { QueryClientOverrides, getQueryClient };
|
|
25
|
+
//# sourceMappingURL=query-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-client.d.ts","names":[],"sources":["../src/query-client.ts"],"mappings":";;;UAUiB,oBAAA;EACf,SAAA;EACA,MAAA;EACA,KAAA;EACA,oBAAA;AAAA;;;;;;;AAoDF;;;;;;iBAAgB,cAAA,CAAe,SAAA,GAAY,oBAAA,GAAuB,WAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { QueryClient, defaultShouldDehydrateQuery, isServer } from "@tanstack/react-query";
|
|
2
|
+
|
|
3
|
+
//#region src/query-client.ts
|
|
4
|
+
const DEFAULTS = {
|
|
5
|
+
staleTime: 300 * 1e3,
|
|
6
|
+
gcTime: 1800 * 1e3,
|
|
7
|
+
retry: 0,
|
|
8
|
+
refetchOnWindowFocus: false
|
|
9
|
+
};
|
|
10
|
+
function makeQueryClient(overrides) {
|
|
11
|
+
const opts = {
|
|
12
|
+
...DEFAULTS,
|
|
13
|
+
...overrides
|
|
14
|
+
};
|
|
15
|
+
return new QueryClient({ defaultOptions: {
|
|
16
|
+
queries: {
|
|
17
|
+
retry: opts.retry,
|
|
18
|
+
staleTime: opts.staleTime,
|
|
19
|
+
gcTime: opts.gcTime,
|
|
20
|
+
refetchOnWindowFocus: opts.refetchOnWindowFocus
|
|
21
|
+
},
|
|
22
|
+
dehydrate: { shouldDehydrateQuery: (query) => defaultShouldDehydrateQuery(query) || query.state.status === "pending" }
|
|
23
|
+
} });
|
|
24
|
+
}
|
|
25
|
+
let browserQueryClient;
|
|
26
|
+
/**
|
|
27
|
+
* SSR-safe QueryClient singleton factory.
|
|
28
|
+
* Server: always creates a new instance (one per request).
|
|
29
|
+
* Browser: reuses a singleton (survives Suspense re-renders).
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // In layout.tsx or providers
|
|
33
|
+
* const queryClient = getQueryClient();
|
|
34
|
+
*
|
|
35
|
+
* // With overrides
|
|
36
|
+
* const queryClient = getQueryClient({ staleTime: 60_000 });
|
|
37
|
+
*/
|
|
38
|
+
function getQueryClient(overrides) {
|
|
39
|
+
if (isServer) return makeQueryClient(overrides);
|
|
40
|
+
if (!browserQueryClient) browserQueryClient = makeQueryClient(overrides);
|
|
41
|
+
return browserQueryClient;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//#endregion
|
|
45
|
+
export { getQueryClient };
|
|
46
|
+
//# sourceMappingURL=query-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-client.js","names":[],"sources":["../src/query-client.ts"],"sourcesContent":["import {\n isServer,\n QueryClient,\n defaultShouldDehydrateQuery,\n} from '@tanstack/react-query';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface QueryClientOverrides {\n staleTime?: number;\n gcTime?: number;\n retry?: number | boolean;\n refetchOnWindowFocus?: boolean;\n}\n\n// ============================================================================\n// Defaults\n// ============================================================================\n\nconst DEFAULTS: Required<QueryClientOverrides> = {\n staleTime: 5 * 60 * 1000,\n gcTime: 30 * 60 * 1000,\n retry: 0,\n refetchOnWindowFocus: false,\n};\n\n// ============================================================================\n// Factory\n// ============================================================================\n\nfunction makeQueryClient(overrides?: QueryClientOverrides): QueryClient {\n const opts = { ...DEFAULTS, ...overrides };\n\n return new QueryClient({\n defaultOptions: {\n queries: {\n retry: opts.retry as number,\n staleTime: opts.staleTime,\n gcTime: opts.gcTime,\n refetchOnWindowFocus: opts.refetchOnWindowFocus,\n },\n dehydrate: {\n shouldDehydrateQuery: (query) =>\n defaultShouldDehydrateQuery(query) ||\n query.state.status === 'pending',\n },\n },\n });\n}\n\nlet browserQueryClient: QueryClient | undefined;\n\n/**\n * SSR-safe QueryClient singleton factory.\n * Server: always creates a new instance (one per request).\n * Browser: reuses a singleton (survives Suspense re-renders).\n *\n * @example\n * // In layout.tsx or providers\n * const queryClient = getQueryClient();\n *\n * // With overrides\n * const queryClient = getQueryClient({ staleTime: 60_000 });\n */\nexport function getQueryClient(overrides?: QueryClientOverrides): QueryClient {\n if (isServer) {\n return makeQueryClient(overrides);\n }\n\n if (!browserQueryClient) {\n browserQueryClient = makeQueryClient(overrides);\n }\n return browserQueryClient;\n}\n"],"mappings":";;;AAqBA,MAAM,WAA2C;CAC/C,WAAW,MAAS;CACpB,QAAQ,OAAU;CAClB,OAAO;CACP,sBAAsB;CACvB;AAMD,SAAS,gBAAgB,WAA+C;CACtE,MAAM,OAAO;EAAE,GAAG;EAAU,GAAG;EAAW;AAE1C,QAAO,IAAI,YAAY,EACrB,gBAAgB;EACd,SAAS;GACP,OAAO,KAAK;GACZ,WAAW,KAAK;GAChB,QAAQ,KAAK;GACb,sBAAsB,KAAK;GAC5B;EACD,WAAW,EACT,uBAAuB,UACrB,4BAA4B,MAAM,IAClC,MAAM,MAAM,WAAW,WAC1B;EACF,EACF,CAAC;;AAGJ,IAAI;;;;;;;;;;;;;AAcJ,SAAgB,eAAe,WAA+C;AAC5E,KAAI,SACF,QAAO,gBAAgB,UAAU;AAGnC,KAAI,CAAC,mBACH,sBAAqB,gBAAgB,UAAU;AAEjD,QAAO"}
|
package/dist/query.d.ts
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { InfiniteData, QueryClient, QueryKey } from "@tanstack/react-query";
|
|
2
|
+
|
|
3
|
+
//#region src/query.d.ts
|
|
4
|
+
interface PaginationData {
|
|
5
|
+
total: number;
|
|
6
|
+
pages: number;
|
|
7
|
+
page: number;
|
|
8
|
+
limit: number;
|
|
9
|
+
hasNext: boolean;
|
|
10
|
+
hasPrev: boolean;
|
|
11
|
+
}
|
|
12
|
+
/** Request-level options passed through to the fetch call */
|
|
13
|
+
interface RequestPassthrough {
|
|
14
|
+
cache?: RequestCache;
|
|
15
|
+
revalidate?: number;
|
|
16
|
+
tags?: string[];
|
|
17
|
+
headerOptions?: Record<string, string>;
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
}
|
|
20
|
+
interface ListQueryOptions {
|
|
21
|
+
public?: boolean;
|
|
22
|
+
enabled?: boolean;
|
|
23
|
+
staleTime?: number;
|
|
24
|
+
gcTime?: number;
|
|
25
|
+
refetchOnWindowFocus?: boolean;
|
|
26
|
+
structuralSharing?: boolean;
|
|
27
|
+
prefillDetailCache?: boolean;
|
|
28
|
+
refetchInterval?: number | false;
|
|
29
|
+
refetchIntervalInBackground?: boolean;
|
|
30
|
+
_scope?: string;
|
|
31
|
+
/** Pass-through options for the underlying fetch request (cache, revalidate, tags, headers) */
|
|
32
|
+
request?: RequestPassthrough;
|
|
33
|
+
}
|
|
34
|
+
interface DetailQueryOptions {
|
|
35
|
+
public?: boolean;
|
|
36
|
+
organizationId?: string | null;
|
|
37
|
+
enabled?: boolean;
|
|
38
|
+
staleTime?: number;
|
|
39
|
+
gcTime?: number;
|
|
40
|
+
structuralSharing?: boolean;
|
|
41
|
+
refetchInterval?: number | false;
|
|
42
|
+
refetchIntervalInBackground?: boolean;
|
|
43
|
+
/** Pass-through options for the underlying fetch request (cache, revalidate, tags, headers) */
|
|
44
|
+
request?: RequestPassthrough;
|
|
45
|
+
}
|
|
46
|
+
interface ListQueryResult<T> {
|
|
47
|
+
items: T[];
|
|
48
|
+
pagination: PaginationData | null;
|
|
49
|
+
isLoading: boolean;
|
|
50
|
+
isFetching: boolean;
|
|
51
|
+
isError: boolean;
|
|
52
|
+
isSuccess: boolean;
|
|
53
|
+
isStale: boolean;
|
|
54
|
+
error: Error | null;
|
|
55
|
+
refetch: () => Promise<unknown>;
|
|
56
|
+
data: unknown;
|
|
57
|
+
}
|
|
58
|
+
interface DetailQueryResult<T> {
|
|
59
|
+
item: T | null;
|
|
60
|
+
isLoading: boolean;
|
|
61
|
+
isFetching: boolean;
|
|
62
|
+
isError: boolean;
|
|
63
|
+
isSuccess: boolean;
|
|
64
|
+
isStale: boolean;
|
|
65
|
+
error: Error | null;
|
|
66
|
+
refetch: () => Promise<unknown>;
|
|
67
|
+
data: unknown;
|
|
68
|
+
}
|
|
69
|
+
interface QueryKeys {
|
|
70
|
+
all: string[];
|
|
71
|
+
lists: () => QueryKey;
|
|
72
|
+
list: (params?: unknown) => QueryKey;
|
|
73
|
+
details: () => QueryKey;
|
|
74
|
+
detail: (id: string) => QueryKey;
|
|
75
|
+
custom: (key: string, ...args: unknown[]) => QueryKey;
|
|
76
|
+
scopedList: (scope: string, params?: unknown) => QueryKey;
|
|
77
|
+
}
|
|
78
|
+
interface CacheUtils<T> {
|
|
79
|
+
invalidateAll: (client: QueryClient) => Promise<void>;
|
|
80
|
+
invalidateLists: (client: QueryClient) => Promise<void>;
|
|
81
|
+
invalidateDetail: (client: QueryClient, id: string) => Promise<void>;
|
|
82
|
+
setDetail: (client: QueryClient, id: string, data: T) => void;
|
|
83
|
+
getDetail: (client: QueryClient, id: string) => T | undefined;
|
|
84
|
+
removeDetail: (client: QueryClient, id: string) => void;
|
|
85
|
+
}
|
|
86
|
+
declare const DEFAULT_QUERY_CONFIG: {
|
|
87
|
+
readonly staleTime: number;
|
|
88
|
+
readonly gcTime: number;
|
|
89
|
+
readonly refetchOnWindowFocus: false;
|
|
90
|
+
readonly retry: 1;
|
|
91
|
+
};
|
|
92
|
+
declare function getItemId(item: unknown): string | null;
|
|
93
|
+
declare function updateListCache<T>(listData: unknown, updater: (items: T[]) => T[]): unknown;
|
|
94
|
+
declare function createQueryKeys(entityKey: string): QueryKeys;
|
|
95
|
+
declare function createCacheUtils<T>(KEYS: QueryKeys): CacheUtils<T>;
|
|
96
|
+
interface CreateListQueryConfig {
|
|
97
|
+
queryKey: QueryKey;
|
|
98
|
+
queryFn: (context: {
|
|
99
|
+
signal: AbortSignal;
|
|
100
|
+
}) => Promise<unknown>;
|
|
101
|
+
enabled?: boolean;
|
|
102
|
+
options?: Record<string, unknown>;
|
|
103
|
+
prefillDetailCache?: boolean;
|
|
104
|
+
detailKeyBuilder?: (id: string) => QueryKey;
|
|
105
|
+
}
|
|
106
|
+
declare function createListQuery<T>({
|
|
107
|
+
queryKey,
|
|
108
|
+
queryFn,
|
|
109
|
+
enabled,
|
|
110
|
+
options,
|
|
111
|
+
prefillDetailCache,
|
|
112
|
+
detailKeyBuilder
|
|
113
|
+
}: CreateListQueryConfig): ListQueryResult<T>;
|
|
114
|
+
interface CreateDetailQueryConfig {
|
|
115
|
+
queryKey: QueryKey;
|
|
116
|
+
queryFn: (context: {
|
|
117
|
+
signal: AbortSignal;
|
|
118
|
+
}) => Promise<unknown>;
|
|
119
|
+
enabled?: boolean;
|
|
120
|
+
options?: Record<string, unknown>;
|
|
121
|
+
}
|
|
122
|
+
declare function createDetailQuery<T>({
|
|
123
|
+
queryKey,
|
|
124
|
+
queryFn,
|
|
125
|
+
enabled,
|
|
126
|
+
options
|
|
127
|
+
}: CreateDetailQueryConfig): DetailQueryResult<T>;
|
|
128
|
+
interface InfiniteListQueryOptions {
|
|
129
|
+
public?: boolean;
|
|
130
|
+
enabled?: boolean;
|
|
131
|
+
staleTime?: number;
|
|
132
|
+
gcTime?: number;
|
|
133
|
+
refetchOnWindowFocus?: boolean;
|
|
134
|
+
structuralSharing?: boolean;
|
|
135
|
+
_scope?: string;
|
|
136
|
+
request?: RequestPassthrough;
|
|
137
|
+
}
|
|
138
|
+
interface InfiniteListQueryResult<T> {
|
|
139
|
+
items: T[];
|
|
140
|
+
hasNextPage: boolean;
|
|
141
|
+
hasPreviousPage: boolean;
|
|
142
|
+
isFetchingNextPage: boolean;
|
|
143
|
+
isFetchingPreviousPage: boolean;
|
|
144
|
+
fetchNextPage: () => void;
|
|
145
|
+
fetchPreviousPage: () => void;
|
|
146
|
+
isLoading: boolean;
|
|
147
|
+
isFetching: boolean;
|
|
148
|
+
isError: boolean;
|
|
149
|
+
isSuccess: boolean;
|
|
150
|
+
error: Error | null;
|
|
151
|
+
refetch: () => Promise<unknown>;
|
|
152
|
+
data: InfiniteData<unknown> | undefined;
|
|
153
|
+
}
|
|
154
|
+
interface CreateInfiniteListQueryConfig {
|
|
155
|
+
queryKey: QueryKey;
|
|
156
|
+
queryFn: (context: {
|
|
157
|
+
signal: AbortSignal;
|
|
158
|
+
pageParam: unknown;
|
|
159
|
+
}) => Promise<unknown>;
|
|
160
|
+
enabled?: boolean;
|
|
161
|
+
options?: Record<string, unknown>;
|
|
162
|
+
initialPageParam?: unknown;
|
|
163
|
+
getNextPageParam: (lastPage: unknown) => unknown;
|
|
164
|
+
getPreviousPageParam?: (firstPage: unknown) => unknown;
|
|
165
|
+
}
|
|
166
|
+
declare function createInfiniteListQuery<T>({
|
|
167
|
+
queryKey,
|
|
168
|
+
queryFn,
|
|
169
|
+
enabled,
|
|
170
|
+
options,
|
|
171
|
+
initialPageParam,
|
|
172
|
+
getNextPageParam,
|
|
173
|
+
getPreviousPageParam
|
|
174
|
+
}: CreateInfiniteListQueryConfig): InfiniteListQueryResult<T>;
|
|
175
|
+
//#endregion
|
|
176
|
+
export { CacheUtils, CreateDetailQueryConfig, CreateInfiniteListQueryConfig, CreateListQueryConfig, DEFAULT_QUERY_CONFIG, DetailQueryOptions, DetailQueryResult, InfiniteListQueryOptions, InfiniteListQueryResult, ListQueryOptions, ListQueryResult, PaginationData, QueryKeys, RequestPassthrough, createCacheUtils, createDetailQuery, createInfiniteListQuery, createListQuery, createQueryKeys, getItemId, updateListCache };
|
|
177
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","names":[],"sources":["../src/query.ts"],"mappings":"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"}
|