Files
PromptArch/lib/artifact-utils.ts

109 lines
3.9 KiB
TypeScript

import JSZip from "jszip";
import { saveAs } from "file-saver";
export async function downloadArtifactAsZip(data: string, type: string, language: string = "html") {
const zip = new JSZip();
const extension = language === "html" || type === "web" || type === "app" ? "html" : (language === "typescript" || language === "tsx" ? "tsx" : "txt");
const filename = `artifact-${Date.now()}.${extension}`;
// Check if data contains common multi-file structures (simple heuristic)
// If it looks like a full project (multiple files defined in one block), we could parse it,
// but for now we'll just save the main artifact.
zip.file(filename, data);
// Add a basic README
zip.file("README.md", `# AI Generated Artifact\n\nType: ${type}\nGenerated: ${new Date().toLocaleString()}`);
const content = await zip.generateAsync({ type: "blob" });
saveAs(content, `promptarch-artifact-${Date.now()}.zip`);
}
export async function pushToGithub(
token: string,
repoName: string,
files: { path: string; content: string }[],
description: string = "Generated by PromptArch"
) {
const headers = {
'Authorization': `token ${token}`,
'Accept': 'application/vnd.github.v3+json',
'Content-Type': 'application/json',
};
// 1. Check if repo exists, if not create it
let repoData;
const userResponse = await fetch('https://api.github.com/user', { headers });
if (!userResponse.ok) throw new Error("Failed to authenticate with GitHub");
const userData = await userResponse.json();
const username = userData.login;
const repoCheckResponse = await fetch(`https://api.github.com/repos/${username}/${repoName}`, { headers });
if (repoCheckResponse.status === 404) {
// Create repo
const createResponse = await fetch('https://api.github.com/user/repos', {
method: 'POST',
headers,
body: JSON.stringify({
name: repoName,
description,
auto_init: true
})
});
if (!createResponse.ok) throw new Error("Failed to create repository");
repoData = await createResponse.json();
// Wait a bit for repo to be ready
await new Promise(resolve => setTimeout(resolve, 2000));
} else {
repoData = await repoCheckResponse.json();
}
// 2. Get latest commit SHA of default branch
const branchResponse = await fetch(`https://api.github.com/repos/${username}/${repoName}/branches/${repoData.default_branch}`, { headers });
const branchData = await branchResponse.json();
const latestCommitSha = branchData.commit.sha;
// 3. Create a new tree
const treeItems = files.map(file => ({
path: file.path,
mode: '100644',
type: 'blob',
content: file.content
}));
const treeResponse = await fetch(`https://api.github.com/repos/${username}/${repoName}/git/trees`, {
method: 'POST',
headers,
body: JSON.stringify({
base_tree: latestCommitSha,
tree: treeItems
})
});
const treeData = await treeResponse.json();
// 4. Create a new commit
const commitResponse = await fetch(`https://api.github.com/repos/${username}/${repoName}/git/commits`, {
method: 'POST',
headers,
body: JSON.stringify({
message: `Update from PromptArch: ${new Date().toISOString()}`,
tree: treeData.sha,
parents: [latestCommitSha]
})
});
const commitData = await commitResponse.json();
// 5. Update the reference
const refResponse = await fetch(`https://api.github.com/repos/${username}/${repoName}/git/refs/heads/${repoData.default_branch}`, {
method: 'PATCH',
headers,
body: JSON.stringify({
sha: commitData.sha
})
});
if (!refResponse.ok) throw new Error("Failed to update branch reference");
return { url: repoData.html_url };
}