UNPKG

@kadena/kadena-cli

Version:

Kadena CLI tool to interact with the Kadena blockchain (manage keys, transactions, etc.)

331 lines 13 kB
import { basename, parse } from 'node:path'; import { chainIdRangeValidation, createFundAmountValidation, getAllAccountNames, parseChainIdRange, } from '../commands/account/utils/accountHelpers.js'; import { CHAIN_ID_RANGE_ERROR_MESSAGE } from '../constants/account.js'; import { MAX_CHAIN_VALUE } from '../constants/config.js'; import { INVALID_FILE_NAME_ERROR_MSG, MULTI_SELECT_INSTRUCTIONS, } from '../constants/global.js'; import { services } from '../services/index.js'; import { formatZodError, isNotEmptyString, isValidFilename, maskStringPreservingStartAndEnd, notEmpty, truncateText, } from '../utils/globalHelpers.js'; import { checkbox, input, select } from '../utils/prompts.js'; import { tableFormatPrompt } from '../utils/tableDisplay.js'; export const publicKeysPrompt = async (previousQuestions, args, isOptional) => await input({ message: 'Enter one or more public keys (comma separated):', validate: function (value) { if (isOptional && !value) return true; if (!value || !value.trim().length) { return 'Please enter public keys'; } return true; }, }); export const accountAliasPrompt = async () => await input({ message: 'Enter an alias for an account:', validate: async function (value) { if (!value || value.trim().length < 3) { return 'Alias must be minimum at least 3 characters long.'; } if (!isValidFilename(value)) { return `Alias is used as a filename. ${INVALID_FILE_NAME_ERROR_MSG}`; } const allAccountAliases = (await getAllAccountNames()).map((account) => basename(account.alias, '.yaml')); if (allAccountAliases.includes(value)) { return `Alias "${value}" already exists. Please enter a different alias.`; } return true; }, }); export const accountNamePrompt = async () => await input({ message: 'Enter an account name (optional):', }); export const accountKdnAddressPrompt = async () => await input({ message: 'Enter an k:account:', }); export const accountKdnNamePrompt = async () => await input({ message: 'Enter an .kda name:', }); export const fundAmountPrompt = async (previousQuestions, args, isOptional) => await input({ validate(value) { const parsedValue = parseFloat(value.trim().replace(',', '.')); const maxAmountString = Number(previousQuestions.maxAmount); const numberOfChains = previousQuestions.numberOfChains; const parseResult = createFundAmountValidation(numberOfChains, maxAmountString).safeParse(parsedValue); if (!parseResult.success) { const formatted = parseResult.error.format(); return `Amount: ${formatted._errors[0]}`; } return true; }, message: 'Enter an amount:', default: previousQuestions === null || previousQuestions === void 0 ? void 0 : previousQuestions.maxAmount, }); export const fungiblePrompt = async () => await input({ default: 'coin', message: 'Enter the name of a fungible:', }); export const predicatePrompt = async (previousQuestions) => { const allowedPredicates = previousQuestions.allowedPredicates !== undefined ? previousQuestions.allowedPredicates : []; const choices = [ { value: 'keys-all', name: 'keys-all', }, { value: 'keys-any', name: 'keys-any', }, { value: 'keys-2', name: 'keys-2', }, { value: 'custom', name: 'Custom predicate', }, ]; const filteredChoices = choices.filter((choice) => allowedPredicates.length === 0 || allowedPredicates.includes(choice.value)); const selectedPredicate = await select({ message: 'Select a keyset predicate:', choices: filteredChoices, }); if (selectedPredicate === 'custom') { const customPredicate = await input({ message: 'Enter your own predicate:', validate: function (value) { if (!value || !value.trim().length) { return 'Predicate cannot be empty.'; } return true; }, }); return customPredicate.trim(); } return selectedPredicate; }; export const accountOverWritePrompt = async () => await select({ message: 'Would you like to use the account details on the chain?', choices: [ { value: true, name: 'Yes, use public keys and predicate from chain', }, { value: false, name: 'No, use it from user input', }, ], }); export const getAllAccountChoices = async () => { const allAccounts = await getAllAccountNames(); const maxAliasLength = Math.max(...allAccounts.map(({ alias }) => alias.length)); return allAccounts.map(({ alias, name }) => { const aliasWithoutExtension = parse(alias).name; const maxLength = maxAliasLength < 25 ? maxAliasLength : 25; const paddedAlias = aliasWithoutExtension.padEnd(maxLength, ' '); return { value: aliasWithoutExtension, name: `${truncateText(paddedAlias, 25)} - ${maskStringPreservingStartAndEnd(name, 20)}`, }; }); }; export const accountSelectionPrompt = async (options = []) => { const allAccountChoices = await getAllAccountChoices(); if (options.includes('all')) { allAccountChoices.unshift({ value: 'all', name: 'All accounts', }); } if (options.includes('allowManualInput')) { allAccountChoices.unshift({ value: 'custom', name: 'Enter an account name manually:', }); } const selectedAlias = await select({ message: 'Select an account (alias - account name):', choices: allAccountChoices, }); if (selectedAlias === 'custom') { const accountName = await input({ message: 'Please enter the account name:', validate: function (value) { if (!value || !value.trim().length) { return 'Account name cannot be empty.'; } return true; }, }); return accountName.trim(); } return selectedAlias; }; export const accountSelectPrompt = async (previousQuestions) => { const options = previousQuestions.isAllowManualInput === true ? ['allowManualInput'] : []; return await accountSelectionPrompt(options); }; export const accountSelectAllPrompt = async (previousQuestions) => { return await accountSelectionPrompt(['all']); }; export const accountSelectMultiplePrompt = async (previousQuestions, args, isOptional) => { const allAccountChoices = await getAllAccountChoices(); const selectedAliases = await checkbox({ message: 'Select an account (alias - account name):', choices: allAccountChoices, instructions: MULTI_SELECT_INSTRUCTIONS, }); return selectedAliases.join(','); }; export const accountDeleteConfirmationPrompt = async (previousQuestions, args, isOptional) => { const selectedAccounts = previousQuestions.accountAlias; const selectedAccountsLength = selectedAccounts.split(',').length; const selectedAccountMessage = previousQuestions.accountAlias === 'all' ? 'all the accounts' : selectedAccountsLength > 1 ? 'all the selected aliases accounts' : `the ${selectedAccounts} alias account`; const answer = await input({ message: `Are you sure you want to delete ${selectedAccountMessage}?\n type "yes" to confirm or "no" to cancel and press enter. \n`, validate: (input) => { if (input === 'yes' || input === 'no') { return true; } return 'Please type "yes" to confirm or "no" to cancel.'; }, }); return answer === 'yes'; }; export const chainIdPrompt = async (previousQuestions, args, isOptional) => { const defaultValue = args.defaultValue || '0'; return (await input({ message: `Enter a ChainId (0-${MAX_CHAIN_VALUE}) (comma or hyphen separated e.g 0,1,2 or 1-5 or all):`, default: defaultValue, validate: function (input) { if (input.trim() === 'all') return true; const parseInput = parseChainIdRange(input); if (!parseInput || !parseInput.length) { return CHAIN_ID_RANGE_ERROR_MESSAGE; } const result = chainIdRangeValidation.safeParse(parseInput); if (!result.success) { const formatted = formatZodError(result.error); return `ChainId: ${formatted}`; } return true; }, })); }; export const addManualPublicKeysPrompt = async (previousQuestions, args, isOptional) => { const plainKeys = await services.plainKey.list(process.cwd()); const selectedKeys = await checkbox({ message: 'Select public keys to add to account(alias - publickey):', choices: [ { value: '_manual_', name: 'Enter public key manually:', }, ...tableFormatPrompt([ ...plainKeys.map((key) => { const { alias, publicKey } = key; return { value: publicKey, name: [ isNotEmptyString(alias) ? truncateText(alias, 24) : '', maskStringPreservingStartAndEnd(publicKey, 24), ], }; }), ]), ], pageSize: 10, instructions: MULTI_SELECT_INSTRUCTIONS, validate: (input) => { if (input.length === 0) { return 'Please select at least one public key'; } return true; }, }); if (selectedKeys.includes('_manual_')) { const keys = selectedKeys.filter((key) => key !== '_manual_'); const customPublicKey = await publicKeysPrompt(previousQuestions, args, isOptional); keys.push(customPublicKey); return keys.join(','); } return selectedKeys.join(','); }; export const publicKeysForAccountAddPrompt = async (previousQuestions, args, isOptional) => { if (previousQuestions.from === 'key') { return addManualPublicKeysPrompt(previousQuestions, args, isOptional); } if (!notEmpty(previousQuestions.walletNameConfig)) { throw new Error('Wallet config is not provided'); } const wallet = previousQuestions.walletNameConfig; const keysList = [wallet].flatMap((wallet) => wallet.keys.map((key) => key)); const selectedKeys = await checkbox({ message: 'Select public keys to add to account(index - alias - publickey):', choices: [ ...tableFormatPrompt([ ...keysList.map((key) => { const { index, alias, publicKey } = key; return { value: publicKey, name: [ index.toString(), isNotEmptyString(alias) ? truncateText(alias, 24) : '', maskStringPreservingStartAndEnd(publicKey, 24), ], }; }), ]), { value: '_generate_', name: 'Generate new public key', }, ], pageSize: 10, instructions: MULTI_SELECT_INSTRUCTIONS, validate: (input) => { if (input.length === 0) { return 'Please select at least one public key'; } return true; }, }); return selectedKeys.join(','); }; export const accountFromSelectionPrompt = async () => { return await select({ message: `How would you like to add the account locally?`, choices: [ { value: 'key', name: 'Key - Add an account by by providing public keys from a key file or entering key details manually', }, { value: 'wallet', name: 'Wallet - Add an account by by providing public keys from a list of available wallets', }, ], }); }; export const confirmAccountVerificationPrompt = async () => { return await select({ message: 'Do you want to verify the account on chain?', choices: [ { value: true, name: 'Yes, verify the account on chain before adding', }, { value: false, name: 'No, add the account without verifying on chain', }, ], }); }; //# sourceMappingURL=account.js.map