react-smart-query 1.0.0
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/LICENSE +21 -0
- package/README.md +130 -0
- package/dist/cache.service-MR6EEYM4.mjs +4 -0
- package/dist/cache.service-MR6EEYM4.mjs.map +1 -0
- package/dist/chunk-KLJQATIV.mjs +170 -0
- package/dist/chunk-KLJQATIV.mjs.map +1 -0
- package/dist/chunk-KSLDOL27.mjs +133 -0
- package/dist/chunk-KSLDOL27.mjs.map +1 -0
- package/dist/chunk-QRCVY7UR.mjs +137 -0
- package/dist/chunk-QRCVY7UR.mjs.map +1 -0
- package/dist/index.d.mts +545 -0
- package/dist/index.d.ts +545 -0
- package/dist/index.js +1533 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1018 -0
- package/dist/index.mjs.map +1 -0
- package/dist/storage.adapter-PJCVI4DE.mjs +3 -0
- package/dist/storage.adapter-PJCVI4DE.mjs.map +1 -0
- package/dist/testing.d.mts +89 -0
- package/dist/testing.d.ts +89 -0
- package/dist/testing.js +272 -0
- package/dist/testing.js.map +1 -0
- package/dist/testing.mjs +78 -0
- package/dist/testing.mjs.map +1 -0
- package/dist/types-XXiTKLnh.d.mts +134 -0
- package/dist/types-XXiTKLnh.d.ts +134 -0
- package/dist/utils/debug.d.mts +2 -0
- package/dist/utils/debug.d.ts +2 -0
- package/dist/utils/debug.js +208 -0
- package/dist/utils/debug.js.map +1 -0
- package/dist/utils/debug.mjs +40 -0
- package/dist/utils/debug.mjs.map +1 -0
- package/docs/API_REFERENCE.md +149 -0
- package/docs/GUIDELINES.md +23 -0
- package/docs/TESTING.md +61 -0
- package/package.json +136 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useSmartQuery.ts","../src/utils/smartCompare.ts","../src/utils/normalize.ts","../src/registry/smartQueryRegistry.ts","../src/hooks/useSmartMutation.ts","../src/hooks/useInfiniteSmartQuery.ts","../src/hooks/useSmartQuerySelector.ts","../src/factory/createTypedQuery.ts","../src/index.ts"],"names":["deleteCache","inFlightKeys","normalizeError","useState","useRef","useCallback","DEFAULT_TTL","useMemo","useEffect","equal","useQueryClient"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * src/hooks/useSmartQuery.ts\n *\n * Core data-fetching hook — V2.\n */\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n useQuery,\n useQueryClient,\n QueryKey,\n QueryFunction,\n UseQueryOptions,\n} from \"@tanstack/react-query\";\n\nimport {\n readCache,\n writeCache,\n deleteCache,\n cacheKeyFor,\n isCacheStale,\n} from \"../services/cache.service\";\nimport { fetchWithLock } from \"../services/requestLock.service\";\nimport { storage } from \"../services/storage.adapter\";\nimport { emit } from \"../services/observer.service\";\nimport { isDataEqual, SmartCompareOptions } from \"../utils/smartCompare\";\nimport {\n NormalizedList,\n fromArray,\n toArray,\n normalizedAdd,\n normalizedUpdate,\n normalizedRemove,\n emptyList,\n trimNormalizedList,\n} from \"../utils/normalize\";\nimport {\n _registerUpdater,\n _unregisterUpdater,\n} from \"../registry/smartQueryRegistry\";\nimport type {\n AnyItem,\n GetItemId,\n GetItemVersion,\n SortComparator,\n SmartQueryError,\n} from \"../types\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type { AnyItem, GetItemId, SortComparator, SmartQueryError };\n\nexport interface SmartQueryOptions<\n TRaw,\n TData,\n TItem extends AnyItem = TData extends AnyItem[] ? TData[number] : AnyItem\n> {\n queryKey: QueryKey;\n\n /**\n * Fetches raw data from the network.\n * Automatically wrapped in fetchWithLock — concurrent calls are deduplicated.\n */\n queryFn: QueryFunction<TRaw>;\n\n /**\n * Transform the raw API response before caching and exposing to the component.\n */\n select?: (raw: TRaw) => TData;\n\n /**\n * Extract a stable string id from a list item.\n */\n getItemId?: TData extends AnyItem[] ? GetItemId<TItem> : never;\n\n /**\n * Sort comparator for list data.\n */\n sortComparator?: TData extends AnyItem[] ? SortComparator<TItem> : never;\n\n /** Cache TTL in ms. Default: 5 minutes. */\n cacheTtl?: number;\n\n /** Maximum items to keep in the normalized list. Default: 1000 */\n maxItems?: number;\n\n /** Optional. Extracts version/timestamp for conflict resolution. */\n getItemVersion?: TData extends AnyItem[] ? GetItemVersion<TItem> : never;\n\n /**\n * When true, stale cache is never served — waits for a fresh fetch.\n */\n strictFreshness?: boolean;\n\n /** Data to show when there is no cache and the fetch fails */\n fallbackData?: TData;\n\n /** Smart diff configuration */\n compareOptions?: SmartCompareOptions;\n\n /** Called when a fresh fetch succeeds */\n onSuccess?: (data: TData) => void;\n\n /**\n * Called when a fetch fails.\n */\n onError?: (error: SmartQueryError) => boolean | void;\n\n /** Extra TanStack Query options */\n queryOptions?: Omit<\n UseQueryOptions<TRaw>,\n \"queryKey\" | \"queryFn\" | \"initialData\" | \"enabled\" | \"select\"\n >;\n}\n\nexport interface SmartQueryResult<\n TData,\n TItem extends AnyItem = TData extends AnyItem[] ? TData[number] : AnyItem\n> {\n data: TData | undefined;\n isLoading: boolean;\n isFetching: boolean;\n isFromCache: boolean;\n isCacheLoading: boolean;\n error: SmartQueryError | null;\n refetch: () => void;\n // List mutations\n addItem: TData extends AnyItem[] ? (item: TItem) => void : never;\n updateItem: TData extends AnyItem[] ? (item: TItem) => void : never;\n removeItem: TData extends AnyItem[] ? (id: string) => void : never;\n}\n\n// ─── Error normalizer ─────────────────────────────────────────────────────────\n\nfunction normalizeError(cause: unknown): SmartQueryError {\n if (cause instanceof Error) {\n const err = cause as Error & { status?: number };\n const status = err.status;\n return {\n cause,\n message: cause.message,\n retryable: !status || status >= 500 || status === 429,\n statusCode: status,\n };\n }\n return { cause, message: String(cause), retryable: true };\n}\n\nconst DEFAULT_TTL = 5 * 60_000;\n\n// ─── Hook ─────────────────────────────────────────────────────────────────────\n\nexport function useSmartQuery<\n TRaw,\n TData,\n TItem extends AnyItem = TData extends AnyItem[] ? TData[number] : AnyItem\n>(\n options: SmartQueryOptions<TRaw, TData, TItem>\n): SmartQueryResult<TData, TItem> {\n const {\n queryKey,\n queryFn,\n select,\n getItemId,\n sortComparator,\n cacheTtl = DEFAULT_TTL,\n maxItems = 1000,\n getItemVersion,\n strictFreshness = false,\n fallbackData,\n compareOptions,\n onSuccess,\n onError,\n queryOptions = {},\n } = options;\n\n const queryClient = useQueryClient();\n\n const storageKey = useMemo(\n () => cacheKeyFor(queryKey as readonly unknown[]),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [JSON.stringify(queryKey)]\n );\n\n const listMode = typeof sortComparator === \"function\" && typeof getItemId === \"function\";\n\n // ── State ──────────────────────────────────────────────────────────────────\n const [viewData, setViewData] = useState<TData | undefined>(undefined);\n const [isCacheLoading, setIsCacheLoading] = useState(true);\n const [isFromCache, setIsFromCache] = useState(false);\n const [shouldFetch, setShouldFetch] = useState(false);\n const [smartError, setSmartError] = useState<SmartQueryError | null>(null);\n\n const prevRawRef = useRef<unknown>(undefined);\n const normalizedRef = useRef<NormalizedList<TItem>>(emptyList<TItem>());\n\n // ── ① Read storage on mount ────────────────────────────────────────────────\n useEffect(() => {\n let cancelled = false;\n setIsCacheLoading(true);\n\n readCache<unknown>(storageKey, queryKey as readonly unknown[]).then((entry) => {\n if (cancelled) return;\n\n if (entry !== null) {\n const isStale = isCacheStale(entry, cacheTtl);\n const usable = !strictFreshness || !isStale;\n\n if (usable) {\n if (listMode) {\n let normalized: NormalizedList<TItem>;\n if (Array.isArray(entry.data)) {\n normalized = fromArray(\n entry.data as TItem[],\n getItemId as GetItemId<TItem>,\n sortComparator as SortComparator<TItem>\n );\n } else {\n normalized = entry.data as NormalizedList<TItem>;\n }\n normalizedRef.current = normalized;\n const view = toArray(normalized) as unknown as TData;\n prevRawRef.current = normalized;\n queryClient.setQueryData(queryKey, view);\n setViewData(view);\n } else {\n prevRawRef.current = entry.data;\n queryClient.setQueryData(queryKey, entry.data as TData);\n setViewData(entry.data as TData);\n }\n setIsFromCache(true);\n setShouldFetch(isStale);\n } else {\n setShouldFetch(true);\n }\n } else {\n setShouldFetch(true);\n }\n\n setIsCacheLoading(false);\n });\n\n return () => { cancelled = true; };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [storageKey]);\n\n // ── ② Dedup + select wrapped queryFn ──────────────────────────────────────\n const wrappedQueryFn: QueryFunction<TData> = useCallback(\n async (ctx) => {\n emit({ type: \"fetch_start\", queryKey: queryKey as readonly unknown[] });\n const start = Date.now();\n try {\n const raw = await fetchWithLock(storageKey, () => queryFn(ctx) as Promise<TRaw>);\n const transformed = select ? select(raw) : (raw as unknown as TData);\n emit({\n type: \"fetch_success\",\n queryKey: queryKey as readonly unknown[],\n durationMs: Date.now() - start,\n });\n return transformed;\n } catch (err) {\n emit({ type: \"fetch_error\", queryKey: queryKey as readonly unknown[], error: err });\n throw err;\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [storageKey, queryFn, select]\n );\n\n // ── ③ TanStack Query ───────────────────────────────────────────────────────\n const {\n data: freshData,\n isFetching,\n error: tqError,\n refetch: tqRefetch,\n } = useQuery<TData>({\n queryKey,\n queryFn: wrappedQueryFn,\n enabled: !isCacheLoading && shouldFetch,\n staleTime: cacheTtl,\n gcTime: cacheTtl * 2,\n refetchOnWindowFocus: false,\n refetchOnReconnect: true,\n networkMode: \"offlineFirst\",\n ...(queryOptions as any),\n });\n\n // ── ④ Handle TQ errors ─────────────────────────────────────────────────────\n useEffect(() => {\n if (!tqError) { setSmartError(null); return; }\n const structured = normalizeError(tqError);\n const suppressed = onError?.(structured);\n if (!suppressed) setSmartError(structured);\n }, [tqError, onError]);\n\n // ── ⑤ Smart diff + persist ────────────────────────────────────────────────\n useEffect(() => {\n if (freshData === undefined || isFetching) return;\n\n if (listMode) {\n const freshNormalized = fromArray(\n freshData as unknown as TItem[],\n getItemId as GetItemId<TItem>,\n sortComparator as SortComparator<TItem>\n );\n\n if (!isDataEqual(prevRawRef.current, freshNormalized, compareOptions)) {\n prevRawRef.current = freshNormalized;\n normalizedRef.current = freshNormalized;\n const view = toArray(freshNormalized) as unknown as TData;\n queryClient.setQueryData(queryKey, view);\n setViewData(() => view);\n setIsFromCache(false);\n\n const trimmed = trimNormalizedList(freshNormalized, maxItems);\n void writeCache(storageKey, trimmed, queryKey as readonly unknown[]);\n onSuccess?.(view);\n }\n } else {\n if (!isDataEqual(prevRawRef.current, freshData, compareOptions)) {\n prevRawRef.current = freshData;\n queryClient.setQueryData(queryKey, freshData);\n setViewData(() => freshData as TData);\n setIsFromCache(false);\n void writeCache(storageKey, freshData, queryKey as readonly unknown[]);\n onSuccess?.(freshData as TData);\n }\n }\n }, [freshData, isFetching]); // eslint-disable-line react-hooks/exhaustive-deps\n\n // ── ⑥ List mutations ───────────────────────────────────────────────────────\n\n const applyMutation = useCallback(\n (fn: (current: NormalizedList<TItem>) => NormalizedList<TItem>) => {\n const next = trimNormalizedList(fn(normalizedRef.current), maxItems);\n normalizedRef.current = next;\n prevRawRef.current = next;\n const view = toArray(next) as unknown as TData;\n queryClient.setQueryData(queryKey, view);\n setViewData(view);\n void writeCache(storageKey, next, queryKey as readonly unknown[]);\n },\n [queryClient, queryKey, storageKey, maxItems]\n );\n\n const addItem = useCallback(\n (item: TItem) => {\n if (!listMode) return;\n applyMutation((cur) =>\n normalizedAdd(\n cur, item,\n getItemId as GetItemId<TItem>,\n sortComparator as SortComparator<TItem>,\n getItemVersion as GetItemVersion<TItem>\n )\n );\n },\n [listMode, getItemId, sortComparator, getItemVersion, applyMutation]\n );\n\n const updateItem = useCallback(\n (item: TItem) => {\n if (!listMode) return;\n applyMutation((cur) =>\n normalizedUpdate(\n cur, item,\n getItemId as GetItemId<TItem>,\n sortComparator as SortComparator<TItem>,\n getItemVersion as GetItemVersion<TItem>\n )\n );\n },\n [listMode, getItemId, sortComparator, getItemVersion, applyMutation]\n );\n\n const removeItem = useCallback(\n (id: string) => {\n if (!listMode) return;\n applyMutation((cur) => normalizedRemove(cur, id));\n },\n [listMode, applyMutation]\n );\n\n // ── ⑦ Registry registration ────────────────────────────────────────────────\n const addRef = useRef(addItem);\n const updateRef = useRef(updateItem);\n const removeRef = useRef(removeItem);\n useEffect(() => { addRef.current = addItem; }, [addItem]);\n useEffect(() => { updateRef.current = updateItem; }, [updateItem]);\n useEffect(() => { removeRef.current = removeItem; }, [removeItem]);\n\n useEffect(() => {\n _registerUpdater(\n storageKey,\n {\n add: (item) => addRef.current(item as TItem),\n update: (item) => updateRef.current(item as TItem),\n remove: (id) => removeRef.current(id),\n },\n listMode && !!sortComparator && !!getItemId\n ? {\n comparator: sortComparator as SortComparator<AnyItem>,\n getItemId: getItemId as GetItemId<AnyItem>,\n }\n : null\n );\n return () => _unregisterUpdater(storageKey);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [storageKey]);\n\n // ── Assemble ───────────────────────────────────────────────────────────────\n const data = viewData ?? (tqError ? fallbackData : undefined);\n const isLoading = isCacheLoading || (data === undefined && isFetching);\n\n const refetch = useCallback(() => {\n setShouldFetch(true);\n tqRefetch();\n }, [tqRefetch]);\n\n return {\n data,\n isLoading,\n isFetching,\n isFromCache,\n isCacheLoading,\n error: smartError,\n refetch,\n addItem: addItem as SmartQueryResult<TData, TItem>[\"addItem\"],\n updateItem: updateItem as SmartQueryResult<TData, TItem>[\"updateItem\"],\n removeItem: removeItem as SmartQueryResult<TData, TItem>[\"removeItem\"],\n };\n}\n\nexport const invalidateSmartCache = (queryKey: QueryKey): Promise<void> =>\n deleteCache(cacheKeyFor(queryKey as readonly unknown[]));\n\nexport const clearAllSmartCache = (): Promise<void> =>\n storage.clearAll();\n","/**\n * src/utils/smartCompare.ts\n *\n * Hybrid 5-tier comparison — short-circuits as early as possible.\n *\n * Tier 1 reference equality O(1)\n * Tier 2 type / length O(1)\n * Tier 3 id-set fingerprint O(n) — detects add / remove / reorder\n * Tier 4 version XOR fingerprint O(n) — detects field updates\n * Tier 5 fast-deep-equal fallback O(n*f) — schema-less safety net\n */\n\nimport equal from \"fast-deep-equal\";\nimport type { AnyItem, GetItemId } from \"../types\";\n\nexport interface SmartCompareOptions {\n idField?: string;\n versionField?: string | null;\n}\n\nexport interface CompareResult {\n isEqual: boolean;\n tier: 1 | 2 | 3 | 4 | 5;\n}\n\nexport function smartCompare(\n oldData: unknown,\n newData: unknown,\n options: SmartCompareOptions = {}\n): CompareResult {\n const idField = options.idField ?? \"id\";\n const versionField = options.versionField === undefined ? \"updatedAt\" : options.versionField;\n\n // Tier 1\n if (oldData === newData) return { isEqual: true, tier: 1 };\n\n const oldIsArr = Array.isArray(oldData);\n const newIsArr = Array.isArray(newData);\n\n // Tier 2\n if (oldIsArr !== newIsArr) return { isEqual: false, tier: 2 };\n if (!oldIsArr) return { isEqual: equal(oldData, newData), tier: 5 };\n\n const o = oldData as AnyItem[];\n const n = newData as AnyItem[];\n if (o.length !== n.length) return { isEqual: false, tier: 2 };\n if (o.length === 0) return { isEqual: true, tier: 2 };\n\n // Tier 3 — id fingerprint\n let oldIds = \"\";\n let newIds = \"\";\n for (let i = 0; i < o.length; i++) {\n oldIds += String(o[i][idField] ?? i) + \"|\";\n newIds += String(n[i][idField] ?? i) + \"|\";\n }\n if (oldIds !== newIds) return { isEqual: false, tier: 3 };\n\n // Tier 4 — version XOR\n if (versionField !== null) {\n let xorOld = 0;\n let xorNew = 0;\n for (let i = 0; i < o.length; i++) {\n xorOld ^= (Number(o[i][versionField] ?? 0) ^ i);\n xorNew ^= (Number(n[i][versionField] ?? 0) ^ i);\n }\n if (xorOld !== xorNew) return { isEqual: false, tier: 4 };\n }\n\n // Tier 5\n return { isEqual: equal(oldData, newData), tier: 5 };\n}\n\nexport function isDataEqual(\n oldData: unknown,\n newData: unknown,\n options?: SmartCompareOptions\n): boolean {\n return smartCompare(oldData, newData, options).isEqual;\n}\n","/**\n * src/utils/normalize.ts\n *\n * NormalizedList — O(1) lookup, O(log n) sorted mutations.\n *\n * The `getItemId` function is passed explicitly — no hardcoded field name.\n * This lets you use `_id`, `uuid`, numeric ids, or composite keys.\n */\n\nimport type { AnyItem, GetItemId, GetItemVersion, NormalizedList, SortComparator } from \"../types\";\n\nexport type { NormalizedList };\n\n// ─── Constructors ─────────────────────────────────────────────────────────────\n\nexport function emptyList<T extends AnyItem>(): NormalizedList<T> {\n return { byId: Object.create(null) as Record<string, T>, allIds: [] };\n}\n\nexport function fromArray<T extends AnyItem>(\n items: T[],\n getItemId: GetItemId<T>,\n comparator?: SortComparator<T>\n): NormalizedList<T> {\n const byId: Record<string, T> = Object.create(null);\n const allIds: string[] = new Array(items.length);\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const id = getItemId(item);\n byId[id] = item;\n allIds[i] = id;\n }\n\n if (comparator) allIds.sort((a, b) => comparator(byId[a], byId[b]));\n\n return { byId, allIds };\n}\n\nexport function toArray<T extends AnyItem>(list: NormalizedList<T>): T[] {\n const out = new Array<T>(list.allIds.length);\n for (let i = 0; i < list.allIds.length; i++) out[i] = list.byId[list.allIds[i]];\n return out;\n}\n\n// ─── Binary search ────────────────────────────────────────────────────────────\n\nfunction binaryIdx<T extends AnyItem>(\n allIds: string[],\n byId: Record<string, T>,\n item: T,\n getItemId: GetItemId<T>,\n cmp: SortComparator<T>\n): number {\n const itemId = getItemId(item);\n let lo = 0, hi = allIds.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const midItem = byId[allIds[mid]];\n let res = cmp(midItem, item);\n\n // Tie-breaker for stable sorting\n if (res === 0) {\n res = allIds[mid].localeCompare(itemId);\n }\n\n res <= 0 ? (lo = mid + 1) : (hi = mid);\n }\n return lo;\n}\n\n// ─── Mutations (all return new NormalizedList — immutable) ────────────────────\n\nexport function normalizedAdd<T extends AnyItem>(\n list: NormalizedList<T>,\n item: T,\n getItemId: GetItemId<T>,\n comparator: SortComparator<T>,\n getItemVersion?: GetItemVersion<T>\n): NormalizedList<T> {\n const id = getItemId(item);\n const existing = list.byId[id];\n\n // Conflict protection: if item exists, check for staleness\n if (existing && getItemVersion) {\n const vExisting = getItemVersion(existing);\n const vNew = getItemVersion(item);\n if (vNew < vExisting) return list; // Ignore stale update\n }\n\n const newById = { ...list.byId, [id]: item };\n const existingIdx = list.allIds.indexOf(id);\n\n const workingIds = list.allIds.slice();\n if (existingIdx !== -1) workingIds.splice(existingIdx, 1);\n\n const insertIdx = binaryIdx(workingIds, newById, item, getItemId, comparator);\n workingIds.splice(insertIdx, 0, id);\n\n return { byId: newById, allIds: workingIds };\n}\n\nexport function normalizedUpdate<T extends AnyItem>(\n list: NormalizedList<T>,\n item: T,\n getItemId: GetItemId<T>,\n comparator: SortComparator<T>,\n getItemVersion?: GetItemVersion<T>\n): NormalizedList<T> {\n const id = getItemId(item);\n const oldItem = list.byId[id];\n\n if (!oldItem) return list;\n\n // Conflict protection: if item exists, check for staleness\n if (getItemVersion) {\n const vExisting = getItemVersion(oldItem);\n const vNew = getItemVersion(item);\n if (vNew < vExisting) return list; // Ignore stale update\n }\n\n // Optimization: If sort key is unchanged, simple in-place object substitution\n if (comparator(oldItem, item) === 0) {\n return {\n allIds: list.allIds, // Keep same reference if possible, but immutable is safer\n byId: { ...list.byId, [id]: item },\n };\n }\n\n // Otherwise, full re-sort/re-insert logic\n return normalizedAdd(list, item, getItemId, comparator, getItemVersion);\n}\n\nexport function normalizedRemove<T extends AnyItem>(\n list: NormalizedList<T>,\n id: string\n): NormalizedList<T> {\n if (!(id in list.byId)) return list;\n\n const newById = { ...list.byId };\n delete newById[id];\n\n const idx = list.allIds.indexOf(id);\n const newAllIds = list.allIds.slice();\n if (idx !== -1) newAllIds.splice(idx, 1);\n\n return { byId: newById, allIds: newAllIds };\n}\n\n/**\n * Merge new items into existing normalized list.\n * Handles deduplication and maintains sort order via binary search.\n */\nexport function mergeNormalizedData<T extends AnyItem>(\n existing: NormalizedList<T>,\n incomingIds: string[],\n incomingById: Record<string, T>,\n getItemId: GetItemId<T>,\n comparator?: SortComparator<T>\n): NormalizedList<T> {\n const newById = { ...existing.byId, ...incomingById };\n const allIds = [...existing.allIds];\n const seen = new Set(existing.allIds);\n\n for (const id of incomingIds) {\n if (seen.has(id)) {\n // If already exists, we updated it in newById already via spread\n // We might need to re-sort if the item changed in a way that affects sort\n continue;\n }\n seen.add(id);\n if (comparator) {\n const item = incomingById[id];\n const insertIdx = binaryIdx(allIds, newById, item, getItemId, comparator);\n allIds.splice(insertIdx, 0, id);\n } else {\n allIds.push(id);\n }\n }\n\n // If comparator is provided, and we had existing items, \n // we might need a full sort if updates changed the order.\n // For performance, we usually assume updates to existing items \n // don't break sort order often, or we re-sort the whole thing if needed.\n if (comparator && incomingIds.some(id => existing.byId[id])) {\n allIds.sort((a, b) => comparator(newById[a], newById[b]));\n }\n\n return { byId: newById, allIds };\n}\n\n/**\n * Derive a single page of items from a normalized list.\n */\nexport function getPage<T extends AnyItem>(\n allIds: string[],\n byId: Record<string, T>,\n pageIndex: number,\n pageSize: number\n): T[] {\n const start = pageIndex * pageSize;\n const ids = allIds.slice(start, start + pageSize);\n return ids.map(id => byId[id]);\n}\n\n/**\n * Derive all pages from a normalized list.\n */\nexport function derivePages<T extends AnyItem>(\n allIds: string[],\n byId: Record<string, T>,\n pageSize: number\n): T[][] {\n const totalItems = allIds.length;\n const totalPages = Math.ceil(totalItems / pageSize);\n const pages: T[][] = [];\n\n for (let i = 0; i < totalPages; i++) {\n pages.push(getPage(allIds, byId, i, pageSize));\n }\n\n return pages;\n}\n\nexport function isNormalizedEmpty<T extends AnyItem>(list: NormalizedList<T>): boolean {\n return list.allIds.length === 0;\n}\n\n/**\n * Soft Trim list to maxItems. \n * Instead of a hard cut every time, we remove 20% of the oldest items\n * to avoid constant array slicing on every single insert.\n * Assumes list is already sorted.\n */\nexport function trimNormalizedList<T extends AnyItem>(\n list: NormalizedList<T>,\n maxItems: number\n): NormalizedList<T> {\n if (list.allIds.length <= maxItems) return list;\n\n // Remove 20% of items or at least enough to get back under limit\n const removeCount = Math.max(\n Math.ceil(list.allIds.length * 0.2),\n list.allIds.length - maxItems\n );\n \n const newSize = list.allIds.length - removeCount;\n const newAllIds = list.allIds.slice(0, newSize);\n const newById: Record<string, T> = {};\n \n for (const id of newAllIds) {\n newById[id] = list.byId[id];\n }\n\n return { byId: newById, allIds: newAllIds };\n}\n","/**\n * src/registry/smartQueryRegistry.ts\n *\n * Global mutation registry.\n * Call addItem / updateItem / removeItem from anywhere — no hook required.\n */\n\nimport { readCache, writeCache, cacheKeyFor } from \"../services/cache.service\";\nimport type { AnyItem, GetItemId, NormalizedList, SortComparator, UnifiedNormalizedInfiniteData } from \"../types\";\nimport {\n normalizedAdd,\n normalizedUpdate,\n normalizedRemove,\n} from \"../utils/normalize\";\n\nexport { cacheKeyFor };\n\n// ─── Internal ─────────────────────────────────────────────────────────────────\n\ninterface LiveUpdater {\n add(item: unknown): void;\n update(item: unknown): void;\n remove(id: string): void;\n}\n\ninterface SortConfig<T extends AnyItem> {\n comparator: SortComparator<T>;\n getItemId: GetItemId<T>;\n}\n\nconst liveRegistry = new Map<string, LiveUpdater>();\nconst sortConfigRegistry = new Map<string, SortConfig<AnyItem>>();\n\nexport function _registerUpdater(\n storageKey: string,\n updater: LiveUpdater,\n config: SortConfig<AnyItem> | null\n): void {\n liveRegistry.set(storageKey, updater);\n if (config) sortConfigRegistry.set(storageKey, config);\n}\n\nexport function _unregisterUpdater(storageKey: string): void {\n liveRegistry.delete(storageKey);\n}\n\n// ─── Cache-only mutation path ─────────────────────────────────────────────────\n\nasync function mutateStorageOnly<T extends AnyItem>(\n storageKey: string,\n queryKey: readonly unknown[],\n fn: (list: NormalizedList<T>, config: SortConfig<T>) => NormalizedList<T>\n): Promise<void> {\n const config = sortConfigRegistry.get(storageKey) as SortConfig<T> | undefined;\n if (!config) return;\n\n const entry = await readCache<any>(storageKey, queryKey);\n if (!entry) return;\n\n const rawData = entry.data;\n const isUnified = \"data\" in rawData && \"meta\" in rawData;\n const currentList: NormalizedList<T> = isUnified ? rawData.data : (rawData as NormalizedList<T>);\n\n const nextList = fn(currentList, config);\n\n const nextData = isUnified\n ? { ...rawData, data: nextList }\n : nextList;\n\n await writeCache(storageKey, nextData, queryKey);\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\nexport interface SmartQueryActions<TItem extends AnyItem> {\n addItem(item: TItem): Promise<void>;\n updateItem(item: TItem): Promise<void>;\n removeItem(id: string): Promise<void>;\n isActive(): boolean;\n}\n\nexport function getSmartQueryActions<TItem extends AnyItem>(\n queryKey: readonly unknown[]\n): SmartQueryActions<TItem> {\n const storageKey = cacheKeyFor(queryKey);\n\n return {\n isActive: () => liveRegistry.has(storageKey),\n\n addItem: async (item) => {\n const live = liveRegistry.get(storageKey);\n if (live) { live.add(item); return; }\n await mutateStorageOnly<TItem>(storageKey, queryKey, (list, { comparator, getItemId }) =>\n normalizedAdd(list, item, getItemId, comparator)\n );\n },\n\n updateItem: async (item) => {\n const live = liveRegistry.get(storageKey);\n if (live) { live.update(item); return; }\n await mutateStorageOnly<TItem>(storageKey, queryKey, (list, { comparator, getItemId }) =>\n normalizedUpdate(list, item, getItemId, comparator)\n );\n },\n\n removeItem: async (id) => {\n const live = liveRegistry.get(storageKey);\n if (live) { live.remove(id); return; }\n await mutateStorageOnly<TItem>(storageKey, queryKey, (list) =>\n normalizedRemove(list, id)\n );\n },\n };\n}\n\n// ─── Debug Tools ─────────────────────────────────────────────────────────────\n\ndeclare const __DEV__: boolean;\n\n/**\n * Dev-only debug API. All methods are no-ops in production.\n */\nexport const smartQueryDebug = {\n /** Get the current normalized state for a query key. */\n getNormalizedState: async <T extends AnyItem>(\n queryKey: readonly unknown[]\n ): Promise<NormalizedList<T> | UnifiedNormalizedInfiniteData<T> | null> => {\n if (typeof __DEV__ !== \"undefined\" && !__DEV__) return null;\n const storageKey = cacheKeyFor(queryKey);\n const entry = await readCache<any>(storageKey, queryKey);\n return entry ? entry.data : null;\n },\n\n /** Log a detailed summary of the cache entry to the console. */\n inspectCache: async (queryKey: readonly unknown[]): Promise<void> => {\n if (typeof __DEV__ !== \"undefined\" && !__DEV__) return;\n const storageKey = cacheKeyFor(queryKey);\n const entry = await readCache<any>(storageKey, queryKey);\n if (!entry) {\n console.log(`[SmartQuery Debug] Cache MISS for:`, queryKey);\n return;\n }\n console.log(`[SmartQuery Debug] Cache HIT for:`, queryKey, {\n cachedAt: new Date(entry.cachedAt).toISOString(),\n size: JSON.stringify(entry.data).length,\n data: entry.data,\n });\n },\n\n /** Clear the cache entry for a query key. */\n clearCache: async (queryKey: readonly unknown[]): Promise<void> => {\n if (typeof __DEV__ !== \"undefined\" && !__DEV__) return;\n const storageKey = cacheKeyFor(queryKey);\n const { deleteCache } = await import(\"../services/cache.service\");\n await deleteCache(storageKey);\n },\n\n /** Get the current state of the offline mutation queue. */\n getQueue: async (): Promise<any[]> => {\n if (typeof __DEV__ !== \"undefined\" && !__DEV__) return [];\n try {\n const { getStorage } = await import(\"../services/storage.adapter\");\n const raw = await getStorage().get(\"sq_mutation_queue\");\n return raw ? JSON.parse(raw) : [];\n } catch {\n return [];\n }\n },\n\n /** Get list of all storage keys currently being fetched. */\n inFlightRequests: (): string[] => {\n if (typeof __DEV__ !== \"undefined\" && !__DEV__) return [];\n try {\n const { inFlightKeys } = require(\"../services/requestLock.service\");\n return inFlightKeys();\n } catch {\n return [];\n }\n },\n};\n\n/**\n * Executes multiple mutations in a single logical batch.\n * If the hook is unmounted, it performs a single storage write.\n */\nexport async function batchUpdate(\n queryKey: readonly unknown[],\n fn: (actions: SmartQueryActions<any>) => void | Promise<void>\n): Promise<void> {\n const storageKey = cacheKeyFor(queryKey);\n const actions = getSmartQueryActions(queryKey);\n \n const live = liveRegistry.has(storageKey);\n if (live) {\n await fn(actions);\n return;\n }\n\n const config = sortConfigRegistry.get(storageKey);\n if (!config) return;\n\n const entry = await readCache<any>(storageKey, queryKey);\n if (!entry) return;\n\n let currentData = entry.data;\n const isUnified = \"data\" in currentData && \"meta\" in currentData;\n let currentList = isUnified ? currentData.data : (currentData as NormalizedList<any>);\n\n const batchActions: SmartQueryActions<any> = {\n isActive: () => false,\n addItem: async (item) => {\n currentList = normalizedAdd(currentList, item, config.getItemId, config.comparator);\n },\n updateItem: async (item) => {\n currentList = normalizedUpdate(currentList, item, config.getItemId, config.comparator);\n },\n removeItem: async (id) => {\n currentList = normalizedRemove(currentList, id);\n },\n };\n\n await fn(batchActions);\n\n const nextData = isUnified\n ? { ...currentData, data: currentList }\n : currentList;\n\n await writeCache(storageKey, nextData, queryKey);\n}\n","/**\n * src/hooks/useSmartMutation.ts\n *\n * First-class write hook — the companion to useSmartQuery.\n *\n * Handles the full mutation lifecycle:\n * 1. Optimistic update via getSmartQueryActions (instant UI)\n * 2. API call via mutationFn\n * 3. On success: optionally update the optimistic item with the server response\n * 4. On error: automatic rollback of the optimistic update\n * 5. Offline: enqueue to the persistent mutation queue\n *\n * Usage:\n * const { mutate, mutateAsync, isLoading, error } = useSmartMutation<Expense>({\n * queryKey: [\"expenses\", tripId],\n * mutationType: \"ADD_ITEM\",\n * mutationFn: (expense) => api.post(\"/expenses\", expense),\n * getItemId: (e) => e.id,\n * });\n *\n * mutate(newExpense); // optimistic + API + queue if offline\n */\n\nimport { useCallback, useRef, useState } from \"react\";\nimport { getSmartQueryActions } from \"../registry/smartQueryRegistry\";\nimport {\n enqueueMutation,\n processQueue,\n} from \"../services/queue.service\";\nimport { emit } from \"../services/observer.service\";\nimport type {\n AnyItem,\n GetItemId,\n MutationType,\n SmartQueryError,\n} from \"../types\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface SmartMutationOptions<TItem extends AnyItem, TResponse = TItem> {\n /** The query key this mutation targets — must match the useSmartQuery key */\n queryKey: readonly unknown[];\n\n /** \"ADD_ITEM\" | \"UPDATE_ITEM\" | \"REMOVE_ITEM\" | custom string */\n mutationType: MutationType | string;\n\n /**\n * The API call. Receives the item and returns the server-confirmed version.\n * If the app is offline, this is skipped and the mutation is queued.\n */\n mutationFn: (item: TItem) => Promise<TResponse>;\n\n /**\n * Extract the stable id from an item.\n * Used to roll back or replace the optimistic item with the server response.\n */\n getItemId: GetItemId<TItem>;\n\n /**\n * Map the server response back to a TItem for the final cache update.\n * If omitted, the server response is used as-is (assumes TResponse = TItem).\n */\n toItem?: (response: TResponse) => TItem;\n\n /**\n * Whether to enqueue the mutation when offline.\n * Default: true.\n */\n enableOfflineQueue?: boolean;\n\n /**\n * Optional entity key for queue coalescing.\n * Example: (item) => `expense:${item.id}`\n */\n getEntityKey?: (item: TItem) => string;\n\n /** Called after the API call succeeds */\n onSuccess?: (response: TResponse, item: TItem) => void;\n\n /** Called when the API call fails (after rollback) */\n onError?: (error: SmartQueryError, item: TItem) => void;\n\n /** Check network status — defaults to navigator.onLine on web, true on native */\n isOnline?: () => boolean;\n}\n\nexport interface SmartMutationResult<TItem extends AnyItem> {\n /** Fire-and-forget mutation */\n mutate(item: TItem): void;\n /** Async mutation — resolves after the API call completes */\n mutateAsync(item: TItem): Promise<void>;\n isPending: boolean;\n error: SmartQueryError | null;\n reset(): void;\n}\n\n// ─── Default online check ─────────────────────────────────────────────────────\n\nfunction defaultIsOnline(): boolean {\n if (typeof navigator !== \"undefined\" && \"onLine\" in navigator) {\n return navigator.onLine;\n }\n return true; // Assume online on native (use NetInfo for accurate check)\n}\n\n// ─── Error normalizer ─────────────────────────────────────────────────────────\n\nfunction normalizeError(cause: unknown): SmartQueryError {\n if (cause instanceof Error) {\n const err = cause as Error & { status?: number };\n const status = err.status;\n return {\n cause,\n message: cause.message,\n retryable: !status || status >= 500 || status === 429,\n statusCode: status,\n };\n }\n return { cause, message: String(cause), retryable: true };\n}\n\n// ─── Hook ─────────────────────────────────────────────────────────────────────\n\nexport function useSmartMutation<\n TItem extends AnyItem,\n TResponse = TItem\n>(\n options: SmartMutationOptions<TItem, TResponse>\n): SmartMutationResult<TItem> {\n const {\n queryKey,\n mutationType,\n mutationFn,\n getItemId,\n toItem,\n enableOfflineQueue = true,\n getEntityKey,\n onSuccess,\n onError,\n isOnline = defaultIsOnline,\n } = options;\n\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<SmartQueryError | null>(null);\n const isMounted = useRef(true);\n\n // Get actions for this query key — stable reference via closure\n const getActions = useCallback(\n () => getSmartQueryActions<TItem>(queryKey),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [JSON.stringify(queryKey)]\n );\n\n const mutateAsync = useCallback(\n async (item: TItem): Promise<void> => {\n const actions = getActions();\n const itemId = getItemId(item);\n\n if (isMounted.current) {\n setIsPending(true);\n setError(null);\n }\n\n // ── Step 1: Optimistic update ────────────────────────────────────────\n if (mutationType === \"ADD_ITEM\" || mutationType === \"CUSTOM\") {\n await actions.addItem(item);\n } else if (mutationType === \"UPDATE_ITEM\") {\n await actions.updateItem(item);\n } else if (mutationType === \"REMOVE_ITEM\") {\n await actions.removeItem(itemId);\n }\n\n // ── Step 2: Offline path ─────────────────────────────────────────────\n if (!isOnline()) {\n if (enableOfflineQueue) {\n await enqueueMutation({\n type: mutationType,\n queryKey,\n payload: item,\n entityKey: getEntityKey?.(item),\n });\n }\n if (isMounted.current) setIsPending(false);\n return;\n }\n\n // ── Step 3: API call ─────────────────────────────────────────────────\n try {\n const response = await mutationFn(item);\n const confirmedItem = toItem ? toItem(response) : (response as unknown as TItem);\n\n // Replace optimistic item with server-confirmed version\n if (mutationType !== \"REMOVE_ITEM\") {\n await actions.updateItem(confirmedItem);\n }\n\n emit({\n type: \"queue_success\",\n mutationId: `${mutationType}:${itemId}`,\n });\n\n onSuccess?.(response, item);\n // Drain queue in case there are pending mutations for this key\n void processQueue();\n } catch (err) {\n // ── Step 4: Rollback ───────────────────────────────────────────────\n if (mutationType === \"ADD_ITEM\" || mutationType === \"CUSTOM\") {\n await actions.removeItem(itemId);\n } else if (mutationType === \"UPDATE_ITEM\") {\n // We don't have the original item here — just signal the error.\n // The next background fetch will restore correct state.\n } else if (mutationType === \"REMOVE_ITEM\") {\n await actions.addItem(item); // restore removed item\n }\n\n const structured = normalizeError(err);\n if (isMounted.current) setError(structured);\n onError?.(structured, item);\n } finally {\n if (isMounted.current) setIsPending(false);\n }\n },\n [\n getActions,\n getItemId,\n mutationType,\n mutationFn,\n toItem,\n enableOfflineQueue,\n getEntityKey,\n isOnline,\n onSuccess,\n onError,\n queryKey,\n ]\n );\n\n const mutate = useCallback(\n (item: TItem): void => { void mutateAsync(item); },\n [mutateAsync]\n );\n\n const reset = useCallback(() => {\n setError(null);\n setIsPending(false);\n }, []);\n\n return { mutate, mutateAsync, isPending, error, reset };\n}\n","/**\n * src/hooks/useInfiniteSmartQuery.ts\n *\n * Cursor-based infinite scroll hook.\n */\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport {\n readCache,\n writeCache,\n cacheKeyFor,\n isCacheStale,\n} from \"../services/cache.service\";\nimport { fetchWithLock } from \"../services/requestLock.service\";\nimport { emit } from \"../services/observer.service\";\nimport {\n NormalizedList,\n fromArray,\n toArray,\n normalizedAdd,\n normalizedUpdate,\n normalizedRemove,\n emptyList,\n} from \"../utils/normalize\";\nimport type {\n AnyItem,\n GetItemId,\n GetItemVersion,\n SortComparator,\n UnifiedNormalizedInfiniteData,\n SmartQueryError,\n PaginationMode,\n} from \"../types\";\nimport {\n derivePages,\n mergeNormalizedData,\n trimNormalizedList,\n} from \"../utils/normalize\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface InfiniteSmartQueryOptions<TRaw, TItem extends AnyItem> {\n queryKey: readonly unknown[];\n\n /**\n * Fetches one page. Receives `pageParam` (the cursor).\n * First call receives `initialPageParam`.\n */\n queryFn: (ctx: { pageParam: unknown }) => Promise<TRaw>;\n\n /**\n * Extract the cursor for the NEXT page from the raw page response.\n * Return null when there are no more pages.\n */\n getNextCursor: (raw: TRaw) => unknown | null;\n\n /**\n * Transform raw page response → TItem[].\n * Use to unwrap response envelopes.\n */\n select: (raw: TRaw) => TItem[];\n\n /** Extract stable string id from an item */\n getItemId: GetItemId<TItem>;\n\n /** Sort order within each page (and across pages) */\n sortComparator?: SortComparator<TItem>;\n\n /** Cursor to use for the first page. Default: undefined */\n initialPageParam?: unknown;\n\n /**\n * \"normalized\" (default) -> data: TItem[]\n * \"pages\" -> data: { pages: TItem[][] }\n */\n paginationMode?: PaginationMode;\n\n /** Optional. Inferred from first page if not provided. */\n pageSize?: number;\n\n /** Maximum items to keep in the unified normalized list. Default: 1000 */\n maxItems?: number;\n\n /** Optional. Extracts version/timestamp for conflict resolution. */\n getItemVersion?: GetItemVersion<TItem>;\n\n cacheTtl?: number;\n strictFreshness?: boolean;\n onError?: (error: SmartQueryError) => void;\n}\n\nexport interface InfiniteSmartQueryResult<TItem extends AnyItem> {\n /**\n * If paginationMode: \"normalized\", data is TItem[]\n * If paginationMode: \"pages\", data is { pages: TItem[][] }\n */\n data: TItem[] | { pages: TItem[][] };\n isLoading: boolean;\n isFetchingNextPage: boolean;\n isFetching: boolean;\n isRefreshing: boolean;\n hasNextPage: boolean;\n error: SmartQueryError | null;\n totalCount: number;\n fetchNextPage(): void;\n refetch(): void;\n addItem(item: TItem): void;\n updateItem(item: TItem): void;\n removeItem(id: string): void;\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction normalizeError(cause: unknown): SmartQueryError {\n if (cause instanceof Error) {\n const err = cause as Error & { status?: number };\n const status = err.status;\n return {\n cause,\n message: cause.message,\n retryable: !status || status >= 500 || status === 429,\n statusCode: status,\n };\n }\n return { cause, message: String(cause), retryable: true };\n}\n\nconst DEFAULT_TTL = 5 * 60_000;\n\n// ─── Hook ─────────────────────────────────────────────────────────────────────\n\nexport function useInfiniteSmartQuery<TRaw, TItem extends AnyItem>(\n options: InfiniteSmartQueryOptions<TRaw, TItem>\n): InfiniteSmartQueryResult<TItem> {\n const {\n queryKey,\n queryFn,\n getNextCursor,\n select,\n getItemId,\n getItemVersion,\n sortComparator,\n initialPageParam = undefined,\n paginationMode = \"normalized\",\n pageSize: pageSizeProp,\n maxItems = 1000,\n cacheTtl = DEFAULT_TTL,\n strictFreshness = false,\n onError,\n } = options;\n\n const storageKey = useMemo(\n () => cacheKeyFor(queryKey),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [JSON.stringify(queryKey)]\n );\n\n // ── State ──────────────────────────────────────────────────────────────────\n const [infiniteData, setInfiniteData] = useState<UnifiedNormalizedInfiniteData<TItem>>({\n data: emptyList<TItem>(),\n meta: {\n nextCursor: initialPageParam ?? null,\n pageParams: [],\n },\n });\n const [pageSize, setPageSize] = useState<number | undefined>(pageSizeProp);\n const [isCacheLoading, setIsCacheLoading] = useState(true);\n const [isFetchingNextPage, setIsFetchingNextPage] = useState(false);\n const [isFetching, setIsFetching] = useState(false);\n const [error, setError] = useState<SmartQueryError | null>(null);\n\n const infiniteRef = useRef(infiniteData);\n\n function setAndNotify(next: UnifiedNormalizedInfiniteData<TItem>) {\n infiniteRef.current = next;\n setInfiniteData(next);\n }\n\n // ── ① Load from cache ──────────────────────────────────────────────────────\n useEffect(() => {\n let cancelled = false;\n setIsCacheLoading(true);\n\n readCache<UnifiedNormalizedInfiniteData<TItem>>(storageKey, queryKey).then((entry) => {\n if (cancelled) return;\n if (entry !== null) {\n const isStale = isCacheStale(entry, cacheTtl);\n if (!strictFreshness || !isStale) {\n setAndNotify(entry.data);\n }\n }\n setIsCacheLoading(false);\n });\n\n return () => { cancelled = true; };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [storageKey]);\n\n // ── ② Fetch a single page ──────────────────────────────────────────────────\n const fetchPage = useCallback(\n async (cursor: unknown): Promise<void> => {\n const lockKey = `${storageKey}:${JSON.stringify(cursor)}`;\n emit({ type: \"fetch_start\", queryKey });\n\n try {\n const raw = await fetchWithLock(lockKey, () => queryFn({ pageParam: cursor }));\n const items = select(raw);\n const nextCursor = getNextCursor(raw);\n const pageIds = items.map(getItemId);\n const pageById = fromArray(items, getItemId).byId;\n const now = Date.now();\n\n emit({ type: \"fetch_success\", queryKey, durationMs: 0 });\n\n const current = infiniteRef.current;\n const alreadyFetched = current.meta.pageParams.includes(cursor);\n\n if (!pageSize && items.length > 0) {\n setPageSize(items.length);\n }\n\n let mergedList = mergeNormalizedData(\n current.data,\n pageIds,\n pageById,\n getItemId,\n sortComparator\n );\n\n mergedList = trimNormalizedList(mergedList, maxItems);\n\n const next: UnifiedNormalizedInfiniteData<TItem> = {\n data: mergedList,\n meta: {\n pageParams: alreadyFetched ? current.meta.pageParams : [...current.meta.pageParams, cursor],\n nextCursor,\n lastFetchedAt: now,\n },\n };\n\n setAndNotify(next);\n void writeCache(storageKey, next, queryKey);\n setError(null);\n } catch (err) {\n emit({ type: \"fetch_error\", queryKey, error: err });\n const structured = normalizeError(err);\n setError(structured);\n onError?.(structured);\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [storageKey, queryFn, select, getNextCursor, getItemId, sortComparator, maxItems]\n );\n\n // ── ③ Initial fetch ────────────────────────────────────────────────────────\n useEffect(() => {\n if (isCacheLoading) return;\n void (async () => {\n setIsFetching(true);\n await fetchPage(initialPageParam);\n setIsFetching(false);\n })();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isCacheLoading]);\n\n // ── ④ Load next page ───────────────────────────────────────────────────────\n const inFlightRef = useRef<Set<string>>(new Set());\n\n const fetchNextPage = useCallback(() => {\n const { nextCursor, lastFetchedAt } = infiniteRef.current.meta;\n if (nextCursor === null || isFetchingNextPage) return;\n\n const cursorKey = JSON.stringify(nextCursor);\n if (inFlightRef.current.has(cursorKey)) return;\n\n if (lastFetchedAt && Date.now() - lastFetchedAt < 500) return;\n\n void (async () => {\n inFlightRef.current.add(cursorKey);\n setIsFetchingNextPage(true);\n await fetchPage(nextCursor);\n setIsFetchingNextPage(false);\n inFlightRef.current.delete(cursorKey);\n })();\n }, [fetchPage, isFetchingNextPage]);\n\n const refetch = useCallback(() => {\n void (async () => {\n setIsFetching(true);\n await fetchPage(initialPageParam);\n setIsFetching(false);\n })();\n }, [fetchPage, initialPageParam]);\n\n // ── ⑤ Single-item mutations across all pages ───────────────────────────────\n\n const applyItemMutation = useCallback(\n (fn: (data: NormalizedList<TItem>) => NormalizedList<TItem>) => {\n const current = infiniteRef.current;\n const next: UnifiedNormalizedInfiniteData<TItem> = {\n ...current,\n data: fn(current.data),\n };\n setAndNotify(next);\n void writeCache(storageKey, next, queryKey);\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [storageKey]\n );\n\n const updateItem = useCallback(\n (item: TItem) => {\n applyItemMutation((data) =>\n normalizedUpdate(\n data,\n item,\n getItemId,\n sortComparator ?? ((a, b) => 0),\n getItemVersion\n )\n );\n },\n [getItemId, sortComparator, getItemVersion, applyItemMutation]\n );\n\n const addItem = useCallback(\n (item: TItem) => {\n const id = getItemId(item);\n const current = infiniteRef.current;\n\n if (id in current.data.byId) {\n updateItem(item);\n return;\n }\n\n applyItemMutation((data) => {\n const next = normalizedAdd(\n data,\n item,\n getItemId,\n sortComparator ?? ((a, b) => 0),\n getItemVersion\n );\n return trimNormalizedList(next, maxItems);\n });\n },\n [getItemId, sortComparator, getItemVersion, applyItemMutation, updateItem, maxItems]\n );\n\n const removeItem = useCallback(\n (id: string) => {\n applyItemMutation((data) => normalizedRemove(data, id));\n },\n [applyItemMutation]\n );\n\n const flatData = useMemo(() => toArray(infiniteData.data), [infiniteData.data]);\n const isLoading = isCacheLoading || (flatData.length === 0 && isFetching);\n const isRefreshing = !!(flatData.length > 0 && isFetching && !isFetchingNextPage);\n const hasNextPage = infiniteRef.current.meta.nextCursor !== null;\n const totalCount = infiniteData.data.allIds.length;\n\n const derivedData = useMemo(() => {\n if (paginationMode === \"pages\") {\n return {\n pages: derivePages(\n infiniteData.data.allIds,\n infiniteData.data.byId,\n pageSize ?? flatData.length\n ),\n };\n }\n return flatData;\n }, [paginationMode, infiniteData.data.allIds, infiniteData.data.byId, pageSize, flatData]);\n\n return {\n data: derivedData as any,\n isLoading,\n isFetchingNextPage,\n isFetching,\n isRefreshing,\n hasNextPage,\n error,\n totalCount,\n fetchNextPage,\n refetch,\n addItem,\n updateItem,\n removeItem,\n };\n}\n","/**\n * src/hooks/useSmartQuerySelector.ts\n *\n * Derived data selector — subscribe to a slice of a cached list.\n *\n * Problem:\n * When an expense list of 500 items has one item updated, every component\n * calling useSmartQuery rerenders. For a row component this is O(n) renders.\n *\n * Solution:\n * useSmartQuerySelector subscribes to the TanStack Query cache for a specific\n * queryKey and applies a selector function. The component only rerenders\n * when the SELECTOR OUTPUT changes (checked with fast-deep-equal).\n *\n * @example\n * // Only rerenders when THIS expense changes\n * const expense = useSmartQuerySelector(\n * [\"expenses\", tripId],\n * (expenses: Expense[]) => expenses.find((e) => e.id === expenseId)\n * );\n *\n * @example\n * // Total amount — only rerenders when the total changes\n * const total = useSmartQuerySelector(\n * [\"expenses\", tripId],\n * (expenses: Expense[]) => expenses.reduce((s, e) => s + e.amount, 0)\n * );\n */\n\nimport { useCallback, useRef } from \"react\";\nimport { useSyncExternalStore } from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport equal from \"fast-deep-equal\";\n\n/**\n * Subscribe to a derived slice of a TanStack Query cache entry.\n *\n * @param queryKey Must match a useSmartQuery / useInfiniteSmartQuery key.\n * @param selector Pure function — receives the cached data, returns derived value.\n * @param equalityFn Override the equality check. Defaults to fast-deep-equal.\n */\nexport function useSmartQuerySelector<TData, TSelected>(\n queryKey: readonly unknown[],\n selector: (data: TData | undefined) => TSelected,\n equalityFn: (a: TSelected, b: TSelected) => boolean = equal\n): TSelected {\n const queryClient = useQueryClient();\n const selectedRef = useRef<TSelected>(selector(queryClient.getQueryData<TData>(queryKey)));\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n // TanStack Query cache emits on every update to any key.\n // We filter to our key and equality-check the selector output.\n return queryClient.getQueryCache().subscribe((event) => {\n // Only react to updates for our specific query key\n if (\n event.type !== \"updated\" &&\n event.type !== \"added\" &&\n event.type !== \"removed\"\n ) return;\n\n const cacheKey = JSON.stringify(queryKey);\n const eventKey = JSON.stringify(event.query.queryKey);\n if (cacheKey !== eventKey) return;\n\n const newSelected = selector(queryClient.getQueryData<TData>(queryKey));\n\n if (!equalityFn(selectedRef.current, newSelected)) {\n selectedRef.current = newSelected;\n onStoreChange();\n }\n });\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [queryClient, JSON.stringify(queryKey), selector, equalityFn]\n );\n\n const getSnapshot = useCallback(\n () => selectedRef.current,\n []\n );\n\n const getServerSnapshot = useCallback(\n () => selector(undefined),\n [selector]\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n","/**\n * src/factory/createTypedQuery.ts\n *\n * Type-safe query factory — inspired by tRPC's router pattern.\n *\n * Problem:\n * getSmartQueryActions<Expense>([\"expenses\", tripId]) — the Expense type\n * is not connected to the queryKey. You can pass the wrong type silently.\n * Every call site must repeat the type annotation and queryFn.\n *\n * Solution:\n * Define the query once at module level (queryKey shape + queryFn + config).\n * Call sites get pre-typed hooks and actions with full inference.\n *\n * @example\n * // Define once (e.g. src/queries/expense.query.ts)\n * export const expenseQuery = createTypedQuery({\n * queryKey: (tripId: string) => [\"expenses\", tripId] as const,\n * queryFn: (tripId: string) =>\n * api.get(`/trips/${tripId}/expenses`).then((r) => r.data as Expense[]),\n * getItemId: (e: Expense) => e.id,\n * sortComparator: (a: Expense, b: Expense) => b.createdAt - a.createdAt,\n * cacheTtl: 5 * 60_000,\n * });\n *\n * // Use anywhere — fully typed, no annotation needed\n * const { data, addItem } = expenseQuery.useQuery(tripId);\n * const actions = expenseQuery.getActions(tripId);\n * await actions.addItem(newExpense); // TItem = Expense — inferred!\n */\n\nimport { useSmartQuery, SmartQueryOptions, SmartQueryResult } from \"../hooks/useSmartQuery\";\nimport { useSmartMutation, SmartMutationOptions, SmartMutationResult } from \"../hooks/useSmartMutation\";\nimport { getSmartQueryActions, SmartQueryActions } from \"../registry/smartQueryRegistry\";\nimport { invalidateSmartCache } from \"../hooks/useSmartQuery\";\nimport type { AnyItem, GetItemId, SortComparator } from \"../types\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\ntype AnyArgs = readonly unknown[];\n\nexport interface TypedQueryDefinition<\n TArgs extends AnyArgs,\n TRaw,\n TData,\n TItem extends AnyItem = TData extends AnyItem[] ? TData[number] : AnyItem\n> {\n /**\n * Pre-typed useSmartQuery hook.\n * Pass the same args you defined in `queryKey(args)`.\n */\n useQuery(\n ...args: TArgs\n ): SmartQueryResult<TData, TItem>;\n\n /**\n * Pre-typed useSmartMutation hook.\n * Requires only the mutation-specific options (queryKey is pre-filled).\n */\n useMutation(\n ...args: [...TArgs, Omit<SmartMutationOptions<TItem>, \"queryKey\" | \"getItemId\">]\n ): SmartMutationResult<TItem>;\n\n /**\n * Get pre-typed global actions for this query key.\n * Call from anywhere — no React required.\n */\n getActions(...args: TArgs): SmartQueryActions<TItem>;\n\n /** Invalidate this query's cache entry */\n invalidate(...args: TArgs): Promise<void>;\n}\n\n// ─── Factory ──────────────────────────────────────────────────────────────────\n\nexport interface CreateTypedQueryConfig<\n TArgs extends AnyArgs,\n TRaw,\n TData,\n TItem extends AnyItem = TData extends AnyItem[] ? TData[number] : AnyItem\n> {\n /** Build the query key array from args */\n queryKey(...args: TArgs): readonly unknown[];\n\n /** Async function that fetches data — receives the same args */\n queryFn(...args: TArgs): Promise<TRaw>;\n\n /** Transform raw response (optional) */\n select?: (raw: TRaw) => TData;\n\n /** Required for list queries */\n getItemId?: TData extends AnyItem[] ? GetItemId<TItem> : never;\n\n /** Required for list queries */\n sortComparator?: TData extends AnyItem[] ? SortComparator<TItem> : never;\n\n cacheTtl?: number;\n strictFreshness?: boolean;\n\n /** Extra SmartQueryOptions applied to every call */\n defaultOptions?: Partial<SmartQueryOptions<TRaw, TData, TItem>>;\n}\n\n/**\n * Create a type-safe query definition.\n * Returns a typed query object with useQuery, useMutation, getActions, invalidate.\n */\nexport function createTypedQuery<\n TArgs extends AnyArgs,\n TRaw,\n TData,\n TItem extends AnyItem = TData extends AnyItem[] ? TData[number] : AnyItem\n>(\n config: CreateTypedQueryConfig<TArgs, TRaw, TData, TItem>\n): TypedQueryDefinition<TArgs, TRaw, TData, TItem> {\n return {\n useQuery(...args: TArgs) {\n const qk = config.queryKey(...args);\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useSmartQuery<TRaw, TData, TItem>({\n queryKey: qk,\n queryFn: () => config.queryFn(...args),\n select: config.select,\n getItemId: config.getItemId,\n sortComparator: config.sortComparator,\n cacheTtl: config.cacheTtl,\n strictFreshness: config.strictFreshness,\n ...config.defaultOptions,\n });\n },\n\n useMutation(\n ...argsAndOptions: [...TArgs, Omit<SmartMutationOptions<TItem>, \"queryKey\" | \"getItemId\">]\n ) {\n const mutationOptions = argsAndOptions[argsAndOptions.length - 1] as Omit<\n SmartMutationOptions<TItem>,\n \"queryKey\" | \"getItemId\"\n >;\n const args = argsAndOptions.slice(0, -1) as unknown as TArgs;\n const qk = config.queryKey(...args);\n\n if (!config.getItemId) {\n throw new Error(\n \"[SmartQuery] useMutation requires getItemId to be defined in createTypedQuery\"\n );\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useSmartMutation<TItem>({\n queryKey: qk,\n getItemId: config.getItemId as GetItemId<TItem>,\n ...mutationOptions,\n });\n },\n\n getActions(...args: TArgs): SmartQueryActions<TItem> {\n const qk = config.queryKey(...args);\n return getSmartQueryActions<TItem>(qk);\n },\n\n invalidate(...args: TArgs): Promise<void> {\n const qk = config.queryKey(...args);\n return invalidateSmartCache(qk);\n },\n };\n}\n","/**\n * react-smart-query — Public API\n *\n * Import from the package root:\n * import { useSmartQuery, createTypedQuery, ... } from \"react-smart-query\";\n *\n * Test utilities (separate entry point to keep test deps out of prod bundle):\n * import { SmartQueryTestProvider, seedCache } from \"react-smart-query/testing\";\n *\n * Debug tools (side-effect import, dev only):\n * import \"react-smart-query/debug\";\n */\n\n// ── Hooks ──────────────────────────────────────────────────────────────────────\nexport { useSmartQuery, invalidateSmartCache, clearAllSmartCache } from \"./hooks/useSmartQuery\";\nexport type { SmartQueryOptions, SmartQueryResult } from \"./hooks/useSmartQuery\";\n\nexport { useSmartMutation } from \"./hooks/useSmartMutation\";\nexport type { SmartMutationOptions, SmartMutationResult } from \"./hooks/useSmartMutation\";\n\nexport { useInfiniteSmartQuery } from \"./hooks/useInfiniteSmartQuery\";\nexport type { InfiniteSmartQueryOptions, InfiniteSmartQueryResult } from \"./hooks/useInfiniteSmartQuery\";\n\nexport { useSmartQuerySelector } from \"./hooks/useSmartQuerySelector\";\n\n// ── Factory ────────────────────────────────────────────────────────────────────\nexport { createTypedQuery } from \"./factory/createTypedQuery\";\nexport type { TypedQueryDefinition, CreateTypedQueryConfig } from \"./factory/createTypedQuery\";\n\n// ── Registry ───────────────────────────────────────────────────────────────────\nexport { getSmartQueryActions, batchUpdate, smartQueryDebug } from \"./registry/smartQueryRegistry\";\nexport type { SmartQueryActions } from \"./registry/smartQueryRegistry\";\n\n// ── Queue ──────────────────────────────────────────────────────────────────────\nexport {\n registerExecutor,\n enqueueMutation,\n processQueue,\n initQueue,\n clearQueue,\n getQueue,\n getQueueLength,\n} from \"./services/queue.service\";\n\n// ── Observability ──────────────────────────────────────────────────────────────\nexport { addObserver, removeObserver, clearObservers } from \"./services/observer.service\";\nexport type { ObservabilityEvent, ObserverFn } from \"./types\";\n\n// ── Cache ──────────────────────────────────────────────────────────────────────\nexport {\n readCache,\n writeCache,\n deleteCache,\n getPartialCache,\n cacheKeyFor,\n isCacheStale,\n CURRENT_CACHE_VERSION,\n setMaxCacheEntries,\n} from \"./services/cache.service\";\nexport type { CacheEntry } from \"./types\";\n\n// ── Normalize ──────────────────────────────────────────────────────────────────\nexport {\n fromArray,\n toArray,\n normalizedAdd,\n normalizedUpdate,\n normalizedRemove,\n emptyList,\n isNormalizedEmpty,\n trimNormalizedList,\n} from \"./utils/normalize\";\nexport type { NormalizedList } from \"./types\";\n\n// ── Smart compare ──────────────────────────────────────────────────────────────\nexport { smartCompare, isDataEqual } from \"./utils/smartCompare\";\nexport type { SmartCompareOptions, CompareResult } from \"./utils/smartCompare\";\n\n// ── Shared types ───────────────────────────────────────────────────────────────\nexport type {\n AnyItem,\n GetItemId,\n GetItemVersion,\n SortComparator,\n SmartQueryError,\n QueuedMutation,\n MutationType,\n InfinitePagedData,\n AsyncStorage,\n} from \"./types\";\n\n// ── Request lock ───────────────────────────────────────────────────────────────\nexport { fetchWithLock, inFlightCount, inFlightKeys } from \"./services/requestLock.service\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"storage.adapter-PJCVI4DE.mjs"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
3
|
+
import { A as AsyncStorage } from './types-XXiTKLnh.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* src/testing.ts
|
|
7
|
+
*
|
|
8
|
+
* Test utilities for SmartQuery.
|
|
9
|
+
*
|
|
10
|
+
* Provides:
|
|
11
|
+
* • SmartQueryTestProvider — wraps components with all required context
|
|
12
|
+
* • createMockStorage — in-memory AsyncStorage (no MMKV, no IDB)
|
|
13
|
+
* • seedCache — pre-populate cache before rendering
|
|
14
|
+
* • clearTestCache — reset between tests
|
|
15
|
+
* • waitForCacheLoad — await the initial async cache read
|
|
16
|
+
*
|
|
17
|
+
* Works with Jest, Vitest, and React Native Testing Library.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* import { render } from "@testing-library/react-native";
|
|
21
|
+
* import { SmartQueryTestProvider, seedCache } from "react-smart-query/testing";
|
|
22
|
+
*
|
|
23
|
+
* beforeEach(() => seedCache(["expenses", "trip_1"], mockExpenses));
|
|
24
|
+
*
|
|
25
|
+
* it("renders cached expenses", async () => {
|
|
26
|
+
* const { findAllByTestId } = render(
|
|
27
|
+
* <SmartQueryTestProvider>
|
|
28
|
+
* <ExpenseList tripId="trip_1" />
|
|
29
|
+
* </SmartQueryTestProvider>
|
|
30
|
+
* );
|
|
31
|
+
* const rows = await findAllByTestId("expense-row");
|
|
32
|
+
* expect(rows).toHaveLength(mockExpenses.length);
|
|
33
|
+
* });
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
declare function createMockStorage(): AsyncStorage;
|
|
37
|
+
interface TestProviderProps {
|
|
38
|
+
children: ReactNode;
|
|
39
|
+
/** Override the QueryClient (e.g. to set custom defaults) */
|
|
40
|
+
queryClient?: QueryClient;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Wrap your component tree in tests.
|
|
44
|
+
* Automatically uses in-memory storage — no MMKV, no IndexedDB required.
|
|
45
|
+
*/
|
|
46
|
+
declare function SmartQueryTestProvider({ children, queryClient, }: TestProviderProps): React.ReactElement;
|
|
47
|
+
/**
|
|
48
|
+
* Pre-populate the cache before rendering a component.
|
|
49
|
+
* Must be called before rendering (not inside a component).
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* beforeEach(() => seedCache(["expenses", "trip_1"], mockExpenses));
|
|
53
|
+
*/
|
|
54
|
+
declare function seedCache<T>(queryKey: readonly unknown[], data: T): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Clear all test cache entries between tests.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* afterEach(() => clearTestCache());
|
|
60
|
+
*/
|
|
61
|
+
declare function clearTestCache(): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Wait for the initial cache read to complete.
|
|
64
|
+
* Useful when you need to assert on cached data immediately after render.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const { getByText } = render(<MyComponent />);
|
|
68
|
+
* await waitForCacheLoad();
|
|
69
|
+
* expect(getByText("Expense 1")).toBeTruthy();
|
|
70
|
+
*/
|
|
71
|
+
declare function waitForCacheLoad(ms?: number): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Create a mock queryFn that resolves with the provided data.
|
|
74
|
+
* Use to test loading → success transitions.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* queryFn: mockQueryFn(mockExpenses, 100) // resolves after 100ms
|
|
78
|
+
*/
|
|
79
|
+
declare function mockQueryFn<T>(data: T, delayMs?: number): () => Promise<T>;
|
|
80
|
+
/**
|
|
81
|
+
* Create a mock queryFn that rejects with the provided error.
|
|
82
|
+
* Use to test error states.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* queryFn: mockErrorFn(new Error("Network error"))
|
|
86
|
+
*/
|
|
87
|
+
declare function mockErrorFn(error: Error, delayMs?: number): () => Promise<never>;
|
|
88
|
+
|
|
89
|
+
export { SmartQueryTestProvider, clearTestCache, createMockStorage, mockErrorFn, mockQueryFn, seedCache, waitForCacheLoad };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
3
|
+
import { A as AsyncStorage } from './types-XXiTKLnh.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* src/testing.ts
|
|
7
|
+
*
|
|
8
|
+
* Test utilities for SmartQuery.
|
|
9
|
+
*
|
|
10
|
+
* Provides:
|
|
11
|
+
* • SmartQueryTestProvider — wraps components with all required context
|
|
12
|
+
* • createMockStorage — in-memory AsyncStorage (no MMKV, no IDB)
|
|
13
|
+
* • seedCache — pre-populate cache before rendering
|
|
14
|
+
* • clearTestCache — reset between tests
|
|
15
|
+
* • waitForCacheLoad — await the initial async cache read
|
|
16
|
+
*
|
|
17
|
+
* Works with Jest, Vitest, and React Native Testing Library.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* import { render } from "@testing-library/react-native";
|
|
21
|
+
* import { SmartQueryTestProvider, seedCache } from "react-smart-query/testing";
|
|
22
|
+
*
|
|
23
|
+
* beforeEach(() => seedCache(["expenses", "trip_1"], mockExpenses));
|
|
24
|
+
*
|
|
25
|
+
* it("renders cached expenses", async () => {
|
|
26
|
+
* const { findAllByTestId } = render(
|
|
27
|
+
* <SmartQueryTestProvider>
|
|
28
|
+
* <ExpenseList tripId="trip_1" />
|
|
29
|
+
* </SmartQueryTestProvider>
|
|
30
|
+
* );
|
|
31
|
+
* const rows = await findAllByTestId("expense-row");
|
|
32
|
+
* expect(rows).toHaveLength(mockExpenses.length);
|
|
33
|
+
* });
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
declare function createMockStorage(): AsyncStorage;
|
|
37
|
+
interface TestProviderProps {
|
|
38
|
+
children: ReactNode;
|
|
39
|
+
/** Override the QueryClient (e.g. to set custom defaults) */
|
|
40
|
+
queryClient?: QueryClient;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Wrap your component tree in tests.
|
|
44
|
+
* Automatically uses in-memory storage — no MMKV, no IndexedDB required.
|
|
45
|
+
*/
|
|
46
|
+
declare function SmartQueryTestProvider({ children, queryClient, }: TestProviderProps): React.ReactElement;
|
|
47
|
+
/**
|
|
48
|
+
* Pre-populate the cache before rendering a component.
|
|
49
|
+
* Must be called before rendering (not inside a component).
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* beforeEach(() => seedCache(["expenses", "trip_1"], mockExpenses));
|
|
53
|
+
*/
|
|
54
|
+
declare function seedCache<T>(queryKey: readonly unknown[], data: T): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Clear all test cache entries between tests.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* afterEach(() => clearTestCache());
|
|
60
|
+
*/
|
|
61
|
+
declare function clearTestCache(): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Wait for the initial cache read to complete.
|
|
64
|
+
* Useful when you need to assert on cached data immediately after render.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const { getByText } = render(<MyComponent />);
|
|
68
|
+
* await waitForCacheLoad();
|
|
69
|
+
* expect(getByText("Expense 1")).toBeTruthy();
|
|
70
|
+
*/
|
|
71
|
+
declare function waitForCacheLoad(ms?: number): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Create a mock queryFn that resolves with the provided data.
|
|
74
|
+
* Use to test loading → success transitions.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* queryFn: mockQueryFn(mockExpenses, 100) // resolves after 100ms
|
|
78
|
+
*/
|
|
79
|
+
declare function mockQueryFn<T>(data: T, delayMs?: number): () => Promise<T>;
|
|
80
|
+
/**
|
|
81
|
+
* Create a mock queryFn that rejects with the provided error.
|
|
82
|
+
* Use to test error states.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* queryFn: mockErrorFn(new Error("Network error"))
|
|
86
|
+
*/
|
|
87
|
+
declare function mockErrorFn(error: Error, delayMs?: number): () => Promise<never>;
|
|
88
|
+
|
|
89
|
+
export { SmartQueryTestProvider, clearTestCache, createMockStorage, mockErrorFn, mockQueryFn, seedCache, waitForCacheLoad };
|