UNPKG

@httpc/cli

Version:

httpc cli for building function-based API with minimal code and end-to-end type safety

151 lines (150 loc) 5.67 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CallCommand = void 0; const promises_1 = __importDefault(require("fs/promises")); const path_1 = __importDefault(require("path")); const commander_1 = require("commander"); const prompts_1 = __importDefault(require("prompts")); const kleur_1 = __importDefault(require("kleur")); const client_1 = require("@httpc/client"); const utils_1 = require("../utils"); exports.CallCommand = (0, commander_1.createCommand)("call") .description("call a function on an httpc server") .option("--setup", "create a configuration used for all calls") .option("--no-config", "don't load the config even if present") .option("-s, --server <address>", "the httpc server address") .addOption(new commander_1.Option("-a, --access <level>", "set the call access type").choices(["read", "write"])) .option("--read", "shortcut for --access read") .arguments("[arguments...]") .configureHelp({ commandDescription: () => "", commandUsage: cmd => ` httpc ${cmd.name()} --setup create a configuration used for all calls httpc ${cmd.name()} <function> [arguments...] call a function on an httpc server` }) .action(async ([callPath, ...args], options) => { if (options.setup) { await runCallSetup(); return; } if (!callPath) { throw new Error("Missing function to call"); } const config = options.config ? await readConfig() : undefined; const { read, access = read ? "read" : "write", endpoint = config?.endpoint || "http://localhost:3000", } = options; // args preprocessing // 1. try to parse numbers // 2. try to parse objects {...} const params = args.map(x => { if (!isNaN(x)) { return Number(x); } else if (x.startsWith("{") && x.endsWith("}")) { return JSON.parse(x); } else { return x; } }); const client = createClient({ ...config, endpoint, }); const result = await (access === "read" ? client.read(callPath, ...params) : client.write(callPath, ...params)).catch(err => { if (err instanceof Error && err.name === "FetchError") { utils_1.log.error(err.message); return err; } if (err instanceof client_1.HttpCClientError) { utils_1.log.error(`HTTP ${err.status}`); return err.body; } throw err; }); if (result instanceof Error) { // already handled return; } if (result === undefined) { utils_1.log.minor("(no value)"); return; } console.log(JSON.stringify(result, undefined, 2)); }); const DEFAULT_CONFIG_FILE = "httpc-client.config.local"; async function readConfig() { try { const configFile = DEFAULT_CONFIG_FILE; return JSON.parse(await promises_1.default.readFile(configFile, "utf8")); } catch { } } async function runCallSetup() { console.log("This procedure will help to create a common configuration used by all calls"); const responses = await (0, prompts_1.default)([ { name: "endpoint", type: "text", message: "Type the server address", initial: "http://localhost:3000", validate: value => { try { return !!new URL(value); } catch { return false; } } }, { name: "authentication", type: "select", message: "Select authentication", choices: [ { title: "None", value: "none" }, { title: "Bearer", value: "Bearer" }, { title: "ApiKey", value: "ApiKey" }, ] }, { name: "token", type: prev => prev === "none" ? null : "password", message: prev => `Type the ${prev === "Bearer" ? "bearer token" : "api key"}` }, ], { onCancel: () => { process.exit(0); } }); const configuration = { endpoint: responses.endpoint, authentication: responses.authentication !== "none" ? `${responses.authentication} ${responses.token}` : undefined }; const configFile = path_1.default.resolve(DEFAULT_CONFIG_FILE); await promises_1.default.writeFile(configFile, JSON.stringify(configuration, undefined, 2), "utf8"); console.log("\r"); utils_1.log.done(`Written configuration to: ${kleur_1.default.bold("%s")}`, configFile); console.log("\nNow on this configuration is shared by all calls"); console.log(`You can run ${kleur_1.default.bold("httpc call --setup")} again to change it`); console.log("Or you can delete it if you don't need it anymore"); } function createClient(options) { const client = new client_1.HttpCClient({ endpoint: options.endpoint, }); if (options.authentication) { const [schema, value] = options.authentication.split(" "); if (!schema || !value) { utils_1.log.error("Invalid configuration: authentication is malformed"); process.exit(1); } client.use((0, client_1.AuthHeader)(schema, value)); } return client; }