diff --git a/app/composables/useCachedFetch.ts b/app/composables/useCachedFetch.ts index c2bf0b741f..1c23277783 100644 --- a/app/composables/useCachedFetch.ts +++ b/app/composables/useCachedFetch.ts @@ -34,14 +34,10 @@ export function useCachedFetch(): CachedFetchFunction { if (import.meta.client) { return async ( url: string, - options: { - method?: string - body?: unknown - headers?: Record - } = {}, + options: Parameters[1] = {}, _ttl?: number, ): Promise> => { - const data = (await $fetch(url, options as Parameters[1])) as T + const data = (await $fetch(url, options)) as T return { data, isStale: false, cachedAt: null } } } @@ -59,14 +55,10 @@ export function useCachedFetch(): CachedFetchFunction { // (shouldn't happen in normal operation) return async ( url: string, - options: { - method?: string - body?: unknown - headers?: Record - } = {}, + options: Parameters[1] = {}, _ttl?: number, ): Promise> => { - const data = (await $fetch(url, options as Parameters[1])) as T + const data = (await $fetch(url, options)) as T return { data, isStale: false, cachedAt: null } } } diff --git a/app/composables/useNpmRegistry.ts b/app/composables/useNpmRegistry.ts index 109980cca0..2f8d10b255 100644 --- a/app/composables/useNpmRegistry.ts +++ b/app/composables/useNpmRegistry.ts @@ -185,9 +185,11 @@ export function usePackage( const asyncData = useLazyAsyncData( () => `package:${toValue(name)}:${toValue(requestedVersion) ?? ''}`, - async () => { + async (_nuxtApp, { signal }) => { const encodedName = encodePackageName(toValue(name)) - const { data: r, isStale } = await cachedFetch(`${NPM_REGISTRY}/${encodedName}`) + const { data: r, isStale } = await cachedFetch(`${NPM_REGISTRY}/${encodedName}`, { + signal, + }) const reqVer = toValue(requestedVersion) const pkg = transformPackument(r, reqVer) const resolvedVersion = getResolvedVersion(pkg, reqVer) @@ -233,10 +235,11 @@ export function usePackageDownloads( const asyncData = useLazyAsyncData( () => `downloads:${toValue(name)}:${toValue(period)}`, - async () => { + async (_nuxtApp, { signal }) => { const encodedName = encodePackageName(toValue(name)) const { data, isStale } = await cachedFetch( `${NPM_API}/downloads/point/${toValue(period)}/${encodedName}`, + { signal }, ) return { ...data, isStale } }, @@ -306,7 +309,7 @@ export function useNpmSearch( const asyncData = useLazyAsyncData( () => `search:incremental:${toValue(query)}`, - async () => { + async (_nuxtApp, { signal }) => { const q = toValue(query) if (!q.trim()) { return emptySearchResponse @@ -325,7 +328,7 @@ export function useNpmSearch( const { data: response, isStale } = await cachedFetch( `${NPM_REGISTRY}/-/v1/search?${params.toString()}`, - {}, + { signal }, 60, ) @@ -509,7 +512,7 @@ export function useOrgPackages(orgName: MaybeRefOrGetter) { const asyncData = useLazyAsyncData( () => `org-packages:${toValue(orgName)}`, - async () => { + async (_nuxtApp, { signal }) => { const org = toValue(orgName) if (!org) { return emptySearchResponse @@ -520,6 +523,7 @@ export function useOrgPackages(orgName: MaybeRefOrGetter) { try { const { data } = await cachedFetch>( `${NPM_REGISTRY}/-/org/${encodeURIComponent(org)}/package`, + { signal }, ) packageNames = Object.keys(data) } catch (err) { @@ -553,6 +557,7 @@ export function useOrgPackages(orgName: MaybeRefOrGetter) { const encoded = encodePackageName(name) const { data: pkg } = await cachedFetch( `${NPM_REGISTRY}/${encoded}`, + { signal }, ) return pkg } catch { diff --git a/app/composables/useRepoMeta.ts b/app/composables/useRepoMeta.ts index 0e6d392334..af60bbe413 100644 --- a/app/composables/useRepoMeta.ts +++ b/app/composables/useRepoMeta.ts @@ -93,6 +93,7 @@ type ProviderAdapter = { cachedFetch: CachedFetchFunction, ref: RepoRef, links: RepoMetaLinks, + options?: Parameters[1], ): Promise } @@ -126,13 +127,13 @@ const githubAdapter: ProviderAdapter = { } }, - async fetchMeta(cachedFetch, ref, links) { + async fetchMeta(cachedFetch, ref, links, options = {}) { // Using UNGH to avoid API limitations of the Github API let res: UnghRepoResponse | null = null try { const { data } = await cachedFetch( `https://ungh.cc/repos/${ref.owner}/${ref.repo}`, - { headers: { 'User-Agent': 'npmx' } }, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, REPO_META_TTL, ) res = data @@ -191,14 +192,14 @@ const gitlabAdapter: ProviderAdapter = { } }, - async fetchMeta(cachedFetch, ref, links) { + async fetchMeta(cachedFetch, ref, links, options = {}) { const baseHost = ref.host ?? 'gitlab.com' const projectPath = encodeURIComponent(`${ref.owner}/${ref.repo}`) let res: GitLabProjectResponse | null = null try { const { data } = await cachedFetch( `https://${baseHost}/api/v4/projects/${projectPath}`, - { headers: { 'User-Agent': 'npmx' } }, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, REPO_META_TTL, ) res = data @@ -249,12 +250,12 @@ const bitbucketAdapter: ProviderAdapter = { } }, - async fetchMeta(cachedFetch, ref, links) { + async fetchMeta(cachedFetch, ref, links, options = {}) { let res: BitbucketRepoResponse | null = null try { const { data } = await cachedFetch( `https://api.bitbucket.org/2.0/repositories/${ref.owner}/${ref.repo}`, - { headers: { 'User-Agent': 'npmx' } }, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, REPO_META_TTL, ) res = data @@ -307,12 +308,12 @@ const codebergAdapter: ProviderAdapter = { } }, - async fetchMeta(cachedFetch, ref, links) { + async fetchMeta(cachedFetch, ref, links, options = {}) { let res: GiteaRepoResponse | null = null try { const { data } = await cachedFetch( `https://codeberg.org/api/v1/repos/${ref.owner}/${ref.repo}`, - { headers: { 'User-Agent': 'npmx' } }, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, REPO_META_TTL, ) res = data @@ -365,12 +366,12 @@ const giteeAdapter: ProviderAdapter = { } }, - async fetchMeta(cachedFetch, ref, links) { + async fetchMeta(cachedFetch, ref, links, options = {}) { let res: GiteeRepoResponse | null = null try { const { data } = await cachedFetch( `https://gitee.com/api/v5/repos/${ref.owner}/${ref.repo}`, - { headers: { 'User-Agent': 'npmx' } }, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, REPO_META_TTL, ) res = data @@ -452,7 +453,7 @@ const giteaAdapter: ProviderAdapter = { } }, - async fetchMeta(cachedFetch, ref, links) { + async fetchMeta(cachedFetch, ref, links, options = {}) { if (!ref.host) return null // Note: Generic Gitea instances may not be in the allowlist, @@ -461,7 +462,7 @@ const giteaAdapter: ProviderAdapter = { try { const { data } = await cachedFetch( `https://${ref.host}/api/v1/repos/${ref.owner}/${ref.repo}`, - { headers: { 'User-Agent': 'npmx' } }, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, REPO_META_TTL, ) res = data @@ -564,13 +565,16 @@ const tangledAdapter: ProviderAdapter = { } }, - async fetchMeta(cachedFetch, ref, links) { + async fetchMeta(cachedFetch, ref, links, options = {}) { // Tangled doesn't have a public JSON API, but we can scrape the star count // from the HTML page (it's in the hx-post URL as countHint=N) try { const { data: html } = await cachedFetch( `https://tangled.org/${ref.owner}/${ref.repo}`, - { headers: { 'User-Agent': 'npmx', 'Accept': 'text/html' } }, + { + headers: { 'User-Agent': 'npmx', 'Accept': 'text/html', ...options.headers }, + ...options, + }, REPO_META_TTL, ) // Extracts the at-uri used in atproto @@ -640,12 +644,12 @@ const radicleAdapter: ProviderAdapter = { } }, - async fetchMeta(cachedFetch, ref, links) { + async fetchMeta(cachedFetch, ref, links, options = {}) { let res: RadicleProjectResponse | null = null try { const { data } = await cachedFetch( `https://seed.radicle.at/api/v1/projects/${ref.repo}`, - { headers: { 'User-Agent': 'npmx' } }, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, REPO_META_TTL, ) res = data @@ -704,14 +708,14 @@ const forgejoAdapter: ProviderAdapter = { } }, - async fetchMeta(cachedFetch, ref, links) { + async fetchMeta(cachedFetch, ref, links, options = {}) { if (!ref.host) return null let res: GiteaRepoResponse | null = null try { const { data } = await cachedFetch( `https://${ref.host}/api/v1/repos/${ref.owner}/${ref.repo}`, - { headers: { 'User-Agent': 'npmx' } }, + { headers: { 'User-Agent': 'npmx', ...options.headers }, ...options }, REPO_META_TTL, ) res = data @@ -766,7 +770,7 @@ export function useRepoMeta(repositoryUrl: MaybeRefOrGetter { + async (_nuxtApp, { signal }) => { const ref = repoRef.value if (!ref) return null @@ -774,7 +778,7 @@ export function useRepoMeta(repositoryUrl: MaybeRefOrGetter { function createCachedFetch(event: H3Event): CachedFetchFunction { return async ( url: string, - options: { - method?: string - body?: unknown - headers?: Record - } = {}, + options: Parameters[1] = {}, ttl: number = FETCH_CACHE_DEFAULT_TTL, ): Promise> => { // Check if this URL should be cached if (!isAllowedDomain(url)) { - const data = (await $fetch(url, options as Parameters[1])) as T + const data = (await $fetch(url, options)) as T return { data, isStale: false, cachedAt: null } } diff --git a/shared/utils/fetch-cache-config.ts b/shared/utils/fetch-cache-config.ts index 16b2ad8e9c..83c1467437 100644 --- a/shared/utils/fetch-cache-config.ts +++ b/shared/utils/fetch-cache-config.ts @@ -105,10 +105,6 @@ export interface CachedFetchResult { */ export type CachedFetchFunction = ( url: string, - options?: { - method?: string - body?: unknown - headers?: Record - }, + options?: Parameters[1], ttl?: number, ) => Promise>