import { defaultData, type GitHubData } from '../types'; const GITHUB_TOKEN = process.env.GITHUB_API_KEY; const REPO_OWNER = 'Adityadn64'; const REPO_NAME = 'Tampilan-MP42PPT'; const FILE_PATH = 'data.json'; const API_URL = `https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/contents/${FILE_PATH}`; // Fungsi untuk decode Base64 yang aman untuk Unicode function b64DecodeUnicode(str: string) { try { return decodeURIComponent(atob(str).split('').map(function(c) { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }).join('')); } catch (e) { console.error("Gagal mendekode Base64:", e); // Kembalikan struktur data default jika gagal return JSON.stringify({ questions: [], message: null }); } } // Fungsi untuk encode ke Base64 yang aman untuk Unicode function b64EncodeUnicode(str: string) { return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function toSolidBytes(match, p1) { return String.fromCharCode(parseInt(p1, 16)); })); } export const getData = async (): Promise<{ data: GitHubData, sha: string | null }> => { if (!GITHUB_TOKEN) { throw new Error("GITHUB_API_KEY tidak diatur."); } const response = await fetch(API_URL, { headers: { 'Authorization': `token ${GITHUB_TOKEN}`, 'Accept': 'application/vnd.github+json', 'X-GitHub-Api-Version': '2022-11-28', }, cache: 'no-cache', // Selalu ambil data terbaru }); if (response.status === 404) { // File tidak ada, ini adalah kondisi yang valid untuk repositori baru. return { data: defaultData, sha: null }; } if (!response.ok) { const errorData = await response.json().catch(() => ({ message: response.statusText })); throw new Error(`Gagal mengambil data dari GitHub: ${errorData.message}`); } const responseData = await response.json(); const decodedContent = b64DecodeUnicode(responseData.content); try { const data = JSON.parse(decodedContent); // Pastikan data memiliki struktur yang diharapkan const validatedData: GitHubData = { idx: data.idx, direction: data.direction }; console.log({data}, {validatedData}) return { data: validatedData, sha: responseData.sha }; } catch(e) { console.error("Gagal mem-parsing JSON dari GitHub:", e); throw new Error("Format data dari GitHub tidak valid."); } }; export const saveData = async ( data: GitHubData, commitMessage: string, sha: string | null ): Promise<{ sha: string }> => { if (!GITHUB_TOKEN) { throw new Error("GITHUB_API_KEY tidak diatur."); } const content = JSON.stringify(data, null, 2); const encodedContent = b64EncodeUnicode(content); console.log(content); const body: { message: string; content: string; sha?: string } = { message: commitMessage, content: encodedContent, }; if (sha) { body.sha = sha; } let isSuccess = false; let responseData; while (!isSuccess) { try { const response = await fetch(API_URL, { method: 'PUT', headers: { 'Authorization': `Bearer ${GITHUB_TOKEN}`, 'Accept': 'application/vnd.github+json', 'X-GitHub-Api-Version': '2022-11-28', }, body: JSON.stringify(body), }); if (!response.ok) { const errorData = await response.json().catch(() => ({ message: response.statusText })); throw new Error(`Gagal menyimpan data ke GitHub: ${errorData.message}`); } responseData = await response.json(); isSuccess = true; } catch (e) { if (e.message.includes("does not match")) { const newData = await getData(); body.sha = newData.sha; } else { isSuccess = true; } } } return { sha: responseData.content.sha }; };