@classytic/arc-next 0.2.1 → 0.3.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/hooks.js CHANGED
@@ -2,16 +2,18 @@
2
2
 
3
3
  import { getAuthContext, getAuthMode } from "./client.js";
4
4
  import { isKeysetPagination, isOffsetPagination } from "./api.js";
5
- import { DEFAULT_QUERY_CONFIG, createCacheUtils, createDetailQuery, createInfiniteListQuery, createListQuery, createQueryKeys, getItemId, updateListCache } from "./query.js";
6
- import { createOptimisticMutation, useMutationWithTransition } from "./mutation.js";
5
+ import { DEFAULT_QUERY_CONFIG, createCacheUtils, createQueryKeys, extractItem, getItemId, updateListCache, useDetailQuery, useInfiniteListQuery, useListQuery } from "./query.js";
6
+ import { useMutationWithTransition, useOptimisticMutation } from "./mutation.js";
7
7
  import { useMutation, useQueryClient } from "@tanstack/react-query";
8
- import { useCallback, useRef } from "react";
8
+ import { useCallback, useMemo, useRef } from "react";
9
9
 
10
10
  //#region src/hooks.ts
11
11
  let useRouterHook = null;
12
12
  /**
13
13
  * Configure the router hook for useNavigation. Call once at app init.
14
14
  *
15
+ * **SSR safety:** This sets module-level state. Call only in client-side code.
16
+ *
15
17
  * @example
16
18
  * import { useRouter } from "next/navigation";
17
19
  * configureNavigation(useRouter);
@@ -19,16 +21,16 @@ let useRouterHook = null;
19
21
  function configureNavigation(hook) {
20
22
  useRouterHook = hook;
21
23
  }
22
- function createEnabledRule(token, options) {
23
- if (getAuthMode() === "cookie" || options.public) return options.enabled ?? true;
24
+ function createEnabledRule(token, options, authMode = getAuthMode()) {
25
+ if (authMode === "cookie" || options.public) return options.enabled ?? true;
24
26
  return options.enabled !== void 0 ? options.enabled && !!token : !!token;
25
27
  }
26
- function createCrudHooks({ api, entityKey, singular, platformScoped, defaults = {}, callbacks = {}, client }) {
27
- const isPlatform = platformScoped ?? api.scope === "platform";
28
+ function createCrudHooks({ api, entityKey, singular, defaults = {}, callbacks = {}, client }) {
28
29
  const KEYS = createQueryKeys(entityKey);
29
30
  const cache = createCacheUtils(KEYS);
30
31
  const instanceToast = client?.toast;
31
32
  const instanceNavigation = client?.navigation ?? null;
33
+ const resolveAuthMode = () => client?.config?.authMode ?? getAuthMode();
32
34
  const config = {
33
35
  ...DEFAULT_QUERY_CONFIG,
34
36
  ...defaults,
@@ -56,15 +58,15 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
56
58
  token = auth.token;
57
59
  params = tokenOrParams ?? {};
58
60
  options = paramsOrOptions ?? {};
59
- if (!isPlatform && auth.organizationId && !params.organizationId) params = {
61
+ if (auth.organizationId && !params.organizationId) params = {
60
62
  ...params,
61
63
  organizationId: auth.organizationId
62
64
  };
63
65
  }
64
66
  const { organizationId, ...restParams } = params;
65
- const scope = options._scope || (isPlatform ? "platform" : organizationId ? "tenant" : "super-admin");
67
+ const scope = options._scope || (organizationId ? "tenant" : "super-admin");
66
68
  const { request: requestOpts, ...queryOpts } = options;
67
- return createListQuery({
69
+ return useListQuery({
68
70
  queryKey: KEYS.scopedList(scope, {
69
71
  organizationId,
70
72
  ...restParams
@@ -78,7 +80,7 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
78
80
  ...requestOpts
79
81
  }
80
82
  }),
81
- enabled: createEnabledRule(token, queryOpts),
83
+ enabled: createEnabledRule(token, queryOpts, resolveAuthMode()),
82
84
  options: {
83
85
  staleTime: queryOpts.staleTime ?? config.staleTime,
84
86
  gcTime: queryOpts.gcTime ?? config.gcTime,
@@ -102,13 +104,13 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
102
104
  const auth = getAuthContext();
103
105
  token = auth.token;
104
106
  options = tokenOrOptions ?? {};
105
- if (!isPlatform && auth.organizationId && !options.organizationId) options = {
107
+ if (auth.organizationId && !options.organizationId) options = {
106
108
  ...options,
107
109
  organizationId: auth.organizationId
108
110
  };
109
111
  }
110
112
  const { organizationId, params: queryParams, request: requestOpts, ...restOptions } = options;
111
- return createDetailQuery({
113
+ return useDetailQuery({
112
114
  queryKey: queryParams ? [...KEYS.detail(id || ""), queryParams] : KEYS.detail(id || ""),
113
115
  queryFn: ({ signal }) => api.getById({
114
116
  id,
@@ -120,10 +122,11 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
120
122
  ...requestOpts
121
123
  }
122
124
  }),
123
- enabled: !!id && createEnabledRule(token, restOptions),
125
+ enabled: !!id && createEnabledRule(token, restOptions, resolveAuthMode()),
124
126
  options: {
125
127
  staleTime: restOptions.staleTime ?? config.staleTime,
126
128
  gcTime: restOptions.gcTime ?? config.gcTime,
129
+ refetchOnWindowFocus: restOptions.refetchOnWindowFocus ?? config.refetchOnWindowFocus,
127
130
  structuralSharing: restOptions.structuralSharing ?? config.structuralSharing,
128
131
  refetchInterval: restOptions.refetchInterval,
129
132
  refetchIntervalInBackground: restOptions.refetchIntervalInBackground
@@ -135,7 +138,7 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
135
138
  const queryClient = useQueryClient();
136
139
  const silentRef = useRef(false);
137
140
  const shouldToast = useCallback(() => !silentRef.current, []);
138
- const createMutation = createOptimisticMutation({
141
+ const createMutation = useOptimisticMutation({
139
142
  mutationFn: ({ token, organizationId, data }) => api.create({
140
143
  token,
141
144
  organizationId,
@@ -152,14 +155,14 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
152
155
  };
153
156
  return updateListCache(oldData, (arr) => [optimisticItem, ...arr || []]);
154
157
  },
155
- onSuccess: (data, variables) => {
156
- callbacks.onCreate?.onSuccess?.(data, { data: variables.data }, void 0);
158
+ onSuccess: (raw, variables) => {
159
+ callbacks.onCreate?.onSuccess?.(extractItem(raw), { data: variables.data }, void 0);
157
160
  },
158
161
  onError: (error, variables) => {
159
162
  callbacks.onCreate?.onError?.(error, { data: variables.data }, void 0);
160
163
  },
161
- onSettled: (data, error, variables) => {
162
- callbacks.onCreate?.onSettled?.(data, error, { data: variables.data }, void 0);
164
+ onSettled: (raw, error, variables) => {
165
+ callbacks.onCreate?.onSettled?.(raw ? extractItem(raw) : void 0, error, { data: variables.data }, void 0);
163
166
  },
164
167
  messages: {
165
168
  success: config.messages.createSuccess,
@@ -167,7 +170,7 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
167
170
  },
168
171
  toastHandler: instanceToast
169
172
  });
170
- const updateMutation = createOptimisticMutation({
173
+ const updateMutation = useOptimisticMutation({
171
174
  mutationFn: ({ token, organizationId, id, data }) => api.update({
172
175
  token,
173
176
  organizationId,
@@ -175,7 +178,7 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
175
178
  data
176
179
  }),
177
180
  queryClient,
178
- queryKeys: [KEYS.lists()],
181
+ queryKeys: [KEYS.lists(), KEYS.details()],
179
182
  shouldToast,
180
183
  optimisticUpdate: (oldData, { id, data }) => {
181
184
  const updated = updateListCache(oldData, (arr) => (arr || []).map((item) => getItemId(item) === id ? {
@@ -191,9 +194,9 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
191
194
  } : current);
192
195
  return updated;
193
196
  },
194
- onSuccess: (data, { id, data: updateData }) => {
197
+ onSuccess: (raw, { id, data: updateData }) => {
195
198
  queryClient.invalidateQueries({ queryKey: KEYS.detail(id) });
196
- callbacks.onUpdate?.onSuccess?.(data, {
199
+ callbacks.onUpdate?.onSuccess?.(extractItem(raw), {
197
200
  id,
198
201
  data: updateData
199
202
  }, void 0);
@@ -204,8 +207,8 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
204
207
  data
205
208
  }, void 0);
206
209
  },
207
- onSettled: (data, error, { id, data: updateData }) => {
208
- callbacks.onUpdate?.onSettled?.(data, error, {
210
+ onSettled: (raw, error, { id, data: updateData }) => {
211
+ callbacks.onUpdate?.onSettled?.(raw ? extractItem(raw) : void 0, error, {
209
212
  id,
210
213
  data: updateData
211
214
  }, void 0);
@@ -216,7 +219,7 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
216
219
  },
217
220
  toastHandler: instanceToast
218
221
  });
219
- const deleteMutation = createOptimisticMutation({
222
+ const deleteMutation = useOptimisticMutation({
220
223
  mutationFn: ({ token, organizationId, id }) => api.delete({
221
224
  token,
222
225
  organizationId,
@@ -226,10 +229,10 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
226
229
  queryKeys: [KEYS.lists()],
227
230
  shouldToast,
228
231
  optimisticUpdate: (oldData, { id }) => {
229
- queryClient.removeQueries({ queryKey: KEYS.detail(id) });
230
232
  return updateListCache(oldData, (arr) => (arr || []).filter((item) => getItemId(item) !== id));
231
233
  },
232
234
  onSuccess: (data, { id }) => {
235
+ queryClient.removeQueries({ queryKey: KEYS.detail(id) });
233
236
  callbacks.onDelete?.onSuccess?.(data, { id }, void 0);
234
237
  },
235
238
  onError: (error, { id }) => {
@@ -244,63 +247,60 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
244
247
  },
245
248
  toastHandler: instanceToast
246
249
  });
247
- const resolveAuth = (params) => {
250
+ const resolveAuth = useCallback((params) => {
248
251
  const auth = getAuthContext();
249
252
  return {
250
253
  ...params,
251
254
  token: params.token ?? auth.token,
252
- organizationId: isPlatform ? params.organizationId ?? null : params.organizationId ?? auth.organizationId
255
+ organizationId: params.organizationId ?? auth.organizationId
253
256
  };
254
- };
255
- const create = async (params, options) => {
256
- silentRef.current = options?.silent ?? false;
257
- try {
258
- const result = await createMutation.mutateAsync(resolveAuth(params));
259
- options?.onSuccess?.(result);
260
- options?.onSettled?.(result, null);
261
- return result;
262
- } catch (error) {
263
- options?.onError?.(error);
264
- options?.onSettled?.(void 0, error);
265
- throw error;
266
- } finally {
267
- silentRef.current = false;
268
- }
269
- };
270
- const update = async (params, options) => {
271
- silentRef.current = options?.silent ?? false;
272
- try {
273
- const result = await updateMutation.mutateAsync(resolveAuth(params));
274
- options?.onSuccess?.(result);
275
- options?.onSettled?.(result, null);
276
- return result;
277
- } catch (error) {
278
- options?.onError?.(error);
279
- options?.onSettled?.(void 0, error);
280
- throw error;
281
- } finally {
282
- silentRef.current = false;
283
- }
284
- };
285
- const remove = async (params, options) => {
286
- silentRef.current = options?.silent ?? false;
287
- try {
288
- const result = await deleteMutation.mutateAsync(resolveAuth(params));
289
- options?.onSuccess?.(result);
290
- options?.onSettled?.(result, null);
291
- return result;
292
- } catch (error) {
293
- options?.onError?.(error);
294
- options?.onSettled?.(void 0, error);
295
- throw error;
296
- } finally {
297
- silentRef.current = false;
298
- }
299
- };
257
+ }, []);
300
258
  return {
301
- create,
302
- update,
303
- remove,
259
+ create: useCallback(async (params, options) => {
260
+ silentRef.current = options?.silent ?? false;
261
+ try {
262
+ const entity = extractItem(await createMutation.mutateAsync(resolveAuth(params)));
263
+ options?.onSuccess?.(entity);
264
+ options?.onSettled?.(entity, null);
265
+ return entity;
266
+ } catch (error) {
267
+ options?.onError?.(error);
268
+ options?.onSettled?.(void 0, error);
269
+ throw error;
270
+ } finally {
271
+ silentRef.current = false;
272
+ }
273
+ }, [createMutation, resolveAuth]),
274
+ update: useCallback(async (params, options) => {
275
+ silentRef.current = options?.silent ?? false;
276
+ try {
277
+ const entity = extractItem(await updateMutation.mutateAsync(resolveAuth(params)));
278
+ options?.onSuccess?.(entity);
279
+ options?.onSettled?.(entity, null);
280
+ return entity;
281
+ } catch (error) {
282
+ options?.onError?.(error);
283
+ options?.onSettled?.(void 0, error);
284
+ throw error;
285
+ } finally {
286
+ silentRef.current = false;
287
+ }
288
+ }, [updateMutation, resolveAuth]),
289
+ remove: useCallback(async (params, options) => {
290
+ silentRef.current = options?.silent ?? false;
291
+ try {
292
+ const result = await deleteMutation.mutateAsync(resolveAuth(params));
293
+ options?.onSuccess?.(result);
294
+ options?.onSettled?.(result, null);
295
+ return result;
296
+ } catch (error) {
297
+ options?.onError?.(error);
298
+ options?.onSettled?.(void 0, error);
299
+ throw error;
300
+ } finally {
301
+ silentRef.current = false;
302
+ }
303
+ }, [deleteMutation, resolveAuth]),
304
304
  isCreating: createMutation.isPending,
305
305
  isUpdating: updateMutation.isPending,
306
306
  isDeleting: deleteMutation.isPending,
@@ -320,7 +320,7 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
320
320
  token = auth.token;
321
321
  params = tokenOrParams ?? {};
322
322
  options = paramsOrOptions ?? {};
323
- if (!isPlatform && auth.organizationId && !params.organizationId) params = {
323
+ if (auth.organizationId && !params.organizationId) params = {
324
324
  ...params,
325
325
  organizationId: auth.organizationId
326
326
  };
@@ -328,7 +328,7 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
328
328
  const { organizationId, ...restParams } = params;
329
329
  const scope = options._scope || (organizationId ? "tenant" : "super-admin");
330
330
  const { request: requestOpts, ...queryOpts } = options;
331
- return createInfiniteListQuery({
331
+ return useInfiniteListQuery({
332
332
  queryKey: [...KEYS.scopedList(scope, {
333
333
  organizationId,
334
334
  ...restParams
@@ -348,7 +348,7 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
348
348
  }
349
349
  });
350
350
  },
351
- enabled: createEnabledRule(token, queryOpts),
351
+ enabled: createEnabledRule(token, queryOpts, resolveAuthMode()),
352
352
  initialPageParam: restParams.after ? restParams.after : 1,
353
353
  getNextPageParam: (lastPage) => {
354
354
  const page = lastPage;
@@ -361,19 +361,20 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
361
361
  staleTime: queryOpts.staleTime ?? config.staleTime,
362
362
  gcTime: queryOpts.gcTime ?? config.gcTime,
363
363
  refetchOnWindowFocus: queryOpts.refetchOnWindowFocus ?? config.refetchOnWindowFocus,
364
- structuralSharing: queryOpts.structuralSharing ?? config.structuralSharing
364
+ structuralSharing: queryOpts.structuralSharing ?? config.structuralSharing,
365
+ refetchInterval: queryOpts.refetchInterval,
366
+ refetchIntervalInBackground: queryOpts.refetchIntervalInBackground
365
367
  }
366
368
  });
367
369
  }
368
370
  function useUpload(options) {
369
- if (!api.upload) throw new Error(`[arc-next] "${entityKey}" api does not define an upload method`);
370
- const uploadApi = api.upload;
371
371
  return useMutationWithTransition({
372
372
  mutationFn: ({ data, id, path }) => {
373
+ if (!api.upload) return Promise.reject(/* @__PURE__ */ new Error(`[arc-next] "${entityKey}" api does not define an upload method`));
373
374
  const auth = getAuthContext();
