mirror of
https://github.com/Lissy93/awesome-privacy.git
synced 2026-03-11 08:55:33 +00:00
Fixes web build, update github info fetch logic, adds build error log
This commit is contained in:
parent
11542c9372
commit
122bb0fc43
12 changed files with 239 additions and 45 deletions
|
|
@ -4,6 +4,7 @@ import { defineConfig } from 'astro/config';
|
|||
import svelte from '@astrojs/svelte';
|
||||
import partytown from '@astrojs/partytown';
|
||||
import sitemap from '@astrojs/sitemap';
|
||||
import { printSummary } from './src/utils/logger.ts';
|
||||
|
||||
// Adapters
|
||||
import vercelAdapter from '@astrojs/vercel/serverless';
|
||||
|
|
@ -21,7 +22,14 @@ const output = import.meta.env.OUTPUT || 'hybrid';
|
|||
const site = import.meta.env.SITE_URL || 'https://awesome-privacy.xyz';
|
||||
|
||||
// Initialize Astro integrations
|
||||
const integrations = [svelte(), partytown(), sitemap()];
|
||||
const buildLogger = {
|
||||
name: 'build-logger',
|
||||
hooks: {
|
||||
'astro:build:done': () => printSummary(),
|
||||
},
|
||||
};
|
||||
|
||||
const integrations = [svelte(), partytown(), sitemap(), buildLogger];
|
||||
|
||||
// Set the appropriate adapter, based on the deploy target
|
||||
const adapter = {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
import FontAwesome from "@components/form/FontAwesome.svelte";
|
||||
import { error } from "@utils/logger";
|
||||
const { github } = Astro.props;
|
||||
|
||||
interface GitHubRepoData {
|
||||
|
|
@ -29,7 +30,7 @@ const fetchGitHubData = async (repo: string) => {
|
|||
const response = await fetch(`https://api.github.com/repos/${repo}`, {
|
||||
headers: headers,
|
||||
}).catch((e) => {
|
||||
console.error(`Network error: ${e.message}`);
|
||||
error('GitHub API', `Network error for ${repo}: ${e.message}`);
|
||||
// Return a placeholder response to handle this gracefully
|
||||
return null;
|
||||
});
|
||||
|
|
@ -45,7 +46,7 @@ const fetchGitHubData = async (repo: string) => {
|
|||
if (response.ok) {
|
||||
data = await response.json();
|
||||
} else {
|
||||
console.error(`HTTP error: Received status code ${response.status}`);
|
||||
error('GitHub API', `HTTP ${response.status} for ${repo}`);
|
||||
}
|
||||
|
||||
return { data, statusCode };
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { error } from './logger';
|
||||
|
||||
const doubleCheckPackageName = (packageStr: string) => {
|
||||
return packageStr.includes('id=') ? packageStr.split('id=')[1] : packageStr;
|
||||
};
|
||||
|
|
@ -7,9 +9,14 @@ export const fetchAndroidInfo = async (
|
|||
): Promise<AndroidInfo | null> => {
|
||||
const endpoint = `https://android-app-privacy.as93.net/${doubleCheckPackageName(androidPackage)}`;
|
||||
try {
|
||||
return await fetch(endpoint).then((res) => res.json());
|
||||
} catch (error) {
|
||||
console.error('Error fetching android data:', error);
|
||||
const res = await fetch(endpoint);
|
||||
if (!res.ok) {
|
||||
error('Android', `HTTP ${res.status} for ${androidPackage} (${endpoint})`);
|
||||
return null;
|
||||
}
|
||||
return await res.json();
|
||||
} catch (err) {
|
||||
error('Android', `Network error for ${androidPackage}: ${err}`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import yaml from 'js-yaml';
|
||||
import { error } from './logger';
|
||||
|
||||
import type { AwesomePrivacy } from '../types/Service';
|
||||
|
||||
|
|
@ -6,10 +7,18 @@ const awesomePrivacyData =
|
|||
'https://raw.githubusercontent.com/Lissy93/awesome-privacy/main/awesome-privacy.yml';
|
||||
|
||||
export const fetchData = async (): Promise<AwesomePrivacy> => {
|
||||
return (await fetch(awesomePrivacyData)
|
||||
.then((res) => res.text())
|
||||
.then((data) => yaml.load(data))
|
||||
.catch((err) => console.error('ah crap', err))) as AwesomePrivacy;
|
||||
try {
|
||||
const res = await fetch(awesomePrivacyData);
|
||||
if (!res.ok) {
|
||||
error('Data', `HTTP ${res.status} fetching awesome-privacy.yml (${awesomePrivacyData})`);
|
||||
return {} as AwesomePrivacy;
|
||||
}
|
||||
const text = await res.text();
|
||||
return yaml.load(text) as AwesomePrivacy;
|
||||
} catch (err) {
|
||||
error('Data', `Failed to fetch awesome-privacy.yml: ${err}`);
|
||||
return {} as AwesomePrivacy;
|
||||
}
|
||||
};
|
||||
|
||||
export const slugify = (title: string) => {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
import { error } from './logger';
|
||||
|
||||
export const fetchDiscordInfo = async (
|
||||
discordInvite: string,
|
||||
): Promise<DiscordInfo | null> => {
|
||||
const endpoint = `https://discord-invite-info.as93.net/${discordInvite}`;
|
||||
try {
|
||||
return await fetch(endpoint).then((res) => res.json());
|
||||
} catch (error) {
|
||||
console.error('Error fetching discord data:', error);
|
||||
const res = await fetch(endpoint);
|
||||
if (!res.ok) {
|
||||
error('Discord', `HTTP ${res.status} for ${discordInvite} (${endpoint})`);
|
||||
return null;
|
||||
}
|
||||
return await res.json();
|
||||
} catch (err) {
|
||||
error('Discord', `Network error for ${discordInvite}: ${err}`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
import { error } from './logger';
|
||||
|
||||
export const fetchDockerData = async (
|
||||
serviceName: string,
|
||||
): Promise<TemplateResponse | null> => {
|
||||
const endpoint = `https://docker-info.as93.workers.dev/${serviceName}`;
|
||||
try {
|
||||
return await fetch(endpoint).then((res) => res.json());
|
||||
} catch (error) {
|
||||
console.error('Error fetching docker data:', error);
|
||||
const res = await fetch(endpoint);
|
||||
if (!res.ok) {
|
||||
error('Docker', `HTTP ${res.status} for ${serviceName} (${endpoint})`);
|
||||
return null;
|
||||
}
|
||||
return await res.json();
|
||||
} catch (err) {
|
||||
error('Docker', `Network error for ${serviceName}: ${err}`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
import { error } from './logger';
|
||||
|
||||
export const fetchIosInfo = async (
|
||||
iosUrl: string,
|
||||
): Promise<IoSApiResponse | null> => {
|
||||
const endpoint = `https://ios-app-info.as93.net?appStoreUrl=${iosUrl}`;
|
||||
try {
|
||||
return await fetch(endpoint).then((res) => res.json());
|
||||
} catch (error) {
|
||||
console.error('Error fetching ios info:', error);
|
||||
const res = await fetch(endpoint);
|
||||
if (!res.ok) {
|
||||
error('iOS', `HTTP ${res.status} for ${iosUrl} (${endpoint})`);
|
||||
return null;
|
||||
}
|
||||
return await res.json();
|
||||
} catch (err) {
|
||||
error('iOS', `Network error for ${iosUrl}: ${err}`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
import { error } from './logger';
|
||||
|
||||
export const fetchTosdrPrivacy = async (
|
||||
serviceId: string,
|
||||
): Promise<PrivacyPolicyResponse | null> => {
|
||||
const endpoint = `https://privacy-policies.as93.workers.dev/${serviceId}`;
|
||||
try {
|
||||
return await fetch(endpoint).then((res) => res.json());
|
||||
} catch (error) {
|
||||
console.error('Error fetching privacy policy data:', error);
|
||||
const res = await fetch(endpoint);
|
||||
if (!res.ok) {
|
||||
error('ToS;DR', `HTTP ${res.status} for service ${serviceId} (${endpoint})`);
|
||||
return null;
|
||||
}
|
||||
return await res.json();
|
||||
} catch (err) {
|
||||
error('ToS;DR', `Network error for service ${serviceId}: ${err}`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
import { error } from './logger';
|
||||
|
||||
export const fetchRedditInfo = async (
|
||||
subreddit: string,
|
||||
): Promise<RedditData | null> => {
|
||||
const endpoint = `https://subreddit-info.as93.net/${subreddit}`;
|
||||
try {
|
||||
return await fetch(endpoint).then((res) => res.json());
|
||||
} catch (error) {
|
||||
console.error('Error fetching reddit data:', error);
|
||||
const res = await fetch(endpoint);
|
||||
if (!res.ok) {
|
||||
error('Reddit', `HTTP ${res.status} for r/${subreddit} (${endpoint})`);
|
||||
return null;
|
||||
}
|
||||
return await res.json();
|
||||
} catch (err) {
|
||||
error('Reddit', `Network error for r/${subreddit}: ${err}`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,17 +1,107 @@
|
|||
import { error } from './logger';
|
||||
|
||||
const githubHeaders = (): Record<string, string> => {
|
||||
const headers: Record<string, string> = {
|
||||
'User-Agent': 'awesome-privacy',
|
||||
'Accept': 'application/vnd.github.v3+json',
|
||||
};
|
||||
const token = import.meta.env.GITHUB_API_KEY;
|
||||
if (token) headers['Authorization'] = `token ${token}`;
|
||||
return headers;
|
||||
};
|
||||
|
||||
const fetchFromGitHub = async (github: string): Promise<GitHubStatsResponse | null> => {
|
||||
const base = `https://api.github.com/repos/${github}`;
|
||||
const headers = githubHeaders();
|
||||
|
||||
const [infoRes, langsRes, tagsRes, contribRes, commitsRes] = await Promise.all([
|
||||
fetch(base, { headers }),
|
||||
fetch(`${base}/languages`, { headers }),
|
||||
fetch(`${base}/tags`, { headers }),
|
||||
fetch(`${base}/contributors`, { headers }),
|
||||
fetch(`${base}/commits`, { headers }),
|
||||
]);
|
||||
|
||||
if (!infoRes.ok) {
|
||||
error('GitHub Stats', `GitHub API returned ${infoRes.status} for ${github}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const parseJson = (r: Response) =>
|
||||
r.ok && r.status !== 204 ? r.json() : null;
|
||||
|
||||
const [info, languages, tags, contributors, commits] = await Promise.all(
|
||||
[infoRes, langsRes, tagsRes, contribRes, commitsRes].map(parseJson),
|
||||
);
|
||||
|
||||
return {
|
||||
info: {
|
||||
ownerUsername: info.owner?.login ?? '',
|
||||
ownerAvatar: info.owner?.avatar_url ?? '',
|
||||
description: info.description ?? '',
|
||||
url: info.html_url ?? '',
|
||||
homepage: info.homepage ?? '',
|
||||
language: info.language ?? '',
|
||||
topics: info.topics ?? [],
|
||||
license: info.license?.spdx_id ?? '',
|
||||
isFork: info.fork ?? false,
|
||||
isArchived: info.archived ?? false,
|
||||
createdAt: info.created_at ?? '',
|
||||
updatedAt: info.updated_at ?? '',
|
||||
size: info.size ?? 0,
|
||||
scarCount: info.stargazers_count ?? 0,
|
||||
forksCount: info.forks_count ?? 0,
|
||||
watchersCount: info.watchers_count ?? 0,
|
||||
},
|
||||
languages: languages ?? {},
|
||||
versions: (tags ?? []).map((tag: any) => ({
|
||||
name: tag.name,
|
||||
commit: tag.commit?.sha ?? '',
|
||||
zipball: tag.zipball_url ?? '',
|
||||
tarball: tag.tarball_url ?? '',
|
||||
})),
|
||||
contributors: (contributors ?? []).map((c: any) => ({
|
||||
username: c.login ?? '',
|
||||
avatar: c.avatar_url ?? '',
|
||||
contributions: c.contributions ?? 0,
|
||||
})),
|
||||
commits: (commits ?? []).map((c: any) => ({
|
||||
sha: c.sha ?? '',
|
||||
authorName: c.commit?.author?.name ?? '',
|
||||
authorDate: c.commit?.author?.date ?? '',
|
||||
message: c.commit?.message ?? '',
|
||||
authorUsername: c.author?.login ?? '',
|
||||
authorAvatar: c.author?.avatar_url ?? '',
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
||||
const fetchFromWorker = async (github: string): Promise<GitHubStatsResponse | null> => {
|
||||
const res = await fetch(`https://repo-info.as93.workers.dev/${github}`);
|
||||
if (!res.ok) return null;
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const fetchGitHubStats = async (
|
||||
github: string,
|
||||
): Promise<GitHubStatsResponse | null> => {
|
||||
const endpoint = `https://repo-info.as93.workers.dev/${github}`;
|
||||
try {
|
||||
return await fetch(endpoint).then((res) => res.json());
|
||||
} catch (error) {
|
||||
console.error('Error fetching GitHub stats:', error);
|
||||
const result = await fetchFromGitHub(github);
|
||||
if (result) return result;
|
||||
const fallback = await fetchFromWorker(github);
|
||||
if (fallback) return fallback;
|
||||
error('GitHub Stats', `Both direct API and worker failed for ${github}`);
|
||||
return null;
|
||||
} catch (err) {
|
||||
try {
|
||||
return await fetchFromWorker(github);
|
||||
} catch {
|
||||
error('GitHub Stats', `All fetches failed for ${github}: ${err}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// fetch(`https://repo-info.as93.workers.dev/${github}`).then((res) => res.json());
|
||||
|
||||
export interface GitHubStatsResponse {
|
||||
info: {
|
||||
ownerUsername: string;
|
||||
|
|
@ -34,17 +124,6 @@ export interface GitHubStatsResponse {
|
|||
languages: {
|
||||
[key: string]: number;
|
||||
};
|
||||
updates: Array<{
|
||||
type: string;
|
||||
actor: {
|
||||
username: string;
|
||||
avatar: string;
|
||||
};
|
||||
repo: string;
|
||||
action: string;
|
||||
createdAt: string;
|
||||
number?: number;
|
||||
}>;
|
||||
versions: Array<{
|
||||
name: string;
|
||||
commit: string;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
import { error } from './logger';
|
||||
|
||||
export const fetchWebsiteInfo = async (
|
||||
url: string,
|
||||
): Promise<WebsiteData | null> => {
|
||||
const endpoint = `https://site-info-fetch.as93.workers.dev/?url=${url}`;
|
||||
try {
|
||||
return await fetch(endpoint).then((res) => res.json());
|
||||
} catch (error) {
|
||||
console.error('Error fetching website info:', error);
|
||||
const res = await fetch(endpoint);
|
||||
if (!res.ok) {
|
||||
error('Website', `HTTP ${res.status} for ${url} (${endpoint})`);
|
||||
return null;
|
||||
}
|
||||
return await res.json();
|
||||
} catch (err) {
|
||||
error('Website', `Network error for ${url}: ${err}`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
48
web/src/utils/logger.ts
Normal file
48
web/src/utils/logger.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
type Level = 'warn' | 'error';
|
||||
|
||||
interface LogEntry {
|
||||
level: Level;
|
||||
source: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
const entries: LogEntry[] = [];
|
||||
|
||||
export const warn = (source: string, message: string) => {
|
||||
console.warn(`[${source}] ${message}`);
|
||||
entries.push({ level: 'warn', source, message });
|
||||
};
|
||||
|
||||
export const error = (source: string, message: string) => {
|
||||
console.error(`[${source}] ${message}`);
|
||||
entries.push({ level: 'error', source, message });
|
||||
};
|
||||
|
||||
export const printSummary = () => {
|
||||
if (entries.length === 0) return;
|
||||
|
||||
const grouped: Record<string, { errors: number; warnings: number; messages: string[] }> = {};
|
||||
for (const entry of entries) {
|
||||
if (!grouped[entry.source]) {
|
||||
grouped[entry.source] = { errors: 0, warnings: 0, messages: [] };
|
||||
}
|
||||
const group = grouped[entry.source];
|
||||
if (entry.level === 'error') group.errors++;
|
||||
else group.warnings++;
|
||||
group.messages.push(` ${entry.level.toUpperCase()}: ${entry.message}`);
|
||||
}
|
||||
|
||||
console.log('\n───────────── Build fetch summary ──────────────');
|
||||
for (const [source, { errors, warnings, messages }] of Object.entries(grouped)) {
|
||||
const parts = [];
|
||||
if (errors) parts.push(`${errors} error${errors > 1 ? 's' : ''}`);
|
||||
if (warnings) parts.push(`${warnings} warning${warnings > 1 ? 's' : ''}`);
|
||||
console.log(`[${source}] ${parts.join(', ')}`);
|
||||
for (const msg of messages) {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
console.log('────────────────────────────────────────────────\n');
|
||||
|
||||
entries.length = 0;
|
||||
};
|
||||
Loading…
Reference in a new issue