Skip to content

Commit ee9e7db

Browse files
committed
fix: polish and cleanup post prototype
1 parent 20ae356 commit ee9e7db

8 files changed

Lines changed: 281 additions & 333 deletions

File tree

app/pages/docs/[...path].vue

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
22
import type { DocsResponse } from '#shared/types'
3+
import { assertValidPackageName } from '#shared/utils/npm'
34
45
definePageMeta({
56
name: 'docs',
@@ -28,6 +29,11 @@ const parsedRoute = computed(() => {
2829
const packageName = computed(() => parsedRoute.value.packageName)
2930
const requestedVersion = computed(() => parsedRoute.value.version)
3031
32+
// Validate package name on server-side for early error detection
33+
if (import.meta.server && packageName.value) {
34+
assertValidPackageName(packageName.value)
35+
}
36+
3137
const { data: pkg } = usePackage(packageName)
3238
3339
const latestVersion = computed(() => pkg.value?.['dist-tags']?.latest ?? null)
@@ -51,19 +57,21 @@ const docsUrl = computed(() => {
5157
5258
const shouldFetch = computed(() => !!docsUrl.value)
5359
54-
const { data: docsData, status: docsStatus } = useLazyFetch<DocsResponse>(() => docsUrl.value!, {
55-
watch: [docsUrl],
56-
immediate: shouldFetch.value,
57-
default: () => ({
58-
package: packageName.value,
59-
version: resolvedVersion.value ?? '',
60-
html: '',
61-
toc: null,
62-
breadcrumbs: null,
63-
status: 'missing',
64-
message: 'Docs are not available for this version.',
65-
}),
66-
})
60+
const { data: docsData, status: docsStatus } = useLazyFetch<DocsResponse>(
61+
() => docsUrl.value ?? '',
62+
{
63+
watch: [docsUrl],
64+
immediate: shouldFetch.value,
65+
default: () => ({
66+
package: packageName.value,
67+
version: resolvedVersion.value ?? '',
68+
html: '',
69+
toc: null,
70+
status: 'missing',
71+
message: 'Docs are not available for this version.',
72+
}),
73+
},
74+
)
6775
6876
const pageTitle = computed(() => {
6977
if (!packageName.value) return 'API Docs - npmx'

pnpm-lock.yaml

Lines changed: 1 addition & 89 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
packages:
22
- '.'
33
- 'cli'
4-
- 'prototypes/*'
54

65
overrides:
76
sharp: 0.34.5

server/api/registry/docs/[...pkg].get.ts

Lines changed: 17 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,49 @@
11
import type { DocsResponse } from '#shared/types'
22
import { fetchNpmPackage } from '#server/utils/npm'
3-
import { assertValidPackageName } from '#shared/utils/npm'
3+
import { assertValidPackageName, parsePackageParam } from '#shared/utils/npm'
44
import { generateDocsWithDeno } from '#server/utils/docs'
55

66
export default defineCachedEventHandler(
77
async (event) => {
8-
const segments = getRouterParam(event, 'pkg')?.split('/') ?? []
9-
if (segments.length === 0) {
8+
const pkgParam = getRouterParam(event, 'pkg')
9+
if (!pkgParam) {
1010
throw createError({ statusCode: 400, message: 'Package name is required' })
1111
}
1212

13-
// Parse package name and optional version from URL segments
14-
// Patterns: [pkg] or [pkg, 'v', version] or [@scope, pkg] or [@scope, pkg, 'v', version]
15-
let packageName: string
16-
let version: string | undefined
17-
18-
const vIndex = segments.indexOf('v')
19-
if (vIndex !== -1 && vIndex < segments.length - 1) {
20-
packageName = segments.slice(0, vIndex).join('/')
21-
version = segments.slice(vIndex + 1).join('/')
22-
}
23-
else {
24-
packageName = segments.join('/')
25-
}
13+
const { packageName, version: requestedVersion } = parsePackageParam(pkgParam)
2614

2715
if (!packageName) {
2816
throw createError({ statusCode: 400, message: 'Package name is required' })
2917
}
3018
assertValidPackageName(packageName)
3119

3220
const packument = await fetchNpmPackage(packageName)
33-
34-
if (!version) {
35-
version = packument['dist-tags']?.latest
36-
}
21+
const version = requestedVersion ?? packument['dist-tags']?.latest
3722

3823
if (!version) {
3924
throw createError({ statusCode: 404, message: 'No latest version found' })
4025
}
4126

42-
try {
43-
const generated = await generateDocsWithDeno(packageName, version)
44-
45-
if (!generated) {
46-
return {
47-
package: packageName,
48-
version,
49-
html: '',
50-
toc: null,
51-
breadcrumbs: null,
52-
status: 'missing',
53-
message: 'Docs are not available for this package. It may not have TypeScript types.',
54-
} satisfies DocsResponse
55-
}
56-
57-
return {
58-
package: packageName,
59-
version,
60-
html: generated.html,
61-
toc: generated.toc,
62-
breadcrumbs: null,
63-
status: 'ok',
64-
} satisfies DocsResponse
65-
}
66-
catch (error) {
67-
const message = error instanceof Error ? error.message : 'Unknown error'
68-
console.error(`[docs] Error generating docs for ${packageName}@${version}:`, message)
27+
const generated = await generateDocsWithDeno(packageName, version)
6928

29+
if (!generated) {
7030
return {
7131
package: packageName,
7232
version,
7333
html: '',
7434
toc: null,
75-
breadcrumbs: null,
76-
status: 'error',
77-
message: 'Failed to generate docs. The package may not export TypeScript types.',
35+
status: 'missing',
36+
message: 'Docs are not available for this package. It may not have TypeScript types.',
7837
} satisfies DocsResponse
7938
}
39+
40+
return {
41+
package: packageName,
42+
version,
43+
html: generated.html,
44+
toc: generated.toc,
45+
status: 'ok',
46+
} satisfies DocsResponse
8047
},
8148
{
8249
maxAge: 60 * 60, // 1 hour cache

0 commit comments

Comments
 (0)