/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ import { writeFile, mkdir, readdir, readFile } from 'fs/promises'; import { join } from 'path'; import { env } from '../../env.js'; import type { Script, ScriptCard, GitHubFile } from '../../types/script'; import { repositoryService } from './repositoryService'; export class GitHubJsonService { private branch: string | null = null; private jsonFolder: string | null = null; private localJsonDirectory: string | null = null; private scriptCache: Map = new Map(); constructor() { // Initialize lazily to avoid accessing env vars during module load } private initializeConfig() { if (this.branch === null) { this.branch = env.REPO_BRANCH; this.jsonFolder = env.JSON_FOLDER; this.localJsonDirectory = join(process.cwd(), 'scripts', 'json'); } } private getBaseUrl(repoUrl: string): string { const urlMatch = /github\.com\/([^\/]+)\/([^\/]+)/.exec(repoUrl); if (!urlMatch) { throw new Error(`Invalid GitHub repository URL: ${repoUrl}`); } const [, owner, repo] = urlMatch; return `https://api.github.com/repos/${owner}/${repo}`; } private extractRepoPath(repoUrl: string): string { const match = /github\.com\/([^\/]+)\/([^\/]+)/.exec(repoUrl); if (!match) { throw new Error('Invalid GitHub repository URL'); } return `${match[1]}/${match[2]}`; } private async fetchFromGitHub(repoUrl: string, endpoint: string): Promise { const baseUrl = this.getBaseUrl(repoUrl); const headers: HeadersInit = { 'Accept': 'application/vnd.github.v3+json', 'User-Agent': 'PVEScripts-Local/1.0', }; // Add GitHub token authentication if available if (env.GITHUB_TOKEN) { headers.Authorization = `token ${env.GITHUB_TOKEN}`; } const response = await fetch(`${baseUrl}${endpoint}`, { headers }); if (!response.ok) { if (response.status === 403) { const error = new Error(`GitHub API rate limit exceeded. Consider setting GITHUB_TOKEN for higher limits. Status: ${response.status} ${response.statusText}`); error.name = 'RateLimitError'; throw error; } throw new Error(`GitHub API error: ${response.status} ${response.statusText}`); } const data = await response.json(); return data as T; } private async downloadJsonFile(repoUrl: string, filePath: string): Promise