109 lines
3.9 KiB
TypeScript
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 };
|
|
}
|