-
-
Notifications
You must be signed in to change notification settings - Fork 427
Expand file tree
/
Copy pathuseCachedFetch.ts
More file actions
85 lines (80 loc) · 2.57 KB
/
useCachedFetch.ts
File metadata and controls
85 lines (80 loc) · 2.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import type { CachedFetchResult } from '#shared/utils/fetch-cache-config'
/**
* Type for the cachedFetch function attached to event context.
*/
export type CachedFetchFunction = <T = unknown>(
url: string,
options?: {
method?: string
body?: unknown
headers?: Record<string, string>
},
ttl?: number,
) => Promise<CachedFetchResult<T>>
/**
* Get the cachedFetch function from the current request context.
*
* IMPORTANT: This must be called in the composable setup context (outside of
* useAsyncData handlers). The returned function can then be used inside handlers.
*
* The returned function returns a wrapper object with staleness metadata:
* - `data`: The response data
* - `isStale`: Whether the data came from stale cache
* - `cachedAt`: Unix timestamp when cached, or null if fresh fetch
*
* @example
* ```ts
* export function usePackage(name: MaybeRefOrGetter<string>) {
* // Get cachedFetch in setup context
* const cachedFetch = useCachedFetch()
*
* return useLazyAsyncData(
* () => `package:${toValue(name)}`,
* // Use it inside the handler - destructure { data } or { data, isStale }
* async () => {
* const { data } = await cachedFetch<Packument>(`https://registry.npmjs.org/${toValue(name)}`)
* return data
* }
* )
* }
* ```
* @public
*/
export function useCachedFetch(): CachedFetchFunction {
// On client, return a function that just uses $fetch (no caching, not stale)
if (import.meta.client) {
return async <T = unknown>(
url: string,
options: {
method?: string
body?: unknown
headers?: Record<string, string>
} = {},
_ttl?: number,
): Promise<CachedFetchResult<T>> => {
const data = (await $fetch(url, options as Parameters<typeof $fetch>[1])) as T
return { data, isStale: false, cachedAt: null }
}
}
// On server, get the cachedFetch from request context
const event = useRequestEvent()
const serverCachedFetch = event?.context?.cachedFetch
// If cachedFetch is available from middleware, return it
if (serverCachedFetch) {
return serverCachedFetch as CachedFetchFunction
}
// Fallback: return a function that uses regular $fetch
// (shouldn't happen in normal operation)
return async <T = unknown>(
url: string,
options: {
method?: string
body?: unknown
headers?: Record<string, string>
} = {},
_ttl?: number,
): Promise<CachedFetchResult<T>> => {
const data = (await $fetch(url, options as Parameters<typeof $fetch>[1])) as T
return { data, isStale: false, cachedAt: null }
}
}