mirror of
https://github.com/domfelipe/mika-agent-assist.git
synced 2026-08-07 06:56:44 +00:00
Changes
Co-authored-by: domfelipe <53182096+domfelipe@users.noreply.github.com>
This commit is contained in:
parent
7de4fe7054
commit
2b45297603
4 changed files with 524 additions and 0 deletions
163
supabase/functions/_shared/railway.ts
Normal file
163
supabase/functions/_shared/railway.ts
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
// Helper para chamar a Railway GraphQL API (Public API).
|
||||
// Docs: https://docs.railway.com/reference/public-api
|
||||
const RAILWAY_GRAPHQL = "https://backboard.railway.com/graphql/v2";
|
||||
|
||||
export interface RailwayError {
|
||||
message: string;
|
||||
path?: string[];
|
||||
extensions?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export async function railwayQuery<T>(
|
||||
query: string,
|
||||
variables: Record<string, unknown>,
|
||||
token: string,
|
||||
): Promise<{ data?: T; errors?: RailwayError[] }> {
|
||||
const res = await fetch(RAILWAY_GRAPHQL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({ query, variables }),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(`Railway HTTP ${res.status}: ${text}`);
|
||||
}
|
||||
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export async function createRailwayService(opts: {
|
||||
token: string;
|
||||
projectId: string;
|
||||
name: string;
|
||||
}): Promise<string> {
|
||||
const mutation = `
|
||||
mutation ServiceCreate($input: ServiceCreateInput!) {
|
||||
serviceCreate(input: $input) { id name }
|
||||
}
|
||||
`;
|
||||
const res = await railwayQuery<{ serviceCreate: { id: string; name: string } }>(
|
||||
mutation,
|
||||
{ input: { projectId: opts.projectId, name: opts.name } },
|
||||
opts.token,
|
||||
);
|
||||
if (res.errors?.length) {
|
||||
throw new Error(`serviceCreate failed: ${JSON.stringify(res.errors)}`);
|
||||
}
|
||||
if (!res.data?.serviceCreate?.id) {
|
||||
throw new Error("serviceCreate returned no id");
|
||||
}
|
||||
return res.data.serviceCreate.id;
|
||||
}
|
||||
|
||||
export async function configureRailwayService(opts: {
|
||||
token: string;
|
||||
serviceId: string;
|
||||
environmentId: string;
|
||||
image: string;
|
||||
variables: Record<string, string>;
|
||||
}): Promise<void> {
|
||||
// O Railway expõe variáveis via variableUpsert (uma por vez) e fonte/imagem via serviceInstanceUpdate.
|
||||
// Setamos a imagem primeiro.
|
||||
const updateSource = `
|
||||
mutation ServiceInstanceUpdate($serviceId: String!, $environmentId: String!, $input: ServiceInstanceUpdateInput!) {
|
||||
serviceInstanceUpdate(serviceId: $serviceId, environmentId: $environmentId, input: $input)
|
||||
}
|
||||
`;
|
||||
const sourceRes = await railwayQuery(
|
||||
updateSource,
|
||||
{
|
||||
serviceId: opts.serviceId,
|
||||
environmentId: opts.environmentId,
|
||||
input: { source: { image: opts.image } },
|
||||
},
|
||||
opts.token,
|
||||
);
|
||||
if (sourceRes.errors?.length) {
|
||||
throw new Error(`serviceInstanceUpdate (source) failed: ${JSON.stringify(sourceRes.errors)}`);
|
||||
}
|
||||
|
||||
// Agora as variáveis. Railway recomenda variableUpsert por chave.
|
||||
const variableUpsert = `
|
||||
mutation VariableUpsert($input: VariableUpsertInput!) {
|
||||
variableUpsert(input: $input)
|
||||
}
|
||||
`;
|
||||
for (const [name, value] of Object.entries(opts.variables)) {
|
||||
const r = await railwayQuery(
|
||||
variableUpsert,
|
||||
{
|
||||
input: {
|
||||
projectId: undefined, // será inferido pelo serviceId+environmentId
|
||||
environmentId: opts.environmentId,
|
||||
serviceId: opts.serviceId,
|
||||
name,
|
||||
value,
|
||||
},
|
||||
},
|
||||
opts.token,
|
||||
);
|
||||
if (r.errors?.length) {
|
||||
throw new Error(`variableUpsert(${name}) failed: ${JSON.stringify(r.errors)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function deployRailwayService(opts: {
|
||||
token: string;
|
||||
serviceId: string;
|
||||
environmentId: string;
|
||||
}): Promise<void> {
|
||||
const mutation = `
|
||||
mutation ServiceInstanceRedeploy($serviceId: String!, $environmentId: String!) {
|
||||
serviceInstanceRedeploy(serviceId: $serviceId, environmentId: $environmentId)
|
||||
}
|
||||
`;
|
||||
const res = await railwayQuery(
|
||||
mutation,
|
||||
{ serviceId: opts.serviceId, environmentId: opts.environmentId },
|
||||
opts.token,
|
||||
);
|
||||
if (res.errors?.length) {
|
||||
throw new Error(`serviceInstanceRedeploy failed: ${JSON.stringify(res.errors)}`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function setRailwayReplicas(opts: {
|
||||
token: string;
|
||||
serviceId: string;
|
||||
environmentId: string;
|
||||
replicas: number;
|
||||
}): Promise<void> {
|
||||
const mutation = `
|
||||
mutation ServiceInstanceUpdate($serviceId: String!, $environmentId: String!, $input: ServiceInstanceUpdateInput!) {
|
||||
serviceInstanceUpdate(serviceId: $serviceId, environmentId: $environmentId, input: $input)
|
||||
}
|
||||
`;
|
||||
const res = await railwayQuery(
|
||||
mutation,
|
||||
{
|
||||
serviceId: opts.serviceId,
|
||||
environmentId: opts.environmentId,
|
||||
input: { numReplicas: opts.replicas },
|
||||
},
|
||||
opts.token,
|
||||
);
|
||||
if (res.errors?.length) {
|
||||
throw new Error(`setRailwayReplicas failed: ${JSON.stringify(res.errors)}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Apaga o webhook do Telegram para que o Hermes assuma via polling. */
|
||||
export async function deleteTelegramWebhook(botToken: string): Promise<void> {
|
||||
const url = `https://api.telegram.org/bot${botToken}/deleteWebhook?drop_pending_updates=false`;
|
||||
const res = await fetch(url, { method: "POST" });
|
||||
if (!res.ok) {
|
||||
const text = await res.text();
|
||||
throw new Error(`deleteWebhook failed: ${res.status} ${text}`);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue