@wisemen/vue-core-api-utils 1.0.0-beta.2 → 1.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.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { err, ok } from "neverthrow";
2
- import { useInfiniteQuery, useMutation as useMutation$1, useQuery as useQuery$1, useQueryClient } from "@tanstack/vue-query";
3
- import { computed, unref } from "vue";
2
+ import { QueryClient as QueryClient$1, VueQueryPlugin, useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/vue-query";
3
+ import { computed } from "vue";
4
4
 
5
5
  //#region src/async-result/asyncResult.ts
6
6
  /**
@@ -135,72 +135,8 @@ const AsyncResult = {
135
135
  return AsyncResultOk._create(value);
136
136
  }
137
137
  };
138
-
139
- //#endregion
140
- //#region src/composables/mutation/mutation.composable.ts
141
- function useMutation(options) {
142
- const isDebug = options.isDebug ?? false;
143
- const queryClient = useQueryClient();
144
- async function onSuccess(responseData, params) {
145
- if (!options.queryKeysToInvalidate) return;
146
- await Promise.all(Object.entries(options.queryKeysToInvalidate).map(async ([queryKey, queryKeyParams]) => {
147
- if (!queryKeyParams) {
148
- if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`);
149
- await queryClient.invalidateQueries({ queryKey: [queryKey] });
150
- return;
151
- }
152
- const qkp = queryKeyParams;
153
- const paramEntries = Object.entries(qkp);
154
- if (paramEntries.length === 0) {
155
- if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`);
156
- await queryClient.invalidateQueries({ queryKey: [queryKey] });
157
- return;
158
- }
159
- const paramsWithValues = paramEntries.reduce((acc, [key, value]) => {
160
- acc[key] = value(params, responseData);
161
- return acc;
162
- }, {});
163
- if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`, paramsWithValues);
164
- await queryClient.invalidateQueries({
165
- exact: false,
166
- queryKey: [queryKey, paramsWithValues]
167
- });
168
- }));
169
- }
170
- const mutation = useMutation$1({
171
- mutationFn: options.queryFn,
172
- onSuccess: async (result$1, variables) => {
173
- if (!result$1.isOk()) return;
174
- const data = result$1.value;
175
- if (variables !== void 0 && "params" in variables) {
176
- await onSuccess(data, variables.params);
177
- return;
178
- }
179
- await onSuccess(data, {});
180
- }
181
- });
182
- async function execute(data) {
183
- return await mutation.mutateAsync(data);
184
- }
185
- const result = computed(() => {
186
- if (mutation.isPending.value) return AsyncResult.loading();
187
- if (mutation.isError.value && mutation.error.value) return AsyncResult.err(mutation.error.value);
188
- if (mutation.isSuccess.value && mutation.data.value !== void 0) {
189
- const apiResult = mutation.data.value;
190
- if (apiResult.isOk()) return AsyncResult.ok(apiResult.value);
191
- if (apiResult.isErr()) return AsyncResult.err(apiResult.error);
192
- }
193
- return AsyncResult.loading();
194
- });
195
- return {
196
- isLoading: computed(() => mutation.isPending.value),
197
- data: computed(() => {
198
- if (mutation.data.value?.isOk()) return mutation.data.value.value;
199
- return null;
200
- }),
201
- execute,
202
- result
203
- };
138
+ function isAsyncResult(value) {
139
+ return value instanceof AsyncResultErr || value instanceof AsyncResultLoading || value instanceof AsyncResultOk;
204
140
  }
205
141
 
206
142
  //#endregion
@@ -211,6 +147,34 @@ const QUERY_CONFIG = {
211
147
  prefetchStaleTime: DEFAULT_PREFETCH_STALE_TIME,
212
148
  limit: DEFAULT_LIMIT$3
213
149
  };
150
+ let globalQueryClient = null;
151
+ /**
152
+ * Initialize the API utilities with a QueryClient.
153
+ * Call this once during app setup (e.g. in a plugin or main.ts).
154
+ *
155
+ * After calling this, `createApiUtils()` can be called without options.
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * import { initializeApiUtils } from '@wisemen/vue-core-api-utils'
160
+ *
161
+ * const queryClient = new QueryClient()
162
+ * initializeApiUtils(queryClient)
163
+ *
164
+ * // Then in your api lib:
165
+ * export const { useQuery, useMutation, ... } = createApiUtils<MyQueryKeys>()
166
+ * ```
167
+ */
168
+ function initializeApiUtils(queryClient) {
169
+ globalQueryClient = queryClient;
170
+ }
171
+ /**
172
+ * @internal
173
+ */
174
+ function getQueryClient() {
175
+ if (globalQueryClient == null) throw new Error("[api-utils] QueryClient not available. Call initializeApiUtils(queryClient) before using createApiUtils().");
176
+ return globalQueryClient;
177
+ }
214
178
  function setQueryConfig(config) {
215
179
  if (config.limit != null && config.limit > 0) QUERY_CONFIG.limit = config.limit;
216
180
  if (config.prefetchStaleTime != null && config.prefetchStaleTime > 0) QUERY_CONFIG.prefetchStaleTime = config.prefetchStaleTime;
@@ -228,15 +192,17 @@ function useKeysetInfiniteQuery(options) {
228
192
  staleTime: options.staleTime,
229
193
  enabled: options.isEnabled,
230
194
  getNextPageParam: (lastPage) => {
231
- if (lastPage.isErr()) return null;
232
- return lastPage.value.meta.next ?? null;
195
+ if (lastPage.isErr() || lastPage.isLoading()) return null;
196
+ return lastPage.getValue().meta.next ?? null;
233
197
  },
234
198
  initialPageParam: void 0,
235
199
  placeholderData: (data) => data,
236
- queryFn: ({ pageParam }) => options.queryFn({
237
- key: pageParam,
238
- limit: options.limit ?? DEFAULT_LIMIT$2
239
- }),
200
+ queryFn: async ({ pageParam }) => {
201
+ return AsyncResult.fromResult(await options.queryFn({
202
+ key: pageParam,
203
+ limit: options.limit ?? DEFAULT_LIMIT$2
204
+ }));
205
+ },
240
206
  queryKey: getQueryKey()
241
207
  });
242
208
  const hasError = computed(() => {
@@ -245,10 +211,10 @@ function useKeysetInfiniteQuery(options) {
245
211
  const result = computed(() => {
246
212
  if (infiniteQuery.isLoading.value) return AsyncResult.loading();
247
213
  const firstError = infiniteQuery.data.value?.pages.find((page) => page.isErr());
248
- if (firstError) return AsyncResult.err(firstError.error);
249
- const data = infiniteQuery.data.value?.pages.filter((page) => page.isOk()).flatMap((page) => page.value.data) ?? [];
214
+ if (firstError) return AsyncResult.err(firstError.getError());
215
+ const data = infiniteQuery.data.value?.pages.filter((page) => page.isOk()).flatMap((page) => page.getValue().data) ?? [];
250
216
  const firstPage = infiniteQuery.data.value?.pages[0];
251
- const meta = firstPage?.isOk() ? firstPage.value.meta : { next: null };
217
+ const meta = firstPage?.isOk() ? firstPage.getValue().meta : { next: null };
252
218
  const response = {
253
219
  data,
254
220
  meta: { next: infiniteQuery.hasNextPage.value ? meta.next : null }
@@ -290,17 +256,17 @@ function useOffsetInfiniteQuery(options) {
290
256
  staleTime: options.staleTime,
291
257
  enabled: options.isEnabled,
292
258
  getNextPageParam: (lastPage) => {
293
- if (lastPage.isErr()) return null;
294
- const total = lastPage.value.meta.offset + lastPage.value.meta.limit;
295
- if (total >= lastPage.value.meta.total) return null;
259
+ if (lastPage.isErr() || lastPage.isLoading()) return null;
260
+ const total = lastPage.getValue().meta.offset + lastPage.getValue().meta.limit;
261
+ if (total >= lastPage.getValue().meta.total) return null;
296
262
  return total;
297
263
  },
298
264
  initialPageParam: 0,
299
265
  placeholderData: (data) => data,
300
- queryFn: ({ pageParam }) => options.queryFn({
266
+ queryFn: async ({ pageParam }) => AsyncResult.fromResult(await options.queryFn({
301
267
  limit: options.limit ?? DEFAULT_LIMIT$1,
302
268
  offset: pageParam ?? 0
303
- }),
269
+ })),
304
270
  queryKey: getQueryKey()
305
271
  });
306
272
  const hasError = computed(() => {
@@ -309,10 +275,10 @@ function useOffsetInfiniteQuery(options) {
309
275
  const result = computed(() => {
310
276
  if (infiniteQuery.isLoading.value) return AsyncResult.loading();
311
277
  const firstError = infiniteQuery.data.value?.pages.find((page) => page.isErr());
312
- if (firstError) return AsyncResult.err(firstError.error);
313
- const data = infiniteQuery.data.value?.pages.filter((page) => page.isOk()).flatMap((page) => page.value.data) ?? [];
278
+ if (firstError) return AsyncResult.err(firstError.getError());
279
+ const data = infiniteQuery.data.value?.pages.filter((page) => page.isOk()).flatMap((page) => page.getValue().data) ?? [];
314
280
  const firstPage = infiniteQuery.data.value?.pages[0];
315
- const meta = firstPage?.isOk() ? firstPage.value.meta : null;
281
+ const meta = firstPage?.isOk() ? firstPage.getValue().meta : null;
316
282
  const response = {
317
283
  data,
318
284
  meta: {
@@ -344,62 +310,6 @@ function useOffsetInfiniteQuery(options) {
344
310
  };
345
311
  }
346
312
 
347
- //#endregion
348
- //#region src/composables/query/prefetchQuery.composable.ts
349
- function usePrefetchQuery(query) {
350
- const queryClient = useQueryClient();
351
- function getQueryKey() {
352
- const [first] = Object.entries(query.queryKey);
353
- if (!first) return [];
354
- const [queryKey, params] = first;
355
- return [queryKey, params];
356
- }
357
- async function execute() {
358
- await queryClient.prefetchQuery({
359
- staleTime: query.staleTime ?? QUERY_CONFIG.prefetchStaleTime,
360
- queryFn: query.queryFn,
361
- queryKey: getQueryKey()
362
- });
363
- }
364
- return { execute };
365
- }
366
-
367
- //#endregion
368
- //#region src/composables/query/query.composable.ts
369
- function useQuery(options) {
370
- const isDebug = options.isDebug ?? false;
371
- const query = useQuery$1({
372
- staleTime: options.staleTime,
373
- enabled: options.isEnabled,
374
- placeholderData: (data) => data,
375
- queryFn: async () => {
376
- return AsyncResult.fromResult(await options.queryFn());
377
- },
378
- queryKey: getQueryKey()
379
- });
380
- function getQueryKey() {
381
- const [queryKey, params] = Object.entries(options.queryKey)[0];
382
- if (isDebug) console.debug(`Create query with key ${queryKey}`, params);
383
- return [queryKey, params];
384
- }
385
- async function refetch() {
386
- await query.refetch();
387
- }
388
- return {
389
- isError: computed(() => query.data.value?.isErr() ?? false),
390
- isFetching: computed(() => query.isFetching.value),
391
- isLoading: computed(() => query.isLoading.value),
392
- isSuccess: computed(() => query.data.value?.isOk() ?? false),
393
- refetch,
394
- result: computed(() => {
395
- if (query.isLoading.value) return AsyncResult.loading();
396
- if (query.data.value?.isOk()) return AsyncResult.ok(query.data.value.getValue());
397
- if (query.data.value?.isErr()) return AsyncResult.err(query.data.value.getError());
398
- return AsyncResult.loading();
399
- })
400
- };
401
- }
402
-
403
313
  //#endregion
404
314
  //#region src/factory/createApiInfiniteQueryUtils.ts
405
315
  function createApiInfiniteQueryUtils() {
@@ -431,11 +341,78 @@ function createApiInfiniteQueryUtils() {
431
341
  };
432
342
  }
433
343
 
344
+ //#endregion
345
+ //#region src/composables/mutation/mutation.composable.ts
346
+ function useMutation$1(options) {
347
+ const isDebug = options.isDebug ?? false;
348
+ const queryClient = useQueryClient();
349
+ async function onSuccess(responseData, params) {
350
+ if (!options.queryKeysToInvalidate) return;
351
+ await Promise.all(Object.entries(options.queryKeysToInvalidate).map(async ([queryKey, queryKeyParams]) => {
352
+ if (!queryKeyParams) {
353
+ if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`);
354
+ await queryClient.invalidateQueries({ queryKey: [queryKey] });
355
+ return;
356
+ }
357
+ const qkp = queryKeyParams;
358
+ const paramEntries = Object.entries(qkp);
359
+ if (paramEntries.length === 0) {
360
+ if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`);
361
+ await queryClient.invalidateQueries({ queryKey: [queryKey] });
362
+ return;
363
+ }
364
+ const paramsWithValues = paramEntries.reduce((acc, [key, value]) => {
365
+ acc[key] = value(params, responseData);
366
+ return acc;
367
+ }, {});
368
+ if (isDebug) console.log(`[MUTATION] Invalidating ${queryKey}`, paramsWithValues);
369
+ await queryClient.invalidateQueries({
370
+ exact: false,
371
+ queryKey: [queryKey, paramsWithValues]
372
+ });
373
+ }));
374
+ }
375
+ const mutation = useMutation({
376
+ mutationFn: options.queryFn,
377
+ onSuccess: async (result$1, variables) => {
378
+ if (!result$1.isOk()) return;
379
+ const data = result$1.value;
380
+ if (variables !== void 0 && "params" in variables) {
381
+ await onSuccess(data, variables.params);
382
+ return;
383
+ }
384
+ await onSuccess(data, {});
385
+ }
386
+ });
387
+ async function execute(data) {
388
+ return await mutation.mutateAsync(data);
389
+ }
390
+ const result = computed(() => {
391
+ if (mutation.isPending.value) return AsyncResult.loading();
392
+ if (mutation.isError.value) return AsyncResult.err(mutation.error.value);
393
+ if (mutation.isSuccess.value && mutation.data.value !== void 0) {
394
+ const apiResult = mutation.data.value;
395
+ if (apiResult.isOk()) return AsyncResult.ok(apiResult.value);
396
+ if (apiResult.isErr()) return AsyncResult.err(apiResult.error);
397
+ }
398
+ return AsyncResult.loading();
399
+ });
400
+ return {
401
+ isLoading: computed(() => mutation.isPending.value),
402
+ data: computed(() => {
403
+ if (mutation.data.value?.isOk()) return mutation.data.value.value;
404
+ return null;
405
+ }),
406
+ execute,
407
+ result
408
+ };
409
+ }
410
+
434
411
  //#endregion
435
412
  //#region src/factory/createApiMutationUtils.ts
436
413
  function createApiMutationUtils() {
437
414
  function useMutation$2(options) {
438
- return useMutation({
415
+ return useMutation$1({
439
416
  isDebug: options.isDebug,
440
417
  queryFn: options.queryFn,
441
418
  queryKeysToInvalidate: options.queryKeysToInvalidate ?? {}
@@ -445,11 +422,84 @@ function createApiMutationUtils() {
445
422
  }
446
423
 
447
424
  //#endregion
448
- //#region src/utils/optimisticUpdates.ts
425
+ //#region src/factory/createApiPrefetchInfiniteQueryUtils.ts
426
+ const DEFAULT_LIMIT = QUERY_CONFIG.limit;
427
+ function createApiPrefetchInfiniteQueryUtils() {
428
+ function usePrefetchOffsetInfiniteQuery(key, queryOptions) {
429
+ const queryKey = [key, queryOptions.params ?? {}];
430
+ const queryClient = getQueryClient();
431
+ async function execute() {
432
+ await queryClient.prefetchInfiniteQuery({
433
+ staleTime: queryOptions.staleTime ?? QUERY_CONFIG.prefetchStaleTime,
434
+ getNextPageParam: (lastPage) => {
435
+ if (lastPage.isErr()) return null;
436
+ const total = lastPage.value.meta.offset + lastPage.value.meta.limit;
437
+ if (total >= lastPage.value.meta.total) return null;
438
+ return total;
439
+ },
440
+ initialPageParam: 0,
441
+ queryFn: ({ pageParam }) => queryOptions.queryFn({
442
+ limit: queryOptions.limit ?? DEFAULT_LIMIT,
443
+ offset: pageParam ?? 0
444
+ }),
445
+ queryKey
446
+ });
447
+ }
448
+ return { execute };
449
+ }
450
+ function usePrefetchKeysetInfiniteQuery(key, queryOptions) {
451
+ const queryKey = [key, queryOptions.params ?? {}];
452
+ async function execute() {
453
+ await getQueryClient().prefetchInfiniteQuery({
454
+ staleTime: queryOptions.staleTime ?? QUERY_CONFIG.prefetchStaleTime,
455
+ getNextPageParam: (lastPage) => {
456
+ if (lastPage.isErr()) return null;
457
+ const next = lastPage.value.meta.next;
458
+ if (next === null || next === void 0) return null;
459
+ return next;
460
+ },
461
+ initialPageParam: void 0,
462
+ queryFn: ({ pageParam }) => queryOptions.queryFn({
463
+ key: pageParam,
464
+ limit: queryOptions.limit ?? DEFAULT_LIMIT
465
+ }),
466
+ queryKey
467
+ });
468
+ }
469
+ return { execute };
470
+ }
471
+ return {
472
+ usePrefetchKeysetInfiniteQuery,
473
+ usePrefetchOffsetInfiniteQuery
474
+ };
475
+ }
476
+
477
+ //#endregion
478
+ //#region src/factory/createApiPrefetchQueryUtils.ts
479
+ function createApiPrefetchQueryUtils() {
480
+ function usePrefetchQuery(key, queryOptions) {
481
+ const queryClient = getQueryClient();
482
+ const queryKey = [key, queryOptions.params ?? {}];
483
+ async function execute() {
484
+ await queryClient.prefetchQuery({
485
+ staleTime: queryOptions.staleTime ?? QUERY_CONFIG.prefetchStaleTime,
486
+ queryFn: async () => {
487
+ return AsyncResult.fromResult(await queryOptions.queryFn());
488
+ },
489
+ queryKey
490
+ });
491
+ }
492
+ return { execute };
493
+ }
494
+ return { usePrefetchQuery };
495
+ }
496
+
497
+ //#endregion
498
+ //#region src/utils/query-client/queryClient.ts
449
499
  /**
450
- * OptimisticUpdates utility class for type-safe optimistic updates
500
+ * QueryClient utility class for type-safe query operations
451
501
  */
452
- var OptimisticUpdates = class {
502
+ var QueryClient = class {
453
503
  constructor(queryClient) {
454
504
  this.queryClient = queryClient;
455
505
  }
@@ -457,13 +507,11 @@ var OptimisticUpdates = class {
457
507
  * Extract the raw entity from AsyncResult data
458
508
  */
459
509
  extractEntityFromAsyncResult(data) {
460
- if (data === void 0 || data === null) return null;
461
- if (typeof data === "object" && "isOk" in data) {
462
- const asyncResult = data;
463
- if (asyncResult.isOk()) return asyncResult.getValue();
464
- return null;
465
- }
466
- return data;
510
+ if (data.isOk()) return data.getValue();
511
+ return null;
512
+ }
513
+ hasDataArray(value) {
514
+ return Boolean(value && typeof value === "object" && Array.isArray(value.data));
467
515
  }
468
516
  isInfiniteDataLike(data) {
469
517
  return Boolean(data && typeof data === "object" && "pages" in data && Array.isArray(data.pages));
@@ -471,33 +519,26 @@ var OptimisticUpdates = class {
471
519
  /**
472
520
  * Determine if an item should be updated
473
521
  */
474
- shouldUpdateItem(by, item, value) {
475
- if (typeof by === "function") return by(item);
476
- if (by && typeof by === "object") return Object.entries(by).every(([key, matchValue]) => {
477
- const itemValue = item[key];
478
- return unref(itemValue) === unref(matchValue);
479
- });
480
- const idFromValue = value.id;
481
- const itemId = item["id"];
482
- if (idFromValue !== void 0 && itemId !== void 0) return unref(itemId) === unref(idFromValue);
483
- return false;
522
+ shouldUpdateItem(by, item) {
523
+ return by(item);
484
524
  }
485
525
  /**
486
526
  * Internal method to update entity based on the "by" option
487
527
  */
488
528
  updateEntity(by, currentData, value) {
489
529
  if (Array.isArray(currentData)) return currentData.map((item) => {
490
- return this.shouldUpdateItem(by, item, value) ? {
491
- ...item,
492
- ...value
493
- } : item;
530
+ return this.shouldUpdateItem(by, item) ? value(item) : item;
494
531
  });
495
- if (this.shouldUpdateItem(by, currentData, value)) return {
496
- ...currentData,
497
- ...value
498
- };
532
+ if (this.shouldUpdateItem(by, currentData)) return value(currentData);
499
533
  return currentData;
500
534
  }
535
+ updateInfinitePageValue(by, value, pageValue) {
536
+ if (!this.hasDataArray(pageValue)) return pageValue;
537
+ return {
538
+ ...pageValue,
539
+ data: this.updateEntity(by, pageValue.data, value)
540
+ };
541
+ }
501
542
  /**
502
543
  * Wrap a raw entity in an AsyncResult (preserving ok state)
503
544
  */
@@ -507,11 +548,13 @@ var OptimisticUpdates = class {
507
548
  get(queryKey, options) {
508
549
  if (Array.isArray(queryKey)) {
509
550
  const data = this.queryClient.getQueryData(queryKey);
551
+ if (data == null) return null;
510
552
  return this.extractEntityFromAsyncResult(data);
511
553
  }
512
554
  if (options?.isExact ?? false) {
513
555
  const normalizedKey = [queryKey];
514
556
  const data = this.queryClient.getQueryData(normalizedKey);
557
+ if (data == null) return null;
515
558
  return this.extractEntityFromAsyncResult(data);
516
559
  }
517
560
  const allQueries = this.queryClient.getQueryCache().findAll({ predicate: (query) => {
@@ -544,7 +587,7 @@ var OptimisticUpdates = class {
544
587
  this.queryClient.setQueryData(normalizedKey, wrappedData);
545
588
  }
546
589
  update(keyOrTuple, options) {
547
- const by = options.by ?? void 0;
590
+ const by = options.by;
548
591
  const value = options.value;
549
592
  const isSpecific = Array.isArray(keyOrTuple);
550
593
  const key = isSpecific ? keyOrTuple[0] : keyOrTuple;
@@ -563,19 +606,14 @@ var OptimisticUpdates = class {
563
606
  const updatedInfiniteData = {
564
607
  ...currentData,
565
608
  pages: currentData.pages.map((page) => {
566
- if (page && typeof page === "object" && "map" in page && typeof page.map === "function") return page.map((pageValue) => {
567
- if (pageValue && typeof pageValue === "object" && Array.isArray(pageValue.data)) return {
568
- ...pageValue,
569
- data: this.updateEntity(by, pageValue.data, value)
570
- };
571
- return pageValue;
572
- });
573
- return page;
609
+ if (!isAsyncResult(page)) return page;
610
+ return page.map((pageValue) => this.updateInfinitePageValue(by, value, pageValue));
574
611
  })
575
612
  };
576
613
  this.queryClient.setQueryData(query.queryKey, updatedInfiniteData);
577
614
  continue;
578
615
  }
616
+ if (!isAsyncResult(currentData)) continue;
579
617
  const rawEntity = this.extractEntityFromAsyncResult(currentData);
580
618
  if (rawEntity === null) continue;
581
619
  const updatedEntity = this.updateEntity(by, rawEntity, value);
@@ -584,100 +622,59 @@ var OptimisticUpdates = class {
584
622
  }
585
623
  }
586
624
  };
587
- /**
588
- * Create an OptimisticUpdates instance
589
- */
590
- function createOptimisticUpdates(queryClient) {
591
- return new OptimisticUpdates(queryClient);
592
- }
593
625
 
594
626
  //#endregion
595
- //#region src/factory/createApiOptimisticUpdatesUtils.ts
596
- function createApiOptimisticUpdatesUtils(options) {
597
- function useOptimisticUpdates() {
598
- return new OptimisticUpdates(options.queryClient);
627
+ //#region src/factory/createApiQueryClientUtils.ts
628
+ function createApiQueryClientUtils() {
629
+ function useQueryClient$1() {
630
+ return new QueryClient(getQueryClient());
599
631
  }
600
- return { useOptimisticUpdates };
632
+ return { useQueryClient: useQueryClient$1 };
601
633
  }
602
634
 
603
635
  //#endregion
604
- //#region src/factory/createApiPrefetchInfiniteQueryUtils.ts
605
- const DEFAULT_LIMIT = QUERY_CONFIG.limit;
606
- function createApiPrefetchInfiniteQueryUtils(options) {
607
- function usePrefetchOffsetInfiniteQuery(key, queryOptions) {
608
- const queryKey = [key, queryOptions.params ?? {}];
609
- async function execute() {
610
- await options.queryClient.prefetchInfiniteQuery({
611
- staleTime: queryOptions.staleTime,
612
- getNextPageParam: (lastPage) => {
613
- if (lastPage.isErr()) return null;
614
- const total = lastPage.value.meta.offset + lastPage.value.meta.limit;
615
- if (total >= lastPage.value.meta.total) return null;
616
- return total;
617
- },
618
- initialPageParam: 0,
619
- queryFn: ({ pageParam }) => queryOptions.queryFn({
620
- limit: queryOptions.limit ?? DEFAULT_LIMIT,
621
- offset: pageParam ?? 0
622
- }),
623
- queryKey
624
- });
625
- }
626
- return { execute };
636
+ //#region src/composables/query/query.composable.ts
637
+ function useQuery$1(options) {
638
+ const isDebug = options.isDebug ?? false;
639
+ const query = useQuery({
640
+ staleTime: options.staleTime,
641
+ enabled: options.isEnabled,
642
+ placeholderData: (data) => data,
643
+ queryFn: async () => {
644
+ return AsyncResult.fromResult(await options.queryFn());
645
+ },
646
+ queryKey: getQueryKey()
647
+ });
648
+ function getQueryKey() {
649
+ const [queryKey, params] = Object.entries(options.queryKey)[0];
650
+ if (isDebug) console.debug(`Create query with key ${queryKey}`, params);
651
+ return [queryKey, params];
627
652
  }
628
- function usePrefetchKeysetInfiniteQuery(key, queryOptions) {
629
- const queryKey = [key, queryOptions.params ?? {}];
630
- async function execute() {
631
- await options.queryClient.prefetchInfiniteQuery({
632
- staleTime: queryOptions.staleTime,
633
- getNextPageParam: (lastPage) => {
634
- if (lastPage.isErr()) return null;
635
- const next = lastPage.value.meta.next;
636
- if (next === null || next === void 0) return null;
637
- return next;
638
- },
639
- initialPageParam: void 0,
640
- queryFn: ({ pageParam }) => queryOptions.queryFn({
641
- key: pageParam,
642
- limit: queryOptions.limit ?? DEFAULT_LIMIT
643
- }),
644
- queryKey
645
- });
646
- }
647
- return { execute };
653
+ async function refetch() {
654
+ await query.refetch();
648
655
  }
649
656
  return {
650
- usePrefetchKeysetInfiniteQuery,
651
- usePrefetchOffsetInfiniteQuery
657
+ isError: computed(() => query.data.value?.isErr() ?? false),
658
+ isFetching: computed(() => query.isFetching.value),
659
+ isLoading: computed(() => query.isLoading.value),
660
+ isSuccess: computed(() => query.data.value?.isOk() ?? false),
661
+ refetch,
662
+ result: computed(() => {
663
+ if (query.isLoading.value) return AsyncResult.loading();
664
+ if (query.data.value?.isOk()) return AsyncResult.ok(query.data.value.getValue());
665
+ if (query.data.value?.isErr()) return AsyncResult.err(query.data.value.getError());
666
+ return AsyncResult.loading();
667
+ })
652
668
  };
653
669
  }
654
670
 
655
- //#endregion
656
- //#region src/factory/createApiPrefetchQueryUtils.ts
657
- function createApiPrefetchQueryUtils(options) {
658
- function usePrefetchQuery$1(key, queryOptions) {
659
- const queryKey = [key, queryOptions.params ?? {}];
660
- async function execute() {
661
- await options.queryClient.prefetchQuery({
662
- staleTime: queryOptions.staleTime ?? QUERY_CONFIG.prefetchStaleTime,
663
- queryFn: async () => {
664
- return AsyncResult.fromResult(await queryOptions.queryFn());
665
- },
666
- queryKey
667
- });
668
- }
669
- return { execute };
670
- }
671
- return { usePrefetchQuery: usePrefetchQuery$1 };
672
- }
673
-
674
671
  //#endregion
675
672
  //#region src/factory/createApiQueryUtils.ts
676
673
  function createApiQueryUtils() {
677
674
  function useQuery$2(key, queryOptions) {
678
675
  const params = queryOptions.params ?? {};
679
676
  const queryKey = { [key]: params };
680
- return useQuery({
677
+ return useQuery$1({
681
678
  staleTime: queryOptions.staleTime,
682
679
  isDebug: queryOptions.isDebug,
683
680
  isEnabled: queryOptions.isEnabled,
@@ -692,18 +689,76 @@ function createApiQueryUtils() {
692
689
  //#region src/factory/createApiUtils.ts
693
690
  /**
694
691
  * Factory that creates typed composables based on a user-provided query-keys config.
695
- * This is an alternative to module augmentation of `QueryKeys`.
692
+ *
693
+ * Requires `initializeApiUtils(queryClient)` to be called first.
694
+ *
695
+ * @example
696
+ * ```typescript
697
+ * // In app setup (plugin or main.ts):
698
+ * initializeApiUtils(queryClient)
699
+ *
700
+ * // In your api lib:
701
+ * export const { useQuery, useMutation, useQueryClient } = createApiUtils<MyQueryKeys>()
702
+ * ```
696
703
  */
697
- function createApiUtils(options) {
704
+ function createApiUtils() {
698
705
  return {
699
706
  ...createApiQueryUtils(),
700
- ...createApiPrefetchQueryUtils(options),
701
- ...createApiPrefetchInfiniteQueryUtils(options),
707
+ ...createApiPrefetchQueryUtils(),
708
+ ...createApiPrefetchInfiniteQueryUtils(),
702
709
  ...createApiInfiniteQueryUtils(),
703
710
  ...createApiMutationUtils(),
704
- ...createApiOptimisticUpdatesUtils(options)
711
+ ...createApiQueryClientUtils()
705
712
  };
706
713
  }
707
714
 
708
715
  //#endregion
709
- export { AsyncResult, AsyncResultErr, AsyncResultLoading, AsyncResultOk, OptimisticUpdates, createApiInfiniteQueryUtils, createApiMutationUtils, createApiOptimisticUpdatesUtils, createApiPrefetchInfiniteQueryUtils, createApiPrefetchQueryUtils, createApiQueryUtils, createApiUtils, createOptimisticUpdates, setQueryConfig, useKeysetInfiniteQuery, useMutation, useOffsetInfiniteQuery, usePrefetchQuery, useQuery };
716
+ //#region src/plugin/apiUtilsPlugin.ts
717
+ /**
718
+ * Create a Vue plugin that sets up TanStack Query and initializes API utilities.
719
+ *
720
+ * This plugin handles:
721
+ * - Creating a QueryClient with the provided config
722
+ * - Installing VueQueryPlugin on the app
723
+ * - Initializing the global QueryClient for api-utils
724
+ *
725
+ * @example
726
+ * ```typescript
727
+ * import { apiUtilsPlugin } from '@wisemen/vue-core-api-utils'
728
+ * import { vueQueryClientConfig } from '@wisemen/vue-core-configs'
729
+ *
730
+ * app.use(apiUtilsPlugin(vueQueryClientConfig()))
731
+ * ```
732
+ *
733
+ * @param config - QueryClient configuration
734
+ * @returns A Vue plugin that can be used with app.use()
735
+ */
736
+ function apiUtilsPlugin(config) {
737
+ const queryClient = new QueryClient$1(config);
738
+ return { install: (app) => {
739
+ app.use(VueQueryPlugin, { queryClient });
740
+ initializeApiUtils(queryClient);
741
+ } };
742
+ }
743
+
744
+ //#endregion
745
+ //#region src/types/sort.type.ts
746
+ let SortDirection = /* @__PURE__ */ function(SortDirection$1) {
747
+ SortDirection$1["ASC"] = "asc";
748
+ SortDirection$1["DESC"] = "desc";
749
+ return SortDirection$1;
750
+ }({});
751
+
752
+ //#endregion
753
+ //#region src/utils/sort/sort.utils.ts
754
+ var SortUtil = class {
755
+ static toDto(sort, sortKeyMap) {
756
+ return sort.filter((s) => s.direction !== null).map((s) => ({
757
+ key: sortKeyMap[s.key],
758
+ order: s.direction === SortDirection.ASC ? SortDirection.ASC : SortDirection.DESC
759
+ }));
760
+ }
761
+ };
762
+
763
+ //#endregion
764
+ export { ApiError, ApiErrorObject, ApiExpectedError, ApiKnownErrorObject, ApiResult, ApiUnexpectedError, ApiUnknownErrorObject, AsyncApiResult, AsyncResult, AsyncResultErr, AsyncResultLoading, AsyncResultOk, KeysetPagination, KeysetPaginationParams, KeysetPaginationResponse, KeysetPaginationResult, OffsetPagination, OffsetPaginationParams, OffsetPaginationResponse, OffsetPaginationResult, PaginatedDataDto, QueryClient, QueryClientUpdateOptions, Sort, SortDirection, SortUtil, apiUtilsPlugin, createApiInfiniteQueryUtils, createApiMutationUtils, createApiPrefetchInfiniteQueryUtils, createApiPrefetchQueryUtils, createApiQueryClientUtils, createApiQueryUtils, createApiUtils, getQueryClient as getTanstackQueryClient, initializeApiUtils, setQueryConfig };