{"version":3,"file":"common.mjs","sources":["../../../src/lib/queries/common.ts"],"sourcesContent":["/**\n * @file Common Query Helpers\n * @description General-purpose query helpers shared across features\n */\n\nimport {\n  useQueryClient,\n  type InvalidateQueryFilters,\n  type QueryKey,\n  type QueryState,\n} from '@tanstack/react-query';\nimport { useCallback, useMemo } from 'react';\n\n/**\n * Prefetch query options\n */\nexport interface PrefetchOptions {\n  staleTime?: number;\n  force?: boolean;\n}\n\n/**\n * Hook to prefetch queries on demand\n */\nexport function usePrefetch(): {\n  prefetch: <T>(\n    queryKey: QueryKey,\n    queryFn: () => Promise<T>,\n    options?: PrefetchOptions\n  ) => Promise<void>;\n} {\n  const queryClient = useQueryClient();\n\n  const prefetch = useCallback(\n    async <T>(\n      queryKey: QueryKey,\n      queryFn: () => Promise<T>,\n      options?: PrefetchOptions\n    ): Promise<void> => {\n      const { staleTime = 5 * 60 * 1000, force = false } = options ?? {};\n\n      if (force) {\n        await queryClient.fetchQuery({\n          queryKey,\n          queryFn,\n          staleTime,\n        });\n      } else {\n        await queryClient.prefetchQuery({\n          queryKey,\n          queryFn,\n          staleTime,\n        });\n      }\n    },\n    [queryClient]\n  );\n\n  return { prefetch };\n}\n\n/**\n * Hook to invalidate queries by pattern\n */\nexport function useInvalidateQueries(): {\n  invalidate: (filters: InvalidateQueryFilters) => Promise<void>;\n  invalidateAll: () => Promise<void>;\n  invalidateByKey: (queryKey: QueryKey) => Promise<void>;\n} {\n  const queryClient = useQueryClient();\n\n  const invalidate = useCallback(\n    async (filters: InvalidateQueryFilters) => {\n      await queryClient.invalidateQueries(filters);\n    },\n    [queryClient]\n  );\n\n  const invalidateAll = useCallback(async () => {\n    await queryClient.invalidateQueries();\n  }, [queryClient]);\n\n  const invalidateByKey = useCallback(\n    async (queryKey: QueryKey) => {\n      await queryClient.invalidateQueries({ queryKey });\n    },\n    [queryClient]\n  );\n\n  return {\n    invalidate,\n    invalidateAll,\n    invalidateByKey,\n  };\n}\n\n/**\n * Hook to get query state information\n */\nexport function useQueryState<T>(queryKey: QueryKey): {\n  state: QueryState<T, Error> | undefined;\n  data: T | undefined;\n  isLoading: boolean;\n  isError: boolean;\n  isSuccess: boolean;\n  isPending: boolean;\n} {\n  const queryClient = useQueryClient();\n\n  const state = useMemo(() => {\n    return queryClient.getQueryState<T>(queryKey);\n  }, [queryClient, queryKey]);\n\n  const data = useMemo(() => {\n    return queryClient.getQueryData<T>(queryKey);\n  }, [queryClient, queryKey]);\n\n  const isLoading = state?.fetchStatus === 'fetching';\n  const isError = state?.status === 'error';\n  const isSuccess = state?.status === 'success';\n  const isPending = state?.status === 'pending';\n\n  return {\n    state,\n    data,\n    isLoading,\n    isError,\n    isSuccess,\n    isPending,\n  };\n}\n\n/**\n * Hook to manage optimistic updates\n */\nexport function useOptimisticUpdate<T>(): {\n  update: <R>(\n    queryKey: QueryKey,\n    updateFn: (old: T | undefined) => T,\n    mutationFn: () => Promise<R>,\n    options?: {\n      onError?: (error: Error, previousData: T | undefined) => void;\n      onSuccess?: (result: R) => void;\n    }\n  ) => Promise<R>;\n} {\n  const queryClient = useQueryClient();\n\n  const update = useCallback(\n    async <R>(\n      queryKey: QueryKey,\n      updateFn: (old: T | undefined) => T,\n      mutationFn: () => Promise<R>,\n      options?: {\n        onError?: (error: Error, previousData: T | undefined) => void;\n        onSuccess?: (result: R) => void;\n      }\n    ) => {\n      // Cancel outgoing refetches\n      await queryClient.cancelQueries({ queryKey });\n\n      // Snapshot previous value\n      const previousData = queryClient.getQueryData<T>(queryKey);\n\n      // Optimistically update\n      queryClient.setQueryData<T>(queryKey, updateFn);\n\n      try {\n        const result = await mutationFn();\n        options?.onSuccess?.(result);\n        return result;\n      } catch (error) {\n        // Rollback on error\n        queryClient.setQueryData<T>(queryKey, previousData);\n        options?.onError?.(error as Error, previousData);\n        throw error;\n      }\n    },\n    [queryClient]\n  );\n\n  return { update };\n}\n\n/**\n * Merge paginated data helper\n */\nexport function mergePaginatedData<T extends { id: string }>(\n  existing: T[] | undefined,\n  incoming: T[]\n): T[] {\n  if (!existing) return incoming;\n\n  const existingMap = new Map(existing.map((item) => [item.id, item]));\n\n  incoming.forEach((item) => {\n    existingMap.set(item.id, item);\n  });\n\n  return Array.from(existingMap.values());\n}\n\n/**\n * Infinite query page merger\n */\nexport function mergeInfinitePages<T>(pages: T[][], newPage: T[], pageIndex: number): T[][] {\n  const result = [...pages];\n  result[pageIndex] = newPage;\n  return result;\n}\n\n/**\n * Query retry delay calculator (exponential backoff)\n */\nexport function calculateRetryDelay(attemptIndex: number): number {\n  const baseDelay = 1000;\n  const maxDelay = 30000;\n  const delay = Math.min(baseDelay * Math.pow(2, attemptIndex), maxDelay);\n  // Add jitter\n  return delay + Math.random() * 1000;\n}\n\n/**\n * Check if query data is stale\n */\nexport function isQueryStale(\n  state: QueryState<unknown, Error> | undefined,\n  staleTime: number\n): boolean {\n  if (state?.dataUpdatedAt == null || state.dataUpdatedAt === 0) return true;\n  return Date.now() - state.dataUpdatedAt > staleTime;\n}\n\n/**\n * Create a typed query key factory\n */\nexport function createQueryKeyFactory<T extends Record<string, unknown>>(\n  scope: string\n): {\n  all: readonly [string];\n  lists: () => readonly [string, 'list'];\n  list: (filters?: T) => readonly [string, 'list', T | undefined];\n  details: () => readonly [string, 'detail'];\n  detail: (id: string) => readonly [string, 'detail', string];\n} {\n  return {\n    all: [scope] as const,\n    lists: () => [scope, 'list'] as const,\n    list: (filters?: T) => [scope, 'list', filters] as const,\n    details: () => [scope, 'detail'] as const,\n    detail: (id: string) => [scope, 'detail', id] as const,\n  };\n}\n\n/**\n * Batch query updates for performance\n */\nexport function useBatchQueryUpdates(): {\n  batchUpdate: (updates: Array<{ queryKey: QueryKey; data: unknown }>) => void;\n} {\n  const queryClient = useQueryClient();\n\n  const batchUpdate = useCallback(\n    (updates: Array<{ queryKey: QueryKey; data: unknown }>) => {\n      queryClient.setQueriesData({ predicate: () => true }, (oldData: unknown) => {\n        const update = updates.find((u) => JSON.stringify(u.queryKey) === JSON.stringify(oldData));\n        return update ? update.data : oldData;\n      });\n    },\n    [queryClient]\n  );\n\n  return { batchUpdate };\n}\n"],"names":["usePrefetch","queryClient","useQueryClient","useCallback","queryKey","queryFn","options","staleTime","force","useInvalidateQueries","invalidate","filters","invalidateAll","invalidateByKey","useQueryState","state","useMemo","data","isLoading","isError","isSuccess","isPending","useOptimisticUpdate","updateFn","mutationFn","previousData","result","error","mergePaginatedData","existing","incoming","existingMap","item","mergeInfinitePages","pages","newPage","pageIndex","calculateRetryDelay","attemptIndex","isQueryStale","createQueryKeyFactory","scope","id","useBatchQueryUpdates","updates","oldData","update","u"],"mappings":";;AAwBO,SAASA,IAMd;AACA,QAAMC,IAAcC,EAAA;AA2BpB,SAAO,EAAE,UAzBQC;AAAA,IACf,OACEC,GACAC,GACAC,MACkB;AAClB,YAAM,EAAE,WAAAC,IAAY,MAAS,KAAM,OAAAC,IAAQ,OAAUF,KAAW,CAAA;AAEhE,MAAIE,IACF,MAAMP,EAAY,WAAW;AAAA,QAC3B,UAAAG;AAAA,QACA,SAAAC;AAAA,QACA,WAAAE;AAAA,MAAA,CACD,IAED,MAAMN,EAAY,cAAc;AAAA,QAC9B,UAAAG;AAAA,QACA,SAAAC;AAAA,QACA,WAAAE;AAAA,MAAA,CACD;AAAA,IAEL;AAAA,IACA,CAACN,CAAW;AAAA,EAAA,EAGL;AACX;AAKO,SAASQ,IAId;AACA,QAAMR,IAAcC,EAAA,GAEdQ,IAAaP;AAAA,IACjB,OAAOQ,MAAoC;AACzC,YAAMV,EAAY,kBAAkBU,CAAO;AAAA,IAC7C;AAAA,IACA,CAACV,CAAW;AAAA,EAAA,GAGRW,IAAgBT,EAAY,YAAY;AAC5C,UAAMF,EAAY,kBAAA;AAAA,EACpB,GAAG,CAACA,CAAW,CAAC,GAEVY,IAAkBV;AAAA,IACtB,OAAOC,MAAuB;AAC5B,YAAMH,EAAY,kBAAkB,EAAE,UAAAG,GAAU;AAAA,IAClD;AAAA,IACA,CAACH,CAAW;AAAA,EAAA;AAGd,SAAO;AAAA,IACL,YAAAS;AAAA,IACA,eAAAE;AAAA,IACA,iBAAAC;AAAA,EAAA;AAEJ;AAKO,SAASC,EAAiBV,GAO/B;AACA,QAAMH,IAAcC,EAAA,GAEda,IAAQC,EAAQ,MACbf,EAAY,cAAiBG,CAAQ,GAC3C,CAACH,GAAaG,CAAQ,CAAC,GAEpBa,IAAOD,EAAQ,MACZf,EAAY,aAAgBG,CAAQ,GAC1C,CAACH,GAAaG,CAAQ,CAAC,GAEpBc,IAAYH,GAAO,gBAAgB,YACnCI,IAAUJ,GAAO,WAAW,SAC5BK,IAAYL,GAAO,WAAW,WAC9BM,IAAYN,GAAO,WAAW;AAEpC,SAAO;AAAA,IACL,OAAAA;AAAA,IACA,MAAAE;AAAA,IACA,WAAAC;AAAA,IACA,SAAAC;AAAA,IACA,WAAAC;AAAA,IACA,WAAAC;AAAA,EAAA;AAEJ;AAKO,SAASC,IAUd;AACA,QAAMrB,IAAcC,EAAA;AAmCpB,SAAO,EAAE,QAjCMC;AAAA,IACb,OACEC,GACAmB,GACAC,GACAlB,MAIG;AAEH,YAAML,EAAY,cAAc,EAAE,UAAAG,GAAU;AAG5C,YAAMqB,IAAexB,EAAY,aAAgBG,CAAQ;AAGzD,MAAAH,EAAY,aAAgBG,GAAUmB,CAAQ;AAE9C,UAAI;AACF,cAAMG,IAAS,MAAMF,EAAA;AACrB,eAAAlB,GAAS,YAAYoB,CAAM,GACpBA;AAAA,MACT,SAASC,GAAO;AAEd,cAAA1B,EAAY,aAAgBG,GAAUqB,CAAY,GAClDnB,GAAS,UAAUqB,GAAgBF,CAAY,GACzCE;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC1B,CAAW;AAAA,EAAA,EAGL;AACX;AAKO,SAAS2B,EACdC,GACAC,GACK;AACL,MAAI,CAACD,EAAU,QAAOC;AAEtB,QAAMC,IAAc,IAAI,IAAIF,EAAS,IAAI,CAACG,MAAS,CAACA,EAAK,IAAIA,CAAI,CAAC,CAAC;AAEnE,SAAAF,EAAS,QAAQ,CAACE,MAAS;AACzB,IAAAD,EAAY,IAAIC,EAAK,IAAIA,CAAI;AAAA,EAC/B,CAAC,GAEM,MAAM,KAAKD,EAAY,OAAA,CAAQ;AACxC;AAKO,SAASE,EAAsBC,GAAcC,GAAcC,GAA0B;AAC1F,QAAMV,IAAS,CAAC,GAAGQ,CAAK;AACxB,SAAAR,EAAOU,CAAS,IAAID,GACbT;AACT;AAKO,SAASW,EAAoBC,GAA8B;AAKhE,SAFc,KAAK,IAAI,MAAY,KAAK,IAAI,GAAGA,CAAY,GAAG,GAAQ,IAEvD,KAAK,OAAA,IAAW;AACjC;AAKO,SAASC,EACdxB,GACAR,GACS;AACT,SAAIQ,GAAO,iBAAiB,QAAQA,EAAM,kBAAkB,IAAU,KAC/D,KAAK,IAAA,IAAQA,EAAM,gBAAgBR;AAC5C;AAKO,SAASiC,EACdC,GAOA;AACA,SAAO;AAAA,IACL,KAAK,CAACA,CAAK;AAAA,IACX,OAAO,MAAM,CAACA,GAAO,MAAM;AAAA,IAC3B,MAAM,CAAC9B,MAAgB,CAAC8B,GAAO,QAAQ9B,CAAO;AAAA,IAC9C,SAAS,MAAM,CAAC8B,GAAO,QAAQ;AAAA,IAC/B,QAAQ,CAACC,MAAe,CAACD,GAAO,UAAUC,CAAE;AAAA,EAAA;AAEhD;AAKO,SAASC,IAEd;AACA,QAAM1C,IAAcC,EAAA;AAYpB,SAAO,EAAE,aAVWC;AAAA,IAClB,CAACyC,MAA0D;AACzD,MAAA3C,EAAY,eAAe,EAAE,WAAW,MAAM,GAAA,GAAQ,CAAC4C,MAAqB;AAC1E,cAAMC,IAASF,EAAQ,KAAK,CAACG,MAAM,KAAK,UAAUA,EAAE,QAAQ,MAAM,KAAK,UAAUF,CAAO,CAAC;AACzF,eAAOC,IAASA,EAAO,OAAOD;AAAA,MAChC,CAAC;AAAA,IACH;AAAA,IACA,CAAC5C,CAAW;AAAA,EAAA,EAGL;AACX;"}