import { apiClient, apiEndpointKeys } from "@/api/api"; // ─── Types ──────────────────────────────────────────────────────────────────── export type Ec2Tag = { key: string; value: string; }; export type Ec2SecurityGroupRef = { id?: string; name?: string; }; export type Ec2NetworkInterface = { networkInterfaceId: string; deviceIndex?: number; status?: string; privateIpAddress?: string; publicIpAddress?: string; privateDnsName?: string; subnetId?: string; vpcId?: string; securityGroups: Ec2SecurityGroupRef[]; }; export type Ec2IpPermission = { protocol: string; fromPort: number | null; toPort: number | null; ipRanges: string[]; ipv6Ranges: string[]; }; export type Ec2SecurityGroup = { groupId: string; groupName: string; description: string; vpcId?: string; inboundRules: Ec2IpPermission[]; outboundRules: Ec2IpPermission[]; tags: Ec2Tag[]; }; export type Ec2Image = { imageId: string; name: string; description?: string; state?: string; architecture?: string; platform?: string; virtualizationType?: string; rootDeviceType?: string; createdAt?: string; ownerId?: string; public?: boolean; tags: Ec2Tag[]; }; export type Ec2Instance = { instanceId: string; name: string; state?: string; instanceType?: string; availabilityZone?: string; publicIpAddress?: string; privateIpAddress?: string; vpcId?: string; subnetId?: string; imageId?: string; keyName?: string; launchTime?: string; architecture?: string; platform?: string; securityGroups: Ec2SecurityGroupRef[]; networkInterfaces: Ec2NetworkInterface[]; tags: Ec2Tag[]; connection?: Ec2InstanceConnection; }; export type Ec2InstanceConnection = { sshHost?: string; sshPort?: number; containerId?: string; containerStatus: 'running' | 'stopped' | 'unavailable'; }; export type Ec2KeyPair = { keyPairId: string; keyName: string; keyFingerprint?: string; tags: Ec2Tag[]; }; export type Ec2KeyPairMaterial = { keyPairId: string; keyName: string; keyMaterial: string; }; export type Ec2KeyPairType = "rsa" | "ed25519"; export type Ec2Vpc = { vpcId: string; cidrBlock: string; state?: string; isDefault: boolean; tags: Ec2Tag[]; }; export type Ec2Subnet = { subnetId: string; vpcId: string; cidrBlock: string; availabilityZone: string; availableIpAddressCount?: number; mapPublicIpOnLaunch: boolean; state?: string; tags: Ec2Tag[]; }; export type Ec2AvailabilityZone = { zoneName: string; zoneId: string; state: string; }; export type Ec2InstanceType = { instanceType: string; vcpu: number; memoryMiB: number; }; export type Ec2VpcAttributes = { enableDnsHostnames: boolean; enableDnsSupport: boolean; }; export type Ec2ConsoleOutput = { instanceId: string; output: string; timestamp?: string; }; export type RunEc2InstanceInput = { name: string; imageId: string; instanceType: string; keyName?: string; subnetId?: string; securityGroupIds?: string[]; userData?: string; iamInstanceProfileName?: string; associatePublicIpAddress?: boolean; rootVolumeSize?: number; rootVolumeType?: string; }; export type CreateAmiInput = { name: string; description?: string; noReboot?: boolean; }; export type IpPermissionInput = { protocol: string; fromPort: number; toPort: number; cidr: string; }; export type SubnetGroup = { name: string; count: number; isPublic: boolean; az?: string; prefix?: number; }; export type VpcWizardInput = { name: string; cidrBlock: string; subnetGroups: SubnetGroup[]; natGateway: boolean; availabilityZone?: string; }; export type VpcWizardResult = { vpcId: string; igwId: string; publicSubnetIds: string[]; privateSubnetIds: string[]; subnetGroups: Array<{ name: string; isPublic: boolean; subnetIds: string[] }>; natGatewayId?: string; eipAllocationId?: string; publicRouteTableId: string; privateRouteTableId?: string; }; export type Ec2InternetGateway = { internetGatewayId: string; attachments: Array<{ vpcId: string; state: string }>; tags: Ec2Tag[]; }; export type Ec2NatGateway = { natGatewayId: string; subnetId: string; vpcId: string; state?: string; publicIp?: string; privateIp?: string; eipAllocationId?: string; tags: Ec2Tag[]; }; export type Ec2Route = { destinationCidrBlock?: string; gatewayId?: string; natGatewayId?: string; vpcPeeringConnectionId?: string; state?: string; origin?: string; }; export type Ec2RouteTableAssociation = { associationId: string; subnetId?: string; isMain: boolean; }; export type Ec2RouteTable = { routeTableId: string; vpcId: string; routes: Ec2Route[]; associations: Ec2RouteTableAssociation[]; tags: Ec2Tag[]; }; export type Ec2ElasticIp = { allocationId: string; publicIp: string; domain?: string; associationId?: string; instanceId?: string; networkInterfaceId?: string; tags: Ec2Tag[]; }; export type CreateNatGatewayInput = { name?: string; subnetId: string; allocationId?: string; }; export type CreateRouteInput = { destinationCidrBlock: string; gatewayId?: string; natGatewayId?: string; vpcPeeringConnectionId?: string; }; export type ResourceSummary = { id: string; name: string; status?: string; metadata?: Record; }; // ─── Functions ──────────────────────────────────────────────────────────────── export async function listEc2Instances(signal?: AbortSignal): Promise { const res = await apiClient.call(apiEndpointKeys.aws.ec2.instances.list, { signal }); return res.data; } export async function describeEc2Instance(instanceId: string, signal?: AbortSignal): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.instances.describe, { signal }, { instanceId }, ); return res.data; } export async function runEc2Instance(input: RunEc2InstanceInput): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.instances.create, { body: JSON.stringify(input), headers: { "content-type": "application/json" } }, ); return res.data; } export async function startEc2Instance(instanceId: string): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.instances.start, { body: "{}", headers: { "content-type": "application/json" } }, { instanceId }, ); } export async function stopEc2Instance(instanceId: string): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.instances.stop, { body: "{}", headers: { "content-type": "application/json" } }, { instanceId }, ); } export async function rebootEc2Instance(instanceId: string): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.instances.reboot, { body: "{}", headers: { "content-type": "application/json" } }, { instanceId }, ); } export async function terminateEc2Instance(instanceId: string): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.instances.terminate, {}, { instanceId }, ); } export async function updateEc2InstanceTags( instanceId: string, toAdd: Ec2Tag[], toRemove: string[], ): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.instances.tags, { body: JSON.stringify({ toAdd, toRemove }), headers: { "content-type": "application/json" } }, { instanceId }, ); } export async function updateEc2InstanceSecurityGroups(instanceId: string, groupIds: string[]): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.instances.securityGroups, { body: JSON.stringify({ groupIds }), headers: { "content-type": "application/json" } }, { instanceId }, ); } export async function createEc2Ami(instanceId: string, input: CreateAmiInput): Promise<{ imageId: string }> { const res = await apiClient.call<{ imageId: string }>( apiEndpointKeys.aws.ec2.instances.createImage, { body: JSON.stringify(input), headers: { "content-type": "application/json" } }, { instanceId }, ); return res.data; } export async function getEc2ConsoleOutput(instanceId: string, signal?: AbortSignal): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.instances.console, { signal }, { instanceId }, ); return res.data; } export async function listEc2Amis(signal?: AbortSignal): Promise { const res = await apiClient.call(apiEndpointKeys.aws.ec2.amis.list, { signal }); return res.data; } export async function deregisterEc2Ami(imageId: string): Promise { await apiClient.call(apiEndpointKeys.aws.ec2.amis.deregister, {}, { imageId }); } export async function listEc2KeyPairs(signal?: AbortSignal): Promise { const res = await apiClient.call(apiEndpointKeys.aws.ec2.keyPairs.list, { signal }); return res.data; } export async function createEc2KeyPair(name: string, keyType: Ec2KeyPairType = "rsa"): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.keyPairs.create, { body: { name, keyType } }, ); return res.data; } export async function deleteEc2KeyPair(name: string): Promise { await apiClient.call(apiEndpointKeys.aws.ec2.keyPairs.delete, {}, { name }); } export async function listEc2SecurityGroups(vpcId?: string, signal?: AbortSignal): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.securityGroups.list, { params: { vpcId }, signal }, ); return res.data; } export async function createEc2SecurityGroup( name: string, description: string, vpcId?: string, ): Promise<{ groupId: string }> { const res = await apiClient.call< { groupId: string }, { name: string; description: string; vpcId?: string } >( apiEndpointKeys.aws.ec2.securityGroups.create, { body: { name, description, vpcId } }, ); return res.data; } export async function deleteEc2SecurityGroup(groupId: string): Promise { await apiClient.call(apiEndpointKeys.aws.ec2.securityGroups.delete, {}, { groupId }); } export async function authorizeEc2SecurityGroupIngress( groupId: string, permission: IpPermissionInput, ): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.securityGroups.authorize, { body: permission }, { groupId }, ); } export async function revokeEc2SecurityGroupIngress( groupId: string, permission: IpPermissionInput, ): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.securityGroups.revoke, { body: permission }, { groupId }, ); } export async function authorizeEc2SecurityGroupEgress( groupId: string, permission: IpPermissionInput, ): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.securityGroups.authorizeEgress, { body: permission }, { groupId }, ); } export async function revokeEc2SecurityGroupEgress( groupId: string, permission: IpPermissionInput, ): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.securityGroups.revokeEgress, { body: permission }, { groupId }, ); } export async function listEc2AvailabilityZones(signal?: AbortSignal): Promise { const res = await apiClient.call(apiEndpointKeys.aws.ec2.availabilityZones, { signal }); return res.data; } export async function listEc2InstanceTypes(signal?: AbortSignal): Promise { const res = await apiClient.call(apiEndpointKeys.aws.ec2.instanceTypes, { signal }); return res.data; } export async function modifyEc2SubnetAttribute(subnetId: string, mapPublicIpOnLaunch: boolean): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.subnets.modifyAttribute, { body: JSON.stringify({ mapPublicIpOnLaunch }), headers: { "content-type": "application/json" } }, { subnetId }, ); } export async function getEc2VpcAttributes(vpcId: string, signal?: AbortSignal): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.vpcs.getAttributes, { signal }, { vpcId }, ); return res.data; } export async function modifyEc2VpcAttribute( vpcId: string, attribute: "enableDnsHostnames" | "enableDnsSupport", value: boolean, ): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.vpcs.modifyAttribute, { body: JSON.stringify({ attribute, value }), headers: { "content-type": "application/json" } }, { vpcId }, ); } export async function associateEc2ElasticIp( allocationId: string, instanceId: string, ): Promise<{ associationId: string }> { const res = await apiClient.call<{ associationId: string }>( apiEndpointKeys.aws.ec2.elasticIps.associate, { body: JSON.stringify({ instanceId }), headers: { "content-type": "application/json" } }, { allocationId }, ); return res.data; } export async function disassociateEc2ElasticIp(allocationId: string, associationId: string): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.elasticIps.disassociate, { body: JSON.stringify({ associationId }), headers: { "content-type": "application/json" } }, { allocationId }, ); } export async function listEc2Vpcs(signal?: AbortSignal): Promise { const res = await apiClient.call(apiEndpointKeys.aws.ec2.vpcs.list, { signal }); return res.data; } export async function createEc2Vpc(cidrBlock: string): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.vpcs.create, { body: JSON.stringify({ cidrBlock }), headers: { "content-type": "application/json" } }, ); return res.data; } export async function deleteEc2Vpc(vpcId: string): Promise { await apiClient.call(apiEndpointKeys.aws.ec2.vpcs.delete, {}, { vpcId }); } export async function listEc2Subnets(vpcId?: string, signal?: AbortSignal): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.subnets.list, { params: { vpcId }, signal }, ); return res.data; } export async function createEc2Subnet( vpcId: string, cidrBlock: string, availabilityZone?: string, ): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.subnets.create, { body: JSON.stringify({ vpcId, cidrBlock, availabilityZone }), headers: { "content-type": "application/json" } }, ); return res.data; } export async function deleteEc2Subnet(subnetId: string): Promise { await apiClient.call(apiEndpointKeys.aws.ec2.subnets.delete, {}, { subnetId }); } export async function listEc2InternetGateways(signal?: AbortSignal): Promise { const res = await apiClient.call(apiEndpointKeys.aws.ec2.internetGateways.list, { signal }); return res.data; } export async function createEc2InternetGateway(name?: string): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.internetGateways.create, { body: JSON.stringify({ name }), headers: { "content-type": "application/json" } }, ); return res.data; } export async function attachEc2InternetGateway(igwId: string, vpcId: string): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.internetGateways.attach, { body: JSON.stringify({ vpcId }), headers: { "content-type": "application/json" } }, { igwId }, ); } export async function detachEc2InternetGateway(igwId: string, vpcId: string): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.internetGateways.detach, { body: JSON.stringify({ vpcId }), headers: { "content-type": "application/json" } }, { igwId }, ); } export async function deleteEc2InternetGateway(igwId: string): Promise { await apiClient.call(apiEndpointKeys.aws.ec2.internetGateways.delete, {}, { igwId }); } export async function listEc2NatGateways(vpcId?: string, signal?: AbortSignal): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.natGateways.list, { params: { vpcId }, signal }, ); return res.data; } export async function createEc2NatGateway(input: CreateNatGatewayInput): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.natGateways.create, { body: JSON.stringify(input), headers: { "content-type": "application/json" } }, ); return res.data; } export async function deleteEc2NatGateway(natId: string): Promise { await apiClient.call(apiEndpointKeys.aws.ec2.natGateways.delete, {}, { natId }); } export async function listEc2RouteTables(vpcId?: string, signal?: AbortSignal): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.routeTables.list, { params: { vpcId }, signal }, ); return res.data; } export async function createEc2RouteTable(vpcId: string, name?: string): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.routeTables.create, { body: JSON.stringify({ vpcId, name }), headers: { "content-type": "application/json" } }, ); return res.data; } export async function deleteEc2RouteTable(rtbId: string): Promise { await apiClient.call(apiEndpointKeys.aws.ec2.routeTables.delete, {}, { rtbId }); } export async function createEc2Route(rtbId: string, input: CreateRouteInput): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.routeTables.createRoute, { body: JSON.stringify(input), headers: { "content-type": "application/json" } }, { rtbId }, ); } export async function deleteEc2Route(rtbId: string, cidr: string): Promise { await apiClient.call( apiEndpointKeys.aws.ec2.routeTables.deleteRoute, { params: { cidr } }, { rtbId }, ); } export async function associateEc2RouteTable(rtbId: string, subnetId: string): Promise { const res = await apiClient.call<{ associationId: string }>( apiEndpointKeys.aws.ec2.routeTables.associate, { body: JSON.stringify({ subnetId }), headers: { "content-type": "application/json" } }, { rtbId }, ); return res.data.associationId; } export async function disassociateEc2RouteTable(associationId: string): Promise { await apiClient.call(apiEndpointKeys.aws.ec2.routeTables.disassociate, {}, { associationId }); } export async function listEc2ElasticIps(signal?: AbortSignal): Promise { const res = await apiClient.call(apiEndpointKeys.aws.ec2.elasticIps.list, { signal }); return res.data; } export async function allocateEc2ElasticIp(name?: string): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.elasticIps.create, { body: JSON.stringify({ name }), headers: { "content-type": "application/json" } }, ); return res.data; } export async function releaseEc2ElasticIp(allocationId: string): Promise { await apiClient.call(apiEndpointKeys.aws.ec2.elasticIps.release, {}, { allocationId }); } export async function createVpcWizard(input: VpcWizardInput): Promise { const res = await apiClient.call( apiEndpointKeys.aws.ec2.vpcWizard, { body: JSON.stringify(input), headers: { "content-type": "application/json" } }, ); return res.data; } export async function listEc2Resources(signal?: AbortSignal): Promise { const instances = await listEc2Instances(signal); return instances.map((instance) => ({ id: instance.instanceId, name: instance.name, status: instance.state, metadata: { instanceType: instance.instanceType, az: instance.availabilityZone, publicIp: instance.publicIpAddress, privateIp: instance.privateIpAddress, }, })); } // ─── Client ─────────────────────────────────────────────────────────────────── export const ec2Client = { listInstances: listEc2Instances, describeInstance: describeEc2Instance, runInstance: runEc2Instance, startInstance: startEc2Instance, stopInstance: stopEc2Instance, rebootInstance: rebootEc2Instance, terminateInstance: terminateEc2Instance, updateInstanceTags: updateEc2InstanceTags, createAmi: createEc2Ami, getConsoleOutput: getEc2ConsoleOutput, listAmis: listEc2Amis, deregisterAmi: deregisterEc2Ami, listResources: listEc2Resources, listKeyPairs: listEc2KeyPairs, createKeyPair: createEc2KeyPair, deleteKeyPair: deleteEc2KeyPair, listSecurityGroups: listEc2SecurityGroups, createSecurityGroup: createEc2SecurityGroup, deleteSecurityGroup: deleteEc2SecurityGroup, authorizeSecurityGroupIngress: authorizeEc2SecurityGroupIngress, revokeSecurityGroupIngress: revokeEc2SecurityGroupIngress, authorizeSecurityGroupEgress: authorizeEc2SecurityGroupEgress, revokeSecurityGroupEgress: revokeEc2SecurityGroupEgress, listAvailabilityZones: listEc2AvailabilityZones, listInstanceTypes: listEc2InstanceTypes, modifySubnetAttribute: modifyEc2SubnetAttribute, getVpcAttributes: getEc2VpcAttributes, modifyVpcAttribute: modifyEc2VpcAttribute, associateElasticIp: associateEc2ElasticIp, disassociateElasticIp: disassociateEc2ElasticIp, listVpcs: listEc2Vpcs, createVpc: createEc2Vpc, deleteVpc: deleteEc2Vpc, listSubnets: listEc2Subnets, createSubnet: createEc2Subnet, deleteSubnet: deleteEc2Subnet, listInternetGateways: listEc2InternetGateways, createInternetGateway: createEc2InternetGateway, attachInternetGateway: attachEc2InternetGateway, detachInternetGateway: detachEc2InternetGateway, deleteInternetGateway: deleteEc2InternetGateway, listNatGateways: listEc2NatGateways, createNatGateway: createEc2NatGateway, deleteNatGateway: deleteEc2NatGateway, listRouteTables: listEc2RouteTables, createRouteTable: createEc2RouteTable, deleteRouteTable: deleteEc2RouteTable, createRoute: createEc2Route, deleteRoute: deleteEc2Route, associateRouteTable: associateEc2RouteTable, disassociateRouteTable: disassociateEc2RouteTable, listElasticIps: listEc2ElasticIps, allocateElasticIp: allocateEc2ElasticIp, releaseElasticIp: releaseEc2ElasticIp, createVpcWizard, };