import { z } from 'zod'; import { APIResponseSchema, APIResponseSchemaNoData, APIClient } from '@agentuity/api'; import { MachineResponseError } from './util.ts'; // TODO: The old /cli/auth/machine/* endpoints should be aliased to redirect // to /cli/auth/org/* in the backend (app repo). Remove aliases in follow-up PR. export const MachineSchema = z .object({ id: z.string().describe('Unique identifier for the machine.'), instanceId: z.string().nullable().optional().describe('Cloud provider instance ID.'), privateIPv4: z .string() .nullable() .optional() .describe('Private IPv4 address of the machine.'), availabilityZone: z .string() .nullable() .optional() .describe('Cloud provider availability zone.'), instanceType: z .string() .nullable() .optional() .describe('Cloud provider instance type (e.g., n1-standard-2).'), instanceTags: z .array(z.string()) .nullable() .optional() .describe('Tags assigned to the cloud instance.'), deploymentCount: z .number() .optional() .describe('Number of active deployments on this machine.'), status: z .string() .describe('Current status of the machine (e.g., running, stopped, errored).'), provider: z.string().describe('Cloud provider (e.g., gcp, aws).'), region: z.string().describe('Cloud region where the machine is deployed.'), startedAt: z .string() .nullable() .optional() .describe('ISO 8601 timestamp when the machine was started.'), stoppedAt: z .string() .nullable() .optional() .describe('ISO 8601 timestamp when the machine was stopped.'), pausedAt: z .string() .nullable() .optional() .describe('ISO 8601 timestamp when the machine was paused.'), erroredAt: z .string() .nullable() .optional() .describe('ISO 8601 timestamp when the machine entered error state.'), error: z .string() .nullable() .optional() .describe('Error message if the machine is in an error state.'), orgId: z.string().nullable().optional().describe('Organization ID that owns this machine.'), orgName: z .string() .nullable() .optional() .describe('Organization name that owns this machine.'), createdAt: z.string().describe('ISO 8601 timestamp when the machine was created.'), updatedAt: z .string() .nullable() .optional() .describe('ISO 8601 timestamp when the machine was last updated.'), metadata: z .record(z.string(), z.unknown()) .nullable() .optional() .describe('Arbitrary metadata associated with the machine.'), }) .describe('Machine instance in the Agentuity infrastructure.'); export const MachineListResponseSchema = APIResponseSchema(z.array(MachineSchema)); export const MachineGetResponseSchema = APIResponseSchema(MachineSchema); export const MachineDeleteResponseSchema = APIResponseSchemaNoData(); export type Machine = z.infer; export async function machineList( client: APIClient, options?: { orgId?: string } ): Promise { const headers = options?.orgId ? { 'x-agentuity-orgid': options.orgId } : undefined; const resp = await client.get('/machine', MachineListResponseSchema, undefined, headers); if (resp.success) { return resp.data; } throw new MachineResponseError({ message: resp.message }); } export async function machineGet(client: APIClient, machineId: string): Promise { const resp = await client.get(`/machine/${machineId}`, MachineGetResponseSchema); if (resp.success) { return resp.data; } throw new MachineResponseError({ message: resp.message }); } export async function machineDelete(client: APIClient, machineId: string): Promise { const resp = await client.delete(`/machine/${machineId}`, MachineDeleteResponseSchema); if (!resp.success) { throw new MachineResponseError({ message: resp.message }); } } export const MachineDeploymentProjectSchema = z .object({ id: z.string().describe('Unique identifier for the project.'), name: z.string().describe('Human-readable project name.'), identifier: z.string().describe('URL-safe project identifier.'), domains: z.array(z.string()).describe('Custom domains assigned to this project.'), }) .describe('Project associated with a machine deployment.'); export type MachineDeploymentProject = z.infer; export const MachineDeploymentResourcesSchema = z .object({ cpuUnits: z.number().describe('CPU units allocated to the deployment.'), memoryUnits: z.number().describe('Memory units allocated to the deployment.'), diskUnits: z.number().describe('Disk units allocated to the deployment.'), }) .describe('Resource allocation for a machine deployment.'); export type MachineDeploymentResources = z.infer; export const MachineDeploymentSchema = z .object({ id: z.string().describe('Unique identifier for the deployment.'), identifier: z.string().optional().describe('URL-safe deployment identifier.'), state: z.string().optional().describe('Current state of the deployment.'), project: MachineDeploymentProjectSchema.nullable() .optional() .describe('Project associated with this deployment.'), resources: MachineDeploymentResourcesSchema.nullable() .optional() .describe('Resource allocation for this deployment.'), customDomains: z.array(z.string()).describe('Custom domains configured for this deployment.'), paused: z.boolean().describe('Whether the deployment is currently paused.'), pausedDuration: z.number().describe('Duration in seconds the deployment has been paused.'), domainSuffix: z.string().describe('Domain suffix for the deployment URL.'), }) .describe('Deployment running on a machine.'); export const MachineDeploymentsResponseSchema = APIResponseSchema(z.array(MachineDeploymentSchema)); export type MachineDeployment = z.infer; export async function machineDeployments( client: APIClient, machineId: string ): Promise { const resp = await client.get( `/machine/deployments/${machineId}`, MachineDeploymentsResponseSchema ); if (resp.success) { return resp.data; } throw new MachineResponseError({ message: resp.message }); } export const OrgAuthEnrollResponseSchema = APIResponseSchema( z.object({ orgId: z.string().describe('Organization ID that was enrolled.'), }) ); export async function orgAuthEnroll( client: APIClient, orgId: string, publicKey: string ): Promise<{ orgId: string }> { const resp = await client.post( '/cli/auth/org/enroll', { orgId, publicKey }, OrgAuthEnrollResponseSchema ); if (resp.success) { return resp.data; } throw new MachineResponseError({ message: resp.message }); } export const OrgAuthStatusResponseSchema = APIResponseSchema( z.object({ publicKey: z .string() .nullable() .describe('Public key for the organization, or null if not enrolled.'), }) ); export async function orgAuthStatus( client: APIClient, orgId: string ): Promise<{ publicKey: string | null }> { const resp = await client.get(`/cli/auth/org/status/${orgId}`, OrgAuthStatusResponseSchema); if (resp.success) { return resp.data; } throw new MachineResponseError({ message: resp.message }); } export const OrgAuthUnenrollResponseSchema = APIResponseSchemaNoData(); export async function orgAuthUnenroll(client: APIClient, orgId: string): Promise { const resp = await client.delete( `/cli/auth/org/unenroll/${orgId}`, OrgAuthUnenrollResponseSchema ); if (!resp.success) { throw new MachineResponseError({ message: resp.message }); } }