UNPKG

@pompeii-labs/cli

Version:

Magma CLI

317 lines (316 loc) 8.91 kB
import chalk from "chalk"; import { getAuthSession, storeAuthSession } from "./auth.js"; const ENDPOINT = "https://api.magmadeploy.com/v1"; const FRONTEND = "https://magmadeploy.com"; const endpoint = (path, frontend = false) => `${frontend ? FRONTEND : ENDPOINT}${path}`; async function authenticatedFetch(input, init) { const session = await getAuthSession(); const response = await fetch(input, { ...init, headers: { Authorization: `Bearer ${session.access_token}`, ...init?.headers } }); if (!response.ok) { if (response.status === 403) { const newTokens = await refreshTokens(session.refresh_token); if (!newTokens) throw new Error("No tokens received from server"); await storeAuthSession(newTokens); return authenticatedFetch(input, init); } else if (response.status === 413) { throw new Error("Payload too large"); } let error = await response.text(); try { error = JSON.parse(error).message; } catch (e) { } throw new Error(error); } return response; } async function getTemplate(id) { const response = await authenticatedFetch(endpoint(`/templates/${id}`)); if (!response.ok) { throw await response.json(); } const data = await response.json(); return data; } async function getTemplateByName(name) { const response = await authenticatedFetch(endpoint(`/templates?name=${name}`)); if (!response.ok) { throw await response.json(); } const data = await response.json(); return data; } async function listTemplates() { const response = await fetch(endpoint("/templates")); if (!response.ok) { throw await response.json(); } const data = await response.json(); return data; } async function createOrUpdateAgent(options) { let response; if (options.id) { response = await authenticatedFetch(endpoint(`/agents/${options.id}`), { method: "PUT", headers: { "Content-Type": "application/json", "x-org-id": options.org_id.toString() }, body: JSON.stringify(options) }); } else { response = await authenticatedFetch(endpoint("/agents"), { method: "POST", headers: { "Content-Type": "application/json", "x-org-id": options.org_id.toString() }, body: JSON.stringify(options) }); } if (!response.ok) { throw await response.json(); } const data = await response.json(); return data; } async function deployAgent(agent) { const response = await authenticatedFetch(endpoint(`/agents/${agent.id}/deploy`), { method: "POST", headers: { "Content-Type": "application/json", "x-org-id": agent.orgId.toString() } }); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ""; let isReading = true; try { while (isReading) { const { value, done } = await reader.read(); if (done) { isReading = false; break; } buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n\n"); buffer = lines.pop() || ""; for (const line of lines) { try { const cleaned = line.replace("data: ", "").replace("\n", ""); const parsed = JSON.parse(cleaned); switch (parsed.type) { case "success": reader.cancel(); isReading = false; break; case "message": console.log(chalk.dim(parsed.data)); break; case "error": reader.cancel(); throw new Error(parsed.data); default: break; } } catch (error) { if (error instanceof Error) { reader.cancel(); throw error; } } } } } catch (error) { reader.cancel(); throw error; } finally { reader.cancel(); } } async function stopAgent(id) { const response = await authenticatedFetch(endpoint(`/agents/${id}/deploy`), { method: "DELETE" }); if (!response.ok) { throw await response.json(); } } async function startAgent(id) { const response = await authenticatedFetch(endpoint(`/agents/${id}/up`), { method: "POST" }); if (!response.ok) { throw await response.json(); } } async function exchangeCode(code) { const response = await fetch(endpoint("/auth/exchange"), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ code }) }); if (!response.ok) { throw await response.json(); } const data = await response.json(); return data; } async function refreshTokens(refresh_token) { const response = await fetch(endpoint("/auth/refresh"), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ refresh_token }) }); if (!response.ok) { throw await response.json(); } const data = await response.json(); return data; } async function exchangeGitHubCode(code) { const response = await authenticatedFetch(endpoint("/integrations/github"), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ code }) }); if (!response.ok) { throw await response.json(); } } async function listGithubRepos() { const response = await authenticatedFetch(endpoint("/integrations/github/repos")); const data = await response.json(); return data; } async function linkGithubRepo(repo, agentId) { const response = await authenticatedFetch(endpoint(`/integrations/github/link`), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ repo, agentId }) }); if (!response.ok) { throw await response.json(); } } async function getOrgs() { const response = await authenticatedFetch(endpoint("/orgs")); const data = await response.json(); return data; } async function getAgent(name, orgId) { const response = await authenticatedFetch(endpoint(`/agents?name=${name}&orgId=${orgId}`)); if (!response.ok) { throw await response.json(); } const data = await response.json(); return data; } async function getEnv(agentId, key) { const response = await authenticatedFetch(endpoint(`/agents/${agentId}/env?key=${key}`)); if (!response.ok) { throw await response.json(); } const data = await response.text(); return data; } async function setEnv(agentId, pairs) { const response = await authenticatedFetch(endpoint(`/agents/${agentId}/env`), { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(pairs) }); if (!response.ok) { throw await response.json(); } } async function getTemplateEnv(templateId, key) { const response = await authenticatedFetch(endpoint(`/templates/${templateId}/env?key=${key}`)); if (!response.ok) { throw await response.json(); } const data = await response.text(); return data; } async function setTemplateEnv(templateId, pairs) { const response = await authenticatedFetch(endpoint(`/templates/${templateId}/env`), { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(pairs) }); if (!response.ok) { throw await response.json(); } } async function deployTemplate(body) { const response = await authenticatedFetch(endpoint("/templates"), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }); const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ""; let isReading = true; try { while (isReading) { const { value, done } = await reader.read(); if (done) { isReading = false; break; } buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n\n"); buffer = lines.pop() || ""; for (const line of lines) { try { const cleaned = line.replace("data: ", "").replace("\n", ""); const parsed = JSON.parse(cleaned); switch (parsed.type) { case "message": console.log(chalk.dim(parsed.data)); break; case "error": reader.cancel(); throw new Error(parsed.data); default: break; } } catch (error) { if (error instanceof Error) { reader.cancel(); throw error; } } } } } catch (error) { reader.cancel(); throw error; } finally { reader.cancel(); } } export { FRONTEND, authenticatedFetch, createOrUpdateAgent, deployAgent, deployTemplate, endpoint, exchangeCode, exchangeGitHubCode, getAgent, getEnv, getOrgs, getTemplate, getTemplateByName, getTemplateEnv, linkGithubRepo, listGithubRepos, listTemplates, refreshTokens, setEnv, setTemplateEnv, startAgent, stopAgent };