{"version":3,"file":"optimistic-mutations.mjs","sources":["../../../src/lib/services/optimistic-mutations.ts"],"sourcesContent":["/**\n * @file Optimistic Mutations\n * @description Production-grade optimistic update patterns with multi-query rollback,\n * conflict resolution, offline support, and queue management.\n * Designed for seamless UX during mutations.\n */\n\nimport {\n  type QueryClient,\n  type QueryKey,\n  useMutation,\n  useQueryClient,\n  type UseMutationOptions,\n  type MutationFunction,\n} from '@tanstack/react-query';\nimport { useCallback, useRef, useMemo } from 'react';\n\n// =============================================================================\n// TYPE DEFINITIONS\n// =============================================================================\n\n/**\n * Snapshot of query data for rollback\n */\nexport interface QuerySnapshot<T = unknown> {\n  /** Query key */\n  queryKey: QueryKey;\n  /** Snapshotted data */\n  data: T | undefined;\n  /** Snapshot timestamp */\n  timestamp: number;\n  /** Data version/etag if available */\n  version?: string;\n}\n\n/**\n * Optimistic mutation context\n */\nexport interface OptimisticContext<T = unknown> {\n  /** Query snapshots for rollback */\n  snapshots: QuerySnapshot<T>[];\n  /** The optimistic data applied */\n  optimisticData?: T;\n  /** Rollback function */\n  rollbackFn: () => void;\n  /** Mutation ID */\n  mutationId: string;\n  /** Start timestamp */\n  startTime: number;\n}\n\n/**\n * Conflict resolution strategy\n */\nexport type ConflictStrategy = 'server-wins' | 'client-wins' | 'merge' | 'manual';\n\n/**\n * Conflict resolution context\n */\nexport interface ConflictContext<T> {\n  /** Server response data */\n  serverData: T;\n  /** Client optimistic data */\n  clientData: T | undefined;\n  /** Original data before mutation */\n  originalData: T | undefined;\n  /** Query key */\n  queryKey: QueryKey;\n}\n\n/**\n * Optimistic update configuration\n */\nexport interface OptimisticUpdateConfig<TData, TVariables, TContext = unknown> {\n  /** Query keys to update optimistically */\n  queryKeys: QueryKey[] | ((variables: TVariables) => QueryKey[]);\n\n  /** Generate optimistic data from variables */\n  getOptimisticData: (variables: TVariables, currentData: TData | undefined) => TData;\n\n  /** Handle successful mutation */\n  onSuccess?: (data: TData, variables: TVariables, context: OptimisticContext<TData>) => void;\n\n  /** Handle mutation error with rollback */\n  onError?: (error: Error, variables: TVariables, context: OptimisticContext<TData>) => void;\n\n  /** Custom rollback logic */\n  customRollback?: (snapshots: QuerySnapshot<TData>[], queryClient: QueryClient) => void;\n\n  /** Conflict resolution strategy */\n  conflictStrategy?: ConflictStrategy;\n\n  /** Custom merge function for 'merge' strategy */\n  mergeFn?: (context: ConflictContext<TData>) => TData;\n\n  /** Manual conflict resolution handler */\n  onConflict?: (context: ConflictContext<TData>) => TData | Promise<TData>;\n\n  /** Enable offline optimistic updates */\n  offlineSupport?: boolean;\n\n  /** Retry failed mutations when back online */\n  retryOnReconnect?: boolean;\n\n  /** Custom context generator */\n  getContext?: TContext;\n}\n\n// =============================================================================\n// OPTIMISTIC MUTATION HOOK\n// =============================================================================\n\n/**\n * Create optimistic mutation hook with advanced features\n */\nexport function useOptimisticMutation<TData = unknown, TError = Error, TVariables = void>(\n  mutationFn: MutationFunction<TData, TVariables>,\n  config: OptimisticUpdateConfig<TData, TVariables>,\n  options?: Omit<\n    UseMutationOptions<TData, TError, TVariables, OptimisticContext<TData>>,\n    'mutationFn' | 'onMutate' | 'onError' | 'onSuccess' | 'onSettled'\n  >\n): ReturnType<typeof useMutation<TData, TError, TVariables, OptimisticContext<TData>>> {\n  const queryClient = useQueryClient();\n  const pendingMutationsRef = useRef<Map<string, OptimisticContext<TData>>>(new Map());\n\n  return useMutation<TData, TError, TVariables, OptimisticContext<TData>>({\n    mutationFn,\n\n    onMutate: async (variables): Promise<OptimisticContext<TData>> => {\n      const mutationId = crypto.randomUUID();\n      const startTime = Date.now();\n\n      // Get query keys to update\n      const queryKeys = typeof config.queryKeys === 'function' ? config.queryKeys(variables) : config.queryKeys;\n\n      // Cancel any outgoing refetches to prevent race conditions\n      await Promise.all(queryKeys.map(async (key) => queryClient.cancelQueries({ queryKey: key })));\n\n      // Snapshot current data for all affected queries\n      const snapshots: QuerySnapshot<TData>[] = queryKeys.map((queryKey) => ({\n        queryKey,\n        data: queryClient.getQueryData<TData>(queryKey),\n        timestamp: startTime,\n      }));\n\n      // Apply optimistic updates to all queries\n      for (const snapshot of snapshots) {\n        const optimisticData = config.getOptimisticData(variables, snapshot.data);\n        queryClient.setQueryData<TData>(snapshot.queryKey, optimisticData);\n      }\n\n      // Create rollback function\n      const rollbackFn = (): void => {\n        for (const snapshot of snapshots) {\n          queryClient.setQueryData(snapshot.queryKey, snapshot.data);\n        }\n      };\n\n      // Store context for potential rollback\n      const context: OptimisticContext<TData> = {\n        snapshots,\n        rollbackFn,\n        mutationId,\n        startTime,\n      };\n\n      pendingMutationsRef.current.set(mutationId, context);\n\n      return context;\n    },\n\n    onError: (error, variables, context) => {\n      if (context == null) return;\n\n      // Execute rollback\n      if (config.customRollback) {\n        config.customRollback(context.snapshots, queryClient);\n      } else {\n        context.rollbackFn();\n      }\n\n      // Notify error handler\n      config.onError?.(error as Error, variables, context);\n\n      // Clean up\n      pendingMutationsRef.current.delete(context.mutationId);\n    },\n\n    onSuccess: async (data, variables, context) => {\n      if (context == null) return;\n\n      // Handle conflict resolution based on strategy\n      for (const snapshot of context.snapshots) {\n        const currentData = queryClient.getQueryData<TData>(snapshot.queryKey);\n\n        const conflictContext: ConflictContext<TData> = {\n          serverData: data,\n          clientData: currentData,\n          originalData: snapshot.data,\n          queryKey: snapshot.queryKey,\n        };\n\n        let finalData: TData;\n\n        switch (config.conflictStrategy) {\n          case 'server-wins':\n            finalData = data;\n            break;\n\n          case 'merge':\n            if (config.mergeFn) {\n              finalData = config.mergeFn(conflictContext);\n            } else {\n              // Default merge: shallow merge server into client\n              finalData =\n                data !== null && typeof data === 'object'\n                  ? ({ ...currentData, ...data } as TData)\n                  : data;\n            }\n            break;\n\n          case 'manual':\n            if (config.onConflict) {\n              finalData = await config.onConflict(conflictContext);\n            } else {\n              finalData = data;\n            }\n            break;\n\n          case 'client-wins':\n          default:\n            // Keep optimistic data, just invalidate for freshness\n            void queryClient.invalidateQueries({ queryKey: snapshot.queryKey });\n            continue;\n        }\n\n        queryClient.setQueryData(snapshot.queryKey, finalData);\n      }\n\n      config.onSuccess?.(data, variables, context);\n\n      // Clean up\n      pendingMutationsRef.current.delete(context.mutationId);\n    },\n\n    onSettled: () => {\n      // Additional cleanup if needed\n    },\n\n    ...options,\n  });\n}\n\n// =============================================================================\n// LIST OPTIMISTIC UPDATE HELPERS\n// =============================================================================\n\n/**\n * List item with required ID\n */\nexport interface ListItem {\n  id: string;\n}\n\n/**\n * List response structure\n */\nexport interface ListResponse<T extends ListItem> {\n  items: T[];\n  total?: number;\n}\n\n/**\n * Create optimistic update helpers for list operations\n */\nexport function createListOptimisticUpdates<TItem extends ListItem, TList extends ListResponse<TItem>>(): {\n  addItem: (list: TList | undefined, newItem: TItem, position?: 'start' | 'end') => TList;\n  updateItem: (list: TList | undefined, id: string, updates: Partial<TItem>) => TList;\n  removeItem: (list: TList | undefined, id: string) => TList;\n  reorderItems: (list: TList | undefined, fromIndex: number, toIndex: number) => TList;\n  moveItem: (list: TList | undefined, id: string, toIndex: number) => TList;\n  replaceList: (list: TList | undefined, newItems: TItem[]) => TList;\n  findItem: (list: TList | undefined, id: string) => TItem | undefined;\n  hasItem: (list: TList | undefined, id: string) => boolean;\n} {\n  return {\n    /**\n     * Optimistically add item to list\n     */\n    addItem: (list: TList | undefined, newItem: TItem, position: 'start' | 'end' = 'end'): TList => {\n      if (!list) {\n        return { items: [newItem], total: 1 } as TList;\n      }\n      return {\n        ...list,\n        items: position === 'start' ? [newItem, ...list.items] : [...list.items, newItem],\n        total: (list.total ?? list.items.length) + 1,\n      };\n    },\n\n    /**\n     * Optimistically update item in list\n     * @returns The updated list, or an empty list structure if input is undefined\n     */\n    updateItem: (list: TList | undefined, id: string, updates: Partial<TItem>): TList => {\n      if (!list) {\n        return { items: [], total: 0 } as unknown as TList;\n      }\n      return {\n        ...list,\n        items: list.items.map((item) => (item.id === id ? { ...item, ...updates } : item)),\n      };\n    },\n\n    /**\n     * Optimistically remove item from list\n     * @returns The updated list, or an empty list structure if input is undefined\n     */\n    removeItem: (list: TList | undefined, id: string): TList => {\n      if (!list) {\n        return { items: [], total: 0 } as unknown as TList;\n      }\n      return {\n        ...list,\n        items: list.items.filter((item) => item.id !== id),\n        total: Math.max(0, (list.total ?? list.items.length) - 1),\n      };\n    },\n\n    /**\n     * Optimistically reorder items in list\n     * @returns The reordered list, or an empty list structure if input is undefined\n     */\n    reorderItems: (list: TList | undefined, fromIndex: number, toIndex: number): TList => {\n      if (!list) {\n        return { items: [], total: 0 } as unknown as TList;\n      }\n      const items = [...list.items];\n      const [removed] = items.splice(fromIndex, 1);\n      if (removed !== undefined) {\n        items.splice(toIndex, 0, removed);\n      }\n      return { ...list, items };\n    },\n\n    /**\n     * Optimistically move item by ID\n     * @returns The updated list, or an empty list structure if input is undefined\n     */\n    moveItem: (list: TList | undefined, id: string, toIndex: number): TList => {\n      if (!list) {\n        return { items: [], total: 0 } as unknown as TList;\n      }\n      const fromIndex = list.items.findIndex((item) => item.id === id);\n      if (fromIndex === -1) return list;\n      const items = [...list.items];\n      const [removed] = items.splice(fromIndex, 1);\n      if (removed !== undefined) {\n        items.splice(toIndex, 0, removed);\n      }\n      return { ...list, items };\n    },\n\n    /**\n     * Optimistically replace entire list\n     */\n    replaceList: (list: TList | undefined, newItems: TItem[]): TList => {\n      return {\n        ...(list ?? {}),\n        items: newItems,\n        total: newItems.length,\n      } as TList;\n    },\n\n    /**\n     * Find item by ID\n     */\n    findItem: (list: TList | undefined, id: string): TItem | undefined => {\n      return list?.items.find((item) => item.id === id);\n    },\n\n    /**\n     * Check if item exists\n     */\n    hasItem: (list: TList | undefined, id: string): boolean => {\n      return list?.items.some((item) => item.id === id) ?? false;\n    },\n  };\n}\n\n// =============================================================================\n// OFFLINE MUTATION QUEUE\n// =============================================================================\n\n/**\n * Queued mutation entry\n */\nexport interface QueuedMutation<TVariables = unknown> {\n  id: string;\n  mutationFn: () => Promise<unknown>;\n  rollbackFn: () => void;\n  variables: TVariables;\n  timestamp: number;\n  retries: number;\n  maxRetries: number;\n  status: 'pending' | 'processing' | 'failed';\n}\n\n/**\n * Mutation queue configuration\n */\nexport interface MutationQueueConfig {\n  /** Maximum retry attempts */\n  maxRetries?: number;\n  /** Retry delay (ms) */\n  retryDelay?: number;\n  /** Persist queue to storage */\n  persist?: boolean;\n  /** Storage key for persistence */\n  storageKey?: string;\n  /** Callback when mutation succeeds */\n  onSuccess?: (mutation: QueuedMutation) => void;\n  /** Callback when mutation fails permanently */\n  onFailure?: (mutation: QueuedMutation, error: Error) => void;\n  /** Callback when queue status changes */\n  onStatusChange?: (status: QueueStatus) => void;\n}\n\n/**\n * Queue status\n */\nexport interface QueueStatus {\n  pending: number;\n  processing: boolean;\n  online: boolean;\n  failed: number;\n  lastSync?: number;\n}\n\n/**\n * Optimistic mutation queue for offline support\n */\nexport class OptimisticMutationQueue {\n  private queue: QueuedMutation[] = [];\n  private processing = false;\n  private config: Required<MutationQueueConfig>;\n  private readonly onlineHandler?: () => void;\n\n  constructor(config: MutationQueueConfig = {}) {\n    this.config = {\n      maxRetries: config.maxRetries ?? 3,\n      retryDelay: config.retryDelay ?? 1000,\n      persist: config.persist ?? true,\n      storageKey: config.storageKey ?? 'optimistic_mutation_queue',\n      onSuccess: config.onSuccess ?? (() => {}),\n      onFailure: config.onFailure ?? (() => {}),\n      onStatusChange: config.onStatusChange ?? (() => {}),\n    };\n\n    // Load persisted queue\n    if (this.config.persist) {\n      this.loadFromStorage();\n    }\n\n    // Listen for online status\n    if (typeof window !== 'undefined') {\n      this.onlineHandler = (): void => {\n        void this.process();\n      };\n      window.addEventListener('online', this.onlineHandler);\n    }\n  }\n\n  /**\n   * Add mutation to queue\n   */\n  add<TVariables>(\n    mutationFn: () => Promise<unknown>,\n    rollbackFn: () => void,\n    variables: TVariables\n  ): string {\n    const id = crypto.randomUUID();\n\n    this.queue.push({\n      id,\n      mutationFn,\n      rollbackFn,\n      variables,\n      timestamp: Date.now(),\n      retries: 0,\n      maxRetries: this.config.maxRetries,\n      status: 'pending',\n    });\n\n    this.persist();\n    this.notifyStatusChange();\n\n    // Try to process immediately\n    void this.process();\n\n    return id;\n  }\n\n  /**\n   * Remove mutation from queue\n   */\n  remove(id: string): boolean {\n    const index = this.queue.findIndex((m) => m.id === id);\n    if (index === -1) return false;\n\n    this.queue.splice(index, 1);\n    this.persist();\n    this.notifyStatusChange();\n    return true;\n  }\n\n  /**\n   * Process queued mutations\n   */\n  async process(): Promise<void> {\n    if (this.processing || this.queue.length === 0) return;\n    if (typeof navigator !== 'undefined' && !navigator.onLine) return;\n\n    this.processing = true;\n    this.notifyStatusChange();\n\n    while (this.queue.length > 0 && (typeof navigator === 'undefined' || navigator.onLine)) {\n      const mutation = this.queue.shift();\n      if (!mutation) break;\n      \n      mutation.status = 'processing';\n      this.persist();\n\n      try {\n        await mutation.mutationFn();\n        this.queue.shift();\n        this.persist();\n        this.config.onSuccess(mutation);\n      } catch (error) {\n        mutation.retries++;\n        mutation.status = 'pending';\n\n        if (mutation.retries >= mutation.maxRetries) {\n          // Rollback and remove from queue\n          mutation.rollbackFn();\n          this.queue.shift();\n          this.persist();\n          this.config.onFailure(mutation, error as Error);\n        } else {\n          // Wait before retry with exponential backoff\n          await new Promise((r) => setTimeout(r, this.config.retryDelay * Math.pow(2, mutation.retries - 1)));\n        }\n      }\n    }\n\n    this.processing = false;\n    this.notifyStatusChange();\n  }\n\n  /**\n   * Rollback all pending mutations\n   */\n  rollbackAll(): void {\n    for (const mutation of this.queue) {\n      try {\n        mutation.rollbackFn();\n      } catch (error) {\n        console.error('Rollback failed:', error);\n      }\n    }\n    this.queue = [];\n    this.persist();\n    this.notifyStatusChange();\n  }\n\n  /**\n   * Get queue status\n   */\n  getStatus(): QueueStatus {\n    return {\n      pending: this.queue.filter(m => m.status === 'pending').length,\n      processing: this.processing,\n      online: typeof navigator === 'undefined' || navigator.onLine,\n      failed: this.queue.filter(m => m.status === 'failed').length,\n    };\n  }\n\n  /**\n   * Get all queued mutations\n   */\n  getQueue(): QueuedMutation[] {\n    return [...this.queue];\n  }\n\n  /**\n   * Clean up\n   */\n  destroy(): void {\n    if (this.onlineHandler && typeof window !== 'undefined') {\n      window.removeEventListener('online', this.onlineHandler);\n    }\n  }\n\n  /**\n   * Persist queue to storage\n   */\n  private persist(): void {\n    if (!this.config.persist) return;\n\n    try {\n      // Only persist serializable data\n      const persistable = this.queue.map(({ id, variables, timestamp, retries, maxRetries, status }) => ({\n        id,\n        variables,\n        timestamp,\n        retries,\n        maxRetries,\n        status,\n      }));\n      localStorage.setItem(this.config.storageKey, JSON.stringify(persistable));\n    } catch {\n      // Storage may be unavailable\n    }\n  }\n\n  /**\n   * Load queue from storage\n   */\n  private loadFromStorage(): void {\n    try {\n      const stored = localStorage.getItem(this.config.storageKey);\n      if (stored !== null && stored !== '') {\n        // Note: Functions cannot be restored, so persisted mutations\n        // need to be re-registered by the application\n        console.info('[MutationQueue] Loaded queue metadata:', JSON.parse(stored));\n      }\n    } catch {\n      // Storage may be unavailable\n    }\n  }\n\n  /**\n   * Notify status change\n   */\n  private notifyStatusChange(): void {\n    this.config.onStatusChange(this.getStatus());\n  }\n}\n\n// =============================================================================\n// REACT HOOKS FOR MUTATION QUEUE\n// =============================================================================\n\nexport interface MutationQueueStatus {\n  pending: number;\n  processing: boolean;\n  failed: number;\n}\n\n/**\n * Hook to use the optimistic mutation queue\n */\nexport function useMutationQueue(config?: MutationQueueConfig): {\n  add: <TVariables>(mutationFn: () => Promise<unknown>, rollbackFn: () => void, variables: TVariables) => string;\n  remove: (id: string) => boolean;\n  process: () => Promise<void>;\n  rollbackAll: () => void;\n  getStatus: () => MutationQueueStatus;\n} {\n  const queueRef = useRef<OptimisticMutationQueue | null>(null);\n\n  queueRef.current ??= new OptimisticMutationQueue(config);\n\n  const add = useCallback(\n    <TVariables>(mutationFn: () => Promise<unknown>, rollbackFn: () => void, variables: TVariables) => {\n      if (!queueRef.current) throw new Error('Queue not initialized');\n      return queueRef.current.add(mutationFn, rollbackFn, variables);\n    },\n    []\n  );\n\n  const remove = useCallback((id: string) => {\n    if (!queueRef.current) throw new Error('Queue not initialized');\n    return queueRef.current.remove(id);\n  }, []);\n\n  const process = useCallback(async () => {\n    if (!queueRef.current) throw new Error('Queue not initialized');\n    return queueRef.current.process();\n  }, []);\n\n  const rollbackAll = useCallback(() => {\n    if (!queueRef.current) throw new Error('Queue not initialized');\n    return queueRef.current.rollbackAll();\n  }, []);\n\n  const getStatus = useCallback(() => {\n    if (!queueRef.current) throw new Error('Queue not initialized');\n    return queueRef.current.getStatus();\n  }, []);\n\n  return useMemo(\n    () => ({\n      add,\n      remove,\n      process,\n      rollbackAll,\n      getStatus,\n    }),\n    [add, remove, process, rollbackAll, getStatus]\n  );\n}\n\n// =============================================================================\n// UTILITY FUNCTIONS\n// =============================================================================\n\n/**\n * Create a deep clone of data for snapshotting\n *\n * @remarks\n * This function handles primitive types, arrays, Date, Map, Set, and plain objects.\n * The type assertions are safe because we preserve the structure of the input.\n */\nexport function deepClone<T>(data: T): T {\n  if (data === null || data === undefined) {\n    return data;\n  }\n\n  if (typeof data !== 'object') {\n    return data;\n  }\n\n  if (Array.isArray(data)) {\n    // Safe cast: we're creating an array of the same element type\n    // TypeScript cannot infer that mapping deepClone over an array preserves the array type\n    const clonedArray = data.map((item: unknown) => deepClone(item));\n    return clonedArray as T;\n  }\n\n  if (data instanceof Date) {\n    // Safe cast: Date to Date preserves type\n    return new Date(data.getTime()) as T;\n  }\n\n  if (data instanceof Map) {\n    // Safe cast: Map clone preserves Map type\n    const result = new Map<unknown, unknown>();\n    data.forEach((value, key) => {\n      result.set(key, deepClone(value));\n    });\n    return result as T;\n  }\n\n  if (data instanceof Set) {\n    // Safe cast: Set clone preserves Set type\n    const result = new Set<unknown>();\n    data.forEach((value) => {\n      result.add(deepClone(value));\n    });\n    return result as T;\n  }\n\n  // Plain object clone\n  const result: Record<string, unknown> = {};\n  for (const key of Object.keys(data)) {\n    result[key] = deepClone((data as Record<string, unknown>)[key]);\n  }\n  return result as T;\n}\n\n/**\n * Merge two objects deeply\n */\nexport function deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T {\n  const result = { ...target };\n\n  for (const key of Object.keys(source)) {\n    const targetValue = result[key];\n    const sourceValue = source[key];\n\n    if (sourceValue === undefined) {\n      continue;\n    }\n\n    if (\n      typeof targetValue === 'object' &&\n      targetValue !== null &&\n      typeof sourceValue === 'object' &&\n      sourceValue !== null &&\n      !Array.isArray(targetValue) &&\n      !Array.isArray(sourceValue)\n    ) {\n      (result as Record<string, unknown>)[key] = deepMerge(\n        targetValue as Record<string, unknown>,\n        sourceValue as Record<string, unknown>\n      );\n    } else {\n      (result as Record<string, unknown>)[key] = sourceValue;\n    }\n  }\n\n  return result;\n}\n\n// =============================================================================\n// GLOBAL INSTANCES\n// =============================================================================\n\n/**\n * Global optimistic mutation queue\n */\nexport const globalMutationQueue = new OptimisticMutationQueue();\n"],"names":["useOptimisticMutation","mutationFn","config","options","queryClient","useQueryClient","pendingMutationsRef","useRef","useMutation","variables","mutationId","startTime","queryKeys","key","snapshots","queryKey","snapshot","optimisticData","context","error","data","currentData","conflictContext","finalData","createListOptimisticUpdates","list","newItem","position","id","updates","item","fromIndex","toIndex","items","removed","newItems","OptimisticMutationQueue","rollbackFn","index","m","mutation","r","persistable","timestamp","retries","maxRetries","status","stored","useMutationQueue","queueRef","add","useCallback","remove","process","rollbackAll","getStatus","useMemo","deepClone","result","value","deepMerge","target","source","targetValue","sourceValue","globalMutationQueue"],"mappings":"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"}