UNPKG

@pompeii-labs/cli

Version:

Magma CLI

326 lines (325 loc) 9.02 kB
import chalk from "chalk"; import { getAuthSession, storeAuthSession } from "./auth.js"; const ENDPOINT = "https://api.magmadeploy.com/v1"; const ENDPOINT_NGROK = "https://magma.ngrok.app/v1"; const FRONTEND = "https://magmadeploy.com"; const endpoint = (path, frontend = false) => { let endpoint2; if (frontend) { endpoint2 = FRONTEND; } else if (process.argv.includes("--ngrok")) { endpoint2 = ENDPOINT_NGROK; } else if (process.argv.includes("--endpoint")) { endpoint2 = process.argv[process.argv.indexOf("--endpoint") + 1]; } else { endpoint2 = ENDPOINT; } return `${endpoint2}${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 saveAgent(options) { const 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 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 getOrgs() { const response = await authenticatedFetch(endpoint("/orgs")); const data = await response.json(); return data; } async function getAgent(name, orgId, version) { const response = await authenticatedFetch(endpoint(`/agents?name=${name}`), { headers: { "x-org-id": orgId.toString() } }); if (!response.ok) { throw await response.json(); } const data = await response.json(); if (!data) { throw new Error("Agent not found"); } let agent = data; if (version) { agent = await getVersionedAgent(agent.id, orgId, version); } return agent; } async function getVersionedAgent(id, orgId, version) { const url = new URL(endpoint(`/agents/${id}`)); url.searchParams.set("source", "true"); if (version) { url.searchParams.set("version", version); } const response = await authenticatedFetch(url, { headers: { "x-org-id": orgId.toString() } }); 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 unsetEnv(agentId, key) { const response = await authenticatedFetch(endpoint(`/agents/${agentId}/env/${key}`), { method: "DELETE" }); 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 unsetTemplateEnv(templateId, key) { const response = await authenticatedFetch(endpoint(`/templates/${templateId}/env/${key}`), { method: "DELETE" }); 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, deployAgent, deployTemplate, endpoint, exchangeCode, getAgent, getEnv, getOrgs, getTemplate, getTemplateByName, getTemplateEnv, listTemplates, refreshTokens, saveAgent, setEnv, setTemplateEnv, stopAgent, unsetEnv, unsetTemplateEnv };