ecs-pf
Version:
CLI for port-forwarding to RDS via AWS ECS
125 lines (124 loc) • 4.44 kB
JavaScript
import { input, search } from "@inquirer/prompts";
import { isTaskArnShape } from "../regex.js";
import { searchClusters, searchInferenceResults, searchRDS, searchRegions, searchTasks, } from "../search.js";
import { parsePort } from "../types/parsers.js";
import { isFailure, parseRegionName, parseTaskArn } from "../types.js";
import { messages } from "../utils/index.js";
const DEFAULT_PAGE_SIZE = 50;
function isRegionName(value) {
return typeof value === "string";
}
function isECSCluster(value) {
return (typeof value === "object" &&
value !== null &&
"clusterName" in value &&
"clusterArn" in value);
}
function isRDSInstance(value) {
return (typeof value === "object" &&
value !== null &&
"dbInstanceIdentifier" in value &&
"endpoint" in value);
}
function isInferenceResult(value) {
return (typeof value === "object" &&
value !== null &&
"cluster" in value &&
"task" in value &&
"confidence" in value);
}
export async function promptForRegion(params) {
const { regions, defaultRegion } = params;
messages.info("filtered as you type (↑↓ to select, Enter to confirm)");
const selectedValue = await search({
message: "Search and select AWS region:",
source: async (input) => {
return await searchRegions(regions, input || "", defaultRegion);
},
pageSize: DEFAULT_PAGE_SIZE,
});
if (!isRegionName(selectedValue)) {
throw new Error("Invalid region selection");
}
const parseResult = parseRegionName(selectedValue);
if (isFailure(parseResult)) {
throw new Error(`Invalid region name: ${parseResult.error}`);
}
return parseResult.data;
}
export async function promptForCluster(params) {
const { clusters } = params;
messages.info("filtered as you type (↑↓ to select, Enter to confirm)");
const selectedValue = await search({
message: "Search and select ECS cluster:",
source: async (input) => {
return await searchClusters(clusters, input || "");
},
pageSize: DEFAULT_PAGE_SIZE,
});
if (!isECSCluster(selectedValue)) {
throw new Error("Invalid cluster selection");
}
return selectedValue;
}
export async function promptForTask(params) {
const { tasks } = params;
const selectedValue = await search({
message: "Search and select ECS task:",
source: async (input) => {
return await searchTasks(tasks, input || "");
},
pageSize: DEFAULT_PAGE_SIZE,
});
if (!isTaskArnShape(selectedValue)) {
throw new Error("Invalid task selection");
}
const parseResult = parseTaskArn(selectedValue);
if (isFailure(parseResult)) {
throw new Error(`Invalid task ARN: ${parseResult.error}`);
}
return parseResult.data;
}
export async function promptForRDS(params) {
const { rdsInstances } = params;
const selectedValue = await search({
message: "Search and select RDS instance:",
source: async (input) => {
return await searchRDS(rdsInstances, input || "");
},
pageSize: DEFAULT_PAGE_SIZE,
});
if (!isRDSInstance(selectedValue)) {
throw new Error("Invalid RDS instance selection");
}
return selectedValue;
}
export async function promptForInferenceResult(params) {
const { inferenceResults } = params;
const selectedValue = await search({
message: "Select ECS target (filter with keywords like 'prod web' or 'staging api'):",
source: async (input) => {
return await searchInferenceResults(inferenceResults, input || "");
},
pageSize: DEFAULT_PAGE_SIZE,
});
if (!isInferenceResult(selectedValue)) {
throw new Error("Invalid inference result selection");
}
return selectedValue;
}
export async function promptForLocalPort() {
const portString = await input({
message: "Enter local port number:",
default: "8888",
validate: (inputValue) => {
const parseResult = parsePort(inputValue || "8888");
return parseResult.success ? true : `Invalid port: ${parseResult.error}`;
},
});
const parseResult = parsePort(portString);
if (isFailure(parseResult)) {
throw new Error(`Failed to parse port: ${parseResult.error}`);
}
return parseResult.data;
}