大 更 新

This commit is contained in:
RiseForever
2026-08-12 01:11:32 +08:00
parent 6570961102
commit c382cd642a
69 changed files with 19471 additions and 16 deletions
+100
View File
@@ -0,0 +1,100 @@
import { readdir, readFile, writeFile, mkdir, rm } from 'node:fs/promises';
import { dirname, join } from 'node:path';
const root = process.cwd();
const cacheDir = join(root, '.astro-cache');
const cachePath = process.env.GITHUB_CACHE_PATH ? join(root, process.env.GITHUB_CACHE_PATH) : join(cacheDir, 'github.json');
const contentDir = join(root, 'src', 'content');
const ttlMs = Number(process.env.GITHUB_CACHE_TTL_MS ?? 24 * 60 * 60 * 1000);
const timeoutMs = Number(process.env.GITHUB_API_TIMEOUT_MS ?? 8000);
const validRepository = /^[A-Za-z0-9](?:[A-Za-z0-9_.-]{0,38})\/[A-Za-z0-9](?:[A-Za-z0-9_.-]{0,99})$/;
async function contentFiles(directory) {
const files = [];
for (const entry of await readdir(directory, { withFileTypes: true })) {
const path = join(directory, entry.name);
if (entry.isDirectory()) files.push(...await contentFiles(path));
else if (/\.(md|mdx)$/i.test(entry.name)) files.push(path);
}
return files;
}
function repositoriesFrom(source) {
const repositories = [];
let fence = null;
for (const line of source.matchAll(/^[^\n]*(?:\n|$)/gm)) {
const text = line[0].trim();
const fenceMatch = text.match(/^(`{3,}|~{3,})/);
if (fenceMatch) {
if (!fence) fence = fenceMatch[1][0];
else if (fenceMatch[1][0] === fence) fence = null;
continue;
}
if (fence) continue;
const tag = text.match(/^\[github\b([^\]]*)/i);
const value = tag?.[1].match(/(?:^|\s)(?:repo|repository)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s\]]+))/i);
const repository = value?.[1] ?? value?.[2] ?? value?.[3];
if (repository && validRepository.test(repository.trim())) repositories.push(repository.trim().toLowerCase());
}
return repositories;
}
async function readCache() {
try {
const cache = JSON.parse(await readFile(cachePath, 'utf8'));
return cache?.repositories && typeof cache.repositories === 'object' ? cache : { repositories: {} };
} catch (error) {
if (error?.code !== 'ENOENT') console.warn('[github] Could not read .astro-cache/github.json; rebuilding it.');
return { repositories: {} };
}
}
async function fetchRepository(repository) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
const headers = { Accept: 'application/vnd.github+json', 'User-Agent': 'mirages-astro-build' };
if (process.env.GITHUB_TOKEN) headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
try {
const response = await fetch(`https://api.github.com/repos/${repository}`, { headers, signal: controller.signal });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
if (data.private) throw new Error('private repositories are not supported');
if (typeof data.stargazers_count !== 'number' || typeof data.forks_count !== 'number' || typeof data.html_url !== 'string') throw new Error('unexpected API response');
return {
stars: String(data.stargazers_count),
forks: String(data.forks_count),
description: typeof data.description === 'string' ? data.description : '',
commitDate: typeof data.pushed_at === 'string' ? data.pushed_at : '',
htmlUrl: data.html_url,
defaultBranch: typeof data.default_branch === 'string' && data.default_branch ? data.default_branch : 'main',
fetchedAt: new Date().toISOString()
};
} finally {
clearTimeout(timeout);
}
}
const repositories = new Set();
for (const file of await contentFiles(contentDir)) {
for (const repository of repositoriesFrom(await readFile(file, 'utf8'))) repositories.add(repository);
}
const cache = await readCache();
const now = Date.now();
let successful = 0;
for (const repository of repositories) {
const cached = cache.repositories[repository];
if (cached?.fetchedAt && now - Date.parse(cached.fetchedAt) < ttlMs) continue;
try {
cache.repositories[repository] = await fetchRepository(repository);
successful += 1;
console.log(`[github] fetched ${repository}`);
} catch (error) {
console.warn(`[github] ${repository}: ${error instanceof Error ? error.message : 'request failed'}; using ${cached ? 'cached data' : 'fallback values'}.`);
}
}
await mkdir(dirname(cachePath), { recursive: true });
await writeFile(cachePath, `${JSON.stringify({ version: 1, generatedAt: new Date().toISOString(), repositories: cache.repositories }, null, 2)}\n`);
await rm(join(root, '.astro'), { recursive: true, force: true });
console.log(`[github] cache ${cachePath} (${successful} request${successful === 1 ? '' : 's'}, ${repositories.size} repos)`);