Skip to content

Commit 5e1361c

Browse files
committed
wip: more request deduplications
1 parent 8825b0a commit 5e1361c

3 files changed

Lines changed: 41 additions & 25 deletions

File tree

app/components/ClaimPackageModal.vue

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,31 +18,33 @@ const {
1818
refreshState,
1919
} = useConnector()
2020
21-
// Fetch name availability when modal opens
22-
const checkResult = shallowRef<CheckNameResult | null>(null)
23-
24-
const isChecking = shallowRef(false)
2521
const isPublishing = shallowRef(false)
26-
const publishError = shallowRef<string | null>(null)
2722
const publishSuccess = shallowRef(false)
2823
29-
async function checkAvailability() {
30-
isChecking.value = true
31-
publishError.value = null
32-
try {
33-
checkResult.value = await checkPackageName(props.packageName)
34-
} catch (err) {
35-
publishError.value = err instanceof Error ? err.message : $t('claim.modal.failed_to_check')
36-
} finally {
37-
isChecking.value = false
38-
}
39-
}
24+
const {
25+
data: checkResult,
26+
refresh: checkAvailability,
27+
status,
28+
error,
29+
} = useAsyncData(
30+
(_nuxtApp, { signal }) => {
31+
return checkPackageName(props.packageName, { signal })
32+
},
33+
{ default: () => null, immediate: false },
34+
)
35+
36+
const isChecking = computed(() => {
37+
return status.value === 'pending'
38+
})
39+
40+
const publishError = computed(() => {
41+
return error.value instanceof Error ? error.value.message : $t('claim.modal.failed_to_check')
42+
})
4043
4144
async function handleClaim() {
4245
if (!checkResult.value?.available || !isConnected.value) return
4346
4447
isPublishing.value = true
45-
publishError.value = null
4648
4749
try {
4850
// Add the operation

app/composables/useNpmRegistry.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ const packumentCache = new Map<string, Promise<Packument | null>>()
2626
* Uses bulk API for unscoped packages, parallel individual requests for scoped.
2727
* Note: npm bulk downloads API does not support scoped packages.
2828
*/
29-
async function fetchBulkDownloads(packageNames: string[]): Promise<Map<string, number>> {
29+
async function fetchBulkDownloads(
30+
packageNames: string[],
31+
options: Parameters<typeof $fetch>[1] = {},
32+
): Promise<Map<string, number>> {
3033
const downloads = new Map<string, number>()
3134
if (packageNames.length === 0) return downloads
3235

@@ -44,6 +47,7 @@ async function fetchBulkDownloads(packageNames: string[]): Promise<Map<string, n
4447
try {
4548
const response = await $fetch<Record<string, { downloads: number } | null>>(
4649
`${NPM_API}/downloads/point/last-week/${chunk.join(',')}`,
50+
options,
4751
)
4852
for (const [name, data] of Object.entries(response)) {
4953
if (data?.downloads !== undefined) {
@@ -575,7 +579,7 @@ export function useOrgPackages(orgName: MaybeRefOrGetter<string>) {
575579
return results
576580
})(),
577581
// Fetch downloads in bulk
578-
fetchBulkDownloads(packageNames),
582+
fetchBulkDownloads(packageNames, { signal }),
579583
])
580584

581585
// Convert to search results with download data

app/utils/package-name.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,17 @@ export interface CheckNameResult {
7272

7373
const NPM_REGISTRY = 'https://registry.npmjs.org'
7474

75-
export async function checkPackageExists(name: string): Promise<boolean> {
75+
export async function checkPackageExists(
76+
name: string,
77+
options: Parameters<typeof $fetch>[1] = {},
78+
): Promise<boolean> {
7679
try {
7780
const encodedName = name.startsWith('@')
7881
? `@${encodeURIComponent(name.slice(1))}`
7982
: encodeURIComponent(name)
8083

8184
await $fetch(`${NPM_REGISTRY}/${encodedName}`, {
85+
...options,
8286
method: 'HEAD',
8387
})
8488
return true
@@ -87,7 +91,10 @@ export async function checkPackageExists(name: string): Promise<boolean> {
8791
}
8892
}
8993

90-
export async function findSimilarPackages(name: string): Promise<SimilarPackage[]> {
94+
export async function findSimilarPackages(
95+
name: string,
96+
options: Parameters<typeof $fetch>[1] = {},
97+
): Promise<SimilarPackage[]> {
9198
const normalized = normalizePackageName(name)
9299
const similar: SimilarPackage[] = []
93100

@@ -99,7 +106,7 @@ export async function findSimilarPackages(name: string): Promise<SimilarPackage[
99106
description?: string
100107
}
101108
}>
102-
}>(`${NPM_REGISTRY}/-/v1/search?text=${encodeURIComponent(name)}&size=20`)
109+
}>(`${NPM_REGISTRY}/-/v1/search?text=${encodeURIComponent(name)}&size=20`, options)
103110

104111
for (const obj of searchResponse.objects) {
105112
const pkgName = obj.package.name
@@ -153,7 +160,10 @@ export async function findSimilarPackages(name: string): Promise<SimilarPackage[
153160
}
154161
}
155162

156-
export async function checkPackageName(name: string): Promise<CheckNameResult> {
163+
export async function checkPackageName(
164+
name: string,
165+
options: Parameters<typeof $fetch>[1] = {},
166+
): Promise<CheckNameResult> {
157167
const validation = validatePackageName(name)
158168
const valid = validation.validForNewPackages === true
159169

@@ -177,8 +187,8 @@ export async function checkPackageName(name: string): Promise<CheckNameResult> {
177187

178188
// Check if package exists and find similar packages in parallel
179189
const [exists, similarPackages] = await Promise.all([
180-
checkPackageExists(name),
181-
findSimilarPackages(name),
190+
checkPackageExists(name, options),
191+
findSimilarPackages(name, options),
182192
])
183193

184194
result.available = !exists

0 commit comments

Comments
 (0)