feat(dashboard): fetch download manifests dynamically (#675)

This commit is contained in:
shenlan 2025-11-11 23:19:43 +08:00 committed by GitHub
parent eae77beeea
commit 5d1f442584
7 changed files with 41 additions and 56 deletions

View File

@ -10,7 +10,7 @@
"prebuild": "tsx ../scripts/export-slugs.ts && tsx ../scripts/scan-md.ts && tsx ../scripts/fetch-dl-index.ts && node ../scripts/copy-manifests.js",
"build": "next build",
"build:static": "npm run prebuild && next build",
"start": "next start",
"start": "node ./scripts/start.js",
"lint": "next lint",
"typecheck": "tsc --noEmit",
"format": "prettier --write .",

View File

@ -0,0 +1,23 @@
#!/usr/bin/env node
const { spawn } = require('node:child_process')
const args = process.argv.slice(2)
const child = spawn('next', ['start', ...args], {
stdio: 'inherit',
shell: process.platform === 'win32',
})
child.on('error', (error) => {
console.error('Failed to launch Next.js:', error)
process.exit(1)
})
child.on('close', (code, signal) => {
if (signal) {
process.kill(process.pid, signal)
} else {
process.exit(code ?? 0)
}
})

View File

@ -1,4 +1,4 @@
export const dynamic = 'error'
export const dynamic = 'force-dynamic'
import { notFound } from 'next/navigation'

View File

@ -32,7 +32,7 @@ interface RawDocResource {
async function fetchDocs(): Promise<RawDocResource[]> {
try {
const response = await fetch(DOCS_MANIFEST_URL, {
cache: 'no-cache',
cache: 'no-store',
})
if (!response.ok) {
@ -58,15 +58,8 @@ async function loadDocs(): Promise<RawDocResource[]> {
return fallbackDocs
}
let cachedDocs: RawDocResource[] | null = null
async function getRawDocs(): Promise<RawDocResource[]> {
if (cachedDocs) {
return cachedDocs
}
cachedDocs = await loadDocs()
return cachedDocs
return loadDocs()
}
async function buildDocsDataset(): Promise<DocResource[]> {
@ -76,20 +69,12 @@ async function buildDocsDataset(): Promise<DocResource[]> {
)
}
let cachedDocsDataset: DocResource[] | null = null
export async function getDocsDataset(): Promise<DocResource[]> {
if (cachedDocsDataset) {
return cachedDocsDataset
}
cachedDocsDataset = await buildDocsDataset()
return cachedDocsDataset
return buildDocsDataset()
}
export function clearDocsCache(): void {
cachedDocs = null
cachedDocsDataset = null
// Intentionally left blank. Runtime fetches always return fresh data.
}
@ -258,20 +243,12 @@ async function buildDocsCollections(): Promise<DocCollection[]> {
return buildCollections(docs)
}
let cachedCollections: DocCollection[] | null = null
export async function getDocCollections(): Promise<DocCollection[]> {
if (cachedCollections) {
return cachedCollections
}
cachedCollections = await buildDocsCollections()
return cachedCollections
return buildDocsCollections()
}
export function clearCollectionsCache(): void {
clearDocsCache()
cachedCollections = null
}
function normalizeResource(item: RawDocResource): DocResource | null {

View File

@ -1,4 +1,4 @@
export const dynamic = 'error'
export const dynamic = 'force-dynamic'
import { notFound } from 'next/navigation'

View File

@ -2,15 +2,14 @@ import 'server-only'
import type { DirListing } from '@lib/download/types'
import fallbackArtifacts from '../../../public/_build/artifacts-manifest.json'
import fallbackOfflinePackage from '../../../public/_build/offline-package.json'
const ARTIFACTS_MANIFEST_URL = 'https://dl.svc.plus/dl-index/artifacts-manifest.json'
const FALLBACK_LISTINGS_URL = 'https://dl.svc.plus/dl-index/offline-package.json'
const FALLBACK_LISTINGS_URL = 'https://dl.svc.plus/dl-index/offline-package-manifest.json'
async function fetchListings(url: string): Promise<DirListing[]> {
try {
const response = await fetch(url, {
cache: 'no-cache',
cache: 'no-store',
})
if (!response.ok) {
@ -41,17 +40,10 @@ async function loadDownloadListings(): Promise<DirListing[]> {
return fallbackArtifacts as DirListing[]
}
let cachedListings: DirListing[] | null = null
export async function getDownloadListings(): Promise<DirListing[]> {
if (cachedListings) {
return cachedListings
}
cachedListings = await loadDownloadListings()
return cachedListings
return loadDownloadListings()
}
export function clearDownloadListingsCache(): void {
cachedListings = null
}
// Intentionally left blank. Runtime fetches always return fresh data.
}

View File

@ -10,7 +10,7 @@ const OFFLINE_PACKAGE_URL = 'https://dl.svc.plus/dl-index/offline-package-manife
export async function fetchOfflinePackageListings(): Promise<DirListing[]> {
try {
const response = await fetch(OFFLINE_PACKAGE_URL, {
cache: 'no-cache',
cache: 'no-store',
})
if (!response.ok) {
@ -27,18 +27,11 @@ export async function fetchOfflinePackageListings(): Promise<DirListing[]> {
}
/**
* Get cached offline-package listings
* This is a simple in-memory cache - in production you might want to use a more robust solution
* Retrieve offline-package listings on demand.
* Data is fetched dynamically so updates are reflected without a deploy.
*/
let cachedListings: DirListing[] | null = null
export async function getOfflinePackageListings(): Promise<DirListing[]> {
if (cachedListings) {
return cachedListings
}
cachedListings = await fetchOfflinePackageListings()
return cachedListings
return fetchOfflinePackageListings()
}
/**
@ -78,5 +71,5 @@ export async function getOfflinePackageFileCount(): Promise<number> {
* Clear the cache (useful for testing or when data might have changed)
*/
export function clearOfflinePackageCache(): void {
cachedListings = null
// Intentionally left blank. Runtime fetches always return fresh data.
}