374
- return uploadApi({
375
+ return api.upload({
375
376
  token: auth.token,
376
- organizationId: isPlatform ? null : auth.organizationId,
377
+ organizationId: auth.organizationId,
377
378
  data,
378
379
  id,
379
380
  path
@@ -394,9 +395,9 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
394
395
  if (!api.search) throw new Error(`[arc-next] "${entityKey}" api does not define a search method`);
395
396
  const searchApi = api.search;
396
397
  const auth = getAuthContext();
397
- const token = auth.token;
398
- const organizationId = platformScoped ? null : params?.organizationId ?? auth.organizationId;
399
- const { organizationId: _, ...restParams } = params ?? {};
398
+ const token = params?.token ?? auth.token;
399
+ const organizationId = params?.organizationId ?? auth.organizationId;
400
+ const { organizationId: _, token: _t, ...restParams } = params ?? {};
400
401
  const searchParams = {
401
402
  q: query,
402
403
  ...restParams
@@ -406,7 +407,7 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
406
407
  organizationId,
407
408
  ...searchParams
408
409
  } : searchParams;
409
- return createListQuery({
410
+ return useListQuery({
410
411
  queryKey: [
411
412
  ...KEYS.lists(),
412
413
  "search",
@@ -421,7 +422,7 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
421
422
  ...requestOpts
422
423
  }
423
424
  }),
424
- enabled: query.length > 0 && createEnabledRule(token, queryOpts),
425
+ enabled: query.length > 0 && createEnabledRule(token, queryOpts, resolveAuthMode()),
425
426
  options: {
426
427
  staleTime: queryOpts.staleTime ?? config.staleTime,
427
428
  gcTime: queryOpts.gcTime ?? config.gcTime
@@ -440,9 +441,13 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
440
441
  toastHandler: instanceToast
441
442
  });
442
443
  }
444
+ const resolvedRouterHook = instanceNavigation ?? useRouterHook ?? (() => ({
445
+ push: () => {},
446
+ replace: () => {}
447
+ }));
443
448
  function useNavigation() {
444
449
  const queryClient = useQueryClient();
445
- const router = (instanceNavigation ?? useRouterHook)?.();
450
+ const router = resolvedRouterHook();
446
451
  return useCallback((href, item, options = {}) => {
447
452
  const id = getItemId(item);
448
453
  if (id) queryClient.setQueryData(KEYS.detail(id), { data: item });
@@ -467,5 +472,4 @@ function createCrudHooks({ api, entityKey, singular, platformScoped, defaults =
467
472
  }
468
473
 
469
474
  //#endregion
470
- export { configureNavigation, createCrudHooks };
471
- //# sourceMappingURL=hooks.js.map
475
+ export { configureNavigation, createCrudHooks };
@@ -26,6 +26,8 @@ interface TransitionMutationReturn<TData, TVariables> {
26
26
  /**
27
27
  * Configure toast handler. Call once at app init.
28
28
  *
29
+ * **SSR safety:** This sets module-level state. Call only in client-side code.
30
+ *
29
31
  * @example
30
32
  * import { toast } from "sonner";
31
33
  * configureToast({ success: toast.success, error: toast.error });
@@ -98,7 +100,7 @@ interface CreateOptimisticMutationConfig<TData, TVariables> {
98
100
  shouldToast?: () => boolean;
99
101
  toastHandler?: ToastHandler;
100
102
  }
101
- declare function createOptimisticMutation<TData, TVariables>(config: CreateOptimisticMutationConfig<TData, TVariables>): _tanstack_react_query0.UseMutationResult<TData, Error, TVariables, {
103
+ declare function useOptimisticMutation<TData, TVariables>(config: CreateOptimisticMutationConfig<TData, TVariables>): _tanstack_react_query0.UseMutationResult<TData, Error, TVariables, {
102
104
  previous: {
103
105
  key: readonly unknown[];
104
106
  data: [readonly unknown[], unknown][];
@@ -119,6 +121,7 @@ declare const QUERY_CONFIGS: {
119
121
  readonly staleTime: 600000;
120
122
  };
121
123
  };
124
+ /** @deprecated Use `useOptimisticMutation` */
125
+ declare const createOptimisticMutation: typeof useOptimisticMutation;
122
126
  //#endregion
123
- export { CreateOptimisticMutationConfig, MutationCallbacks, MutationMessages, OptimisticMutationConfig, QUERY_CONFIGS, type ToastHandler, TransitionMutationConfig, TransitionMutationReturn, configureToast, createOptimisticMutation, useMutationWithOptimistic, useMutationWithTransition };
124
- //# sourceMappingURL=mutation.d.ts.map
127
+ export { CreateOptimisticMutationConfig, MutationCallbacks, MutationMessages, OptimisticMutationConfig, QUERY_CONFIGS, TransitionMutationConfig, TransitionMutationReturn, configureToast, createOptimisticMutation, useMutationWithOptimistic, useMutationWithTransition, useOptimisticMutation };
package/dist/mutation.js CHANGED
@@ -12,6 +12,8 @@ let toastHandler = {
12
12
  /**
13
13
  * Configure toast handler. Call once at app init.
14
14
  *
15
+ * **SSR safety:** This sets module-level state. Call only in client-side code.
16
+ *
15
17
  * @example
16
18
  * import { toast } from "sonner";
17
19
  * configureToast({ success: toast.success, error: toast.error });
@@ -112,7 +114,7 @@ function useMutationWithOptimistic(config) {
112
114
  reset: mutation.reset
113
115
  };
114
116
  }
115
- function createOptimisticMutation(config) {
117
+ function useOptimisticMutation(config) {
116
118
  const { mutationFn, queryClient, queryKeys, optimisticUpdate, onSuccess, onError, onSettled, messages, toastHandler: instanceToast } = config;
117
119
  return useMutation({
118
120
  mutationFn,
@@ -158,7 +160,8 @@ const QUERY_CONFIGS = {
158
160
  stable: { staleTime: 3e5 },
159
161
  static: { staleTime: 6e5 }
160
162
  };
163
+ /** @deprecated Use `useOptimisticMutation` */
164
+ const createOptimisticMutation = useOptimisticMutation;
161
165
 
162
166
  //#endregion
163
- export { QUERY_CONFIGS, configureToast, createOptimisticMutation, useMutationWithOptimistic, useMutationWithTransition };
164
- //# sourceMappingURL=mutation.js.map
167
+ export { QUERY_CONFIGS, configureToast, createOptimisticMutation, useMutationWithOptimistic, useMutationWithTransition, useOptimisticMutation };
@@ -4,6 +4,13 @@ import { QueryClient, dehydrate } from "@tanstack/react-query";
4
4
  interface PrefetchOptions {
5
5
  staleTime?: number;
6
6
  }
7
+ interface PrefetchDetailOptions extends PrefetchOptions {
8
+ /** Query params (select, populate) — key must match useDetail's params to share cache */
9
+ params?: {
10
+ select?: string;
11
+ populate?: string | string[];
12
+ };
13
+ }
7
14
  interface CrudPrefetcher {
8
15
  /**
9
16
  * Prefetch a list query on the server. Uses the same query keys as useList.
@@ -20,7 +27,7 @@ interface CrudPrefetcher {
20
27
  * const queryClient = getQueryClient();
21
28
  * await productsPrefetcher.prefetchDetail(queryClient, productId);
22
29
  */
23
- prefetchDetail: (queryClient: QueryClient, id: string, options?: PrefetchOptions) => Promise<void>;
30
+ prefetchDetail: (queryClient: QueryClient, id: string, options?: PrefetchDetailOptions) => Promise<void>;
24
31
  }
25
32
  /**
26
33
  * Create server-safe prefetch helpers for CRUD queries.
@@ -60,5 +67,4 @@ declare function createCrudPrefetcher(api: {
60
67
  }) => Promise<unknown>;
61
68
  }, entityKey: string): CrudPrefetcher;
62
69
  //#endregion
63
- export { CrudPrefetcher, PrefetchOptions, createCrudPrefetcher, dehydrate };
64
- //# sourceMappingURL=prefetch.d.ts.map
70
+ export { CrudPrefetcher, PrefetchDetailOptions, PrefetchOptions, createCrudPrefetcher, dehydrate };
package/dist/prefetch.js CHANGED
@@ -61,16 +61,20 @@ function createCrudPrefetcher(api, entityKey) {
61
61
  });
62
62
  },
63
63
  async prefetchDetail(queryClient, id, options = {}) {
64
- const queryKey = detailKey(entityKey, id);
64
+ const { params, staleTime } = options;
65
+ const baseKey = detailKey(entityKey, id);
66
+ const queryKey = params ? [...baseKey, params] : baseKey;
65
67
  await queryClient.prefetchQuery({
66
68
  queryKey,
67
- queryFn: () => api.getById({ id }),
68
- staleTime: options.staleTime
69
+ queryFn: () => api.getById({
70
+ id,
71
+ ...params ? { params } : {}
72
+ }),
73
+ staleTime
69
74
  });
70
75
  }
71
76
  };
72
77
  }
73
78
 
74
79
  //#endregion
75
- export { createCrudPrefetcher, dehydrate };
76
- //# sourceMappingURL=prefetch.js.map
80
+ export { createCrudPrefetcher, dehydrate };
@@ -21,5 +21,4 @@ interface QueryClientOverrides {
21
21
  */
22
22
  declare function getQueryClient(overrides?: QueryClientOverrides): QueryClient;
23
23
  //#endregion
24
- export { QueryClientOverrides, getQueryClient };
25
- //# sourceMappingURL=query-client.d.ts.map
24
+ export { QueryClientOverrides, getQueryClient };
@@ -38,9 +38,9 @@ let browserQueryClient;
38
38
  function getQueryClient(overrides) {
39
39
  if (isServer) return makeQueryClient(overrides);
40
40
  if (!browserQueryClient) browserQueryClient = makeQueryClient(overrides);
41
+ else if (overrides) console.warn("[arc-next] getQueryClient(): Browser singleton already exists — overrides are ignored. Pass overrides only on the first call.");
41
42
  return browserQueryClient;
42
43
  }
43
44
 
44
45
  //#endregion
45
- export { getQueryClient };
46
- //# sourceMappingURL=query-client.js.map
46
+ export { getQueryClient };
package/dist/query.d.ts CHANGED
@@ -2,12 +2,16 @@ import { InfiniteData, QueryClient, QueryKey } from "@tanstack/react-query";
2
2
 
3
3
  //#region src/query.d.ts
4
4
  interface PaginationData {
5
+ /** Pagination method detected from response (offset | keyset | aggregate) */
6
+ method: 'offset' | 'keyset' | 'aggregate' | null;
5
7
  total: number;
6
8
  pages: number;
7
9
  page: number;
8
10
  limit: number;
9
11
  hasNext: boolean;
10
12
  hasPrev: boolean;
13
+ /** Keyset cursor for next page (keyset pagination only) */
14
+ next?: string | null;
11
15
  }
12
16
  /** Request-level options passed through to the fetch call */
13
17
  interface RequestPassthrough {
@@ -39,6 +43,7 @@ interface DetailQueryOptions<TData = unknown> {
39
43
  enabled?: boolean;
40
44
  staleTime?: number;
41
45
  gcTime?: number;
46
+ refetchOnWindowFocus?: boolean;
42
47
  structuralSharing?: boolean;
43
48
  refetchInterval?: number | false;
44
49
  refetchIntervalInBackground?: boolean;
@@ -99,6 +104,7 @@ declare const DEFAULT_QUERY_CONFIG: {
99
104
  readonly retry: 0;
100
105
  };
101
106
  declare function getItemId(item: unknown): string | null;
107
+ declare function extractItem<T>(data: unknown): T | null;
102
108
  declare function updateListCache<T>(listData: unknown, updater: (items: T[]) => T[]): unknown;
103
109
  declare function createQueryKeys(entityKey: string): QueryKeys;
104
110
  declare function createCacheUtils<T>(KEYS: QueryKeys): CacheUtils<T>;
@@ -113,7 +119,7 @@ interface CreateListQueryConfig {
113
119
  detailKeyBuilder?: (id: string) => QueryKey;
114
120
  select?: (data: unknown) => unknown;
115
121
  }
116
- declare function createListQuery<T>({
122
+ declare function useListQuery<T>({
117
123
  queryKey,
118
124
  queryFn,
119
125
  enabled,
@@ -131,7 +137,7 @@ interface CreateDetailQueryConfig {
131
137
  options?: Record<string, unknown>;
132
138
  select?: (data: unknown) => unknown;
133
139
  }
134
- declare function createDetailQuery<T>({
140
+ declare function useDetailQuery<T>({
135
141
  queryKey,
136
142
  queryFn,
137
143
  enabled,
@@ -145,6 +151,8 @@ interface InfiniteListQueryOptions {
145
151
  gcTime?: number;
146
152
  refetchOnWindowFocus?: boolean;
147
153
  structuralSharing?: boolean;
154
+ refetchInterval?: number | false;
155
+ refetchIntervalInBackground?: boolean;
148
156
  _scope?: string;
149
157
  request?: RequestPassthrough;
150
158
  }
@@ -176,7 +184,7 @@ interface CreateInfiniteListQueryConfig {
176
184
  getNextPageParam: (lastPage: unknown) => unknown;
177
185
  getPreviousPageParam?: (firstPage: unknown) => unknown;
178
186
  }
179
- declare function createInfiniteListQuery<T>({
187
+ declare function useInfiniteListQuery<T>({
180
188
  queryKey,
181
189
  queryFn,
182
190
  enabled,
@@ -185,6 +193,11 @@ declare function createInfiniteListQuery<T>({
185
193
  getNextPageParam,
186
194
  getPreviousPageParam
187
195
  }: CreateInfiniteListQueryConfig): InfiniteListQueryResult<T>;
196
+ /** @deprecated Use `useListQuery` */
197
+ declare const createListQuery: typeof useListQuery;
198
+ /** @deprecated Use `useDetailQuery` */
199
+ declare const createDetailQuery: typeof useDetailQuery;
200
+ /** @deprecated Use `useInfiniteListQuery` */
201
+ declare const createInfiniteListQuery: typeof useInfiniteListQuery;
188
202
  //#endregion
189
- export { CacheUtils, CreateDetailQueryConfig, CreateInfiniteListQueryConfig, CreateListQueryConfig, DEFAULT_QUERY_CONFIG, DetailQueryOptions, DetailQueryResult, InfiniteListQueryOptions, InfiniteListQueryResult, ListQueryOptions, ListQueryResult, PaginationData, QueryKeys, RequestPassthrough, createCacheUtils, createDetailQuery, createInfiniteListQuery, createListQuery, createQueryKeys, getItemId, updateListCache };
190
- //# sourceMappingURL=query.d.ts.map
203
+ export { CacheUtils, CreateDetailQueryConfig, CreateInfiniteListQueryConfig, CreateListQueryConfig, DEFAULT_QUERY_CONFIG, DetailQueryOptions, DetailQueryResult, InfiniteListQueryOptions, InfiniteListQueryResult, ListQueryOptions, ListQueryResult, PaginationData, QueryKeys, RequestPassthrough, createCacheUtils, createDetailQuery, createInfiniteListQuery, createListQuery, createQueryKeys, extractItem, getItemId, updateListCache, useDetailQuery, useInfiniteListQuery, useListQuery };