import { ref, onUnmounted } from 'vue' /** * Smart incremental polling composable. * Calls `fetchFn()` at `interval` ms. Compares result count/IDs * with previous to detect new items and trigger `onNew` callback. * * @param {Function} fetchFn - async function that returns array of items * @param {Object} opts * @param {number} opts.interval - poll interval in ms (default 10000) * @param {Function} opts.getId - function to get unique ID from item (default: item => item.name) * @param {Function} opts.onNew - callback when new items detected, receives array of new items */ export function usePolling (fetchFn, opts = {}) { const interval = opts.interval || 10000 const getId = opts.getId || (item => item.name) const onNew = opts.onNew || (() => {}) const knownIds = ref(new Set()) let timer = null let running = false function seedKnownIds (items) { knownIds.value = new Set(items.map(getId)) } async function poll () { if (running) return running = true try { const items = await fetchFn() const newItems = items.filter(item => !knownIds.value.has(getId(item))) if (newItems.length) { for (const item of items) { knownIds.value.add(getId(item)) } onNew(newItems, items) } } catch { // Silent fail on poll } finally { running = false } } function start () { stop() timer = setInterval(poll, interval) } function stop () { if (timer) { clearInterval(timer) timer = null } } // Auto-cleanup on component unmount onUnmounted(stop) return { start, stop, poll, seedKnownIds } }