@nfps.dev/cli
Version:
CLI for NFP development, inspection, and manipulation
195 lines • 7.36 kB
JavaScript
import { debug } from 'node:console';
import { writeFile } from 'node:fs/promises';
import { URL } from 'node:url';
import { oderac, buffer_to_hex } from '@blake.regalia/belt';
import { gen_sk, sk_to_pk, pubkey_to_bech32, } from '@solar-republic/neutrino';
import prompts from 'prompts';
import { check_writable_env, define_command, env_exists, exit, result, validate_bech32 } from '../common.js';
import { H_DEFAULT_NETWORKS } from '../constants.js';
const cancel = () => exit('Init cancelled');
const validate_non_empty = (s) => !!s.trim() || 'Must not be empty';
const validate_urls = (s) => {
const a_urls = s.trim().split(/\s*,\s*/g);
for (const p_url of a_urls) {
try {
new URL(p_url);
}
catch (e_parse) {
return `Invalid URL <${p_url}>: ${e_parse.message}`;
}
}
return true;
};
export const H_CMDS_INIT = {
// nfp init
init: define_command({
info: 'set up an nfp config',
opts: {
force: {
alias: 'f',
type: 'boolean',
desc: 'overwrite an existing .env file if present',
},
},
async handler(g_argv) {
// check for existing .env file
const b_existing = await env_exists();
if (b_existing) {
// check if file is write-protected
await check_writable_env();
// overwrite is not explicit
if (!g_argv.force) {
// confirm user wants to overwrite
const { confirm: b_confirm } = await prompts([
{
type: 'confirm',
name: 'confirm',
message: 'Replace existing .env file?',
onRender() {
// @ts-expect-error no-option not defined in typings
this.noOption = '(y/N) bypass this prompt with `-f` option';
},
},
]);
// cancel
if (!b_confirm)
return cancel();
}
}
// chain-id
let { network: si_chain } = await prompts([
{
type: 'select',
name: 'network',
message: 'Which network do you want to use?',
choices: [
...oderac(H_DEFAULT_NETWORKS, (si, g_chain) => ({
title: `${g_chain.title} (${si})`,
value: si,
})),
{
title: 'Other',
value: '',
},
],
initial: 1,
},
]);
// cancel
if (!si_chain)
return cancel();
// other
if ('' === si_chain) {
({ chain_id: si_chain } = await prompts([
{
type: 'text',
name: 'chain_id',
message: 'Enter the chain id',
validate: validate_non_empty,
},
]));
// cancel
if (!si_chain)
return cancel();
}
// rest
const { lcds: s_lcds, rpcs: s_rpcs, addr: sa_contract, token_id: si_token, } = await prompts([
{
type: 'text',
name: 'lcds',
message: 'LCD endpoint(s)',
initial: H_DEFAULT_NETWORKS[si_chain]?.lcds ?? '',
validate: validate_urls,
},
{
type: 'text',
name: 'rpcs',
message: 'RPC endpoint(s)',
initial: H_DEFAULT_NETWORKS[si_chain]?.rpcs ?? '',
validate: validate_urls,
},
{
type: 'text',
name: 'addr',
message: 'Contract address (leave blank if one does not yet exist)',
validate(sa_input) {
// normalize
sa_input = sa_input.trim();
// omitted
if (!sa_input)
return true;
// validate
return validate_bech32(sa_input);
},
},
{
type: (sa) => sa ? 'text' : null,
name: 'token_id',
message: 'Token ID (leave balnk if one does not yet exist)',
},
]);
// cancel
if ('undefined' === typeof sa_contract)
return cancel();
// generate new private key
const atu8_sk = gen_sk();
const sb16_sk_gen = buffer_to_hex(atu8_sk);
const sa_gen = await pubkey_to_bech32(sk_to_pk(atu8_sk));
// construct env
const sx_out = [
'# WARNING: private keys and passwords are not encrypted!',
'',
`NFP_WEB_LCDS="${s_lcds}"`,
`NFP_WEB_RPCS="${s_rpcs}"`,
`NFP_WEB_COMCS="https://x.s2r.sh/"`,
'',
`NFP_SELF_CHAIN="${si_chain}"`,
`NFP_SELF_CONTRACT="${sa_contract || ''}"`,
`NFP_SELF_TOKEN="${si_token || ''}"`,
'',
`NFP_WALLET_PRIVATE_KEY="${sb16_sk_gen}" # ${sa_gen}`,
].join('\n');
// ask for action
const { action: si_action } = await prompts([
{
type: 'select',
name: 'action',
message: 'Ready to save config?',
choices: [
{
title: b_existing
? 'Overwrite .env file'
: 'Save new .env file',
value: 'save',
},
{
title: 'Print to console',
value: 'print',
},
{
title: `Do both (print and ${b_existing ? 'overwrite' : 'save'})`,
value: 'both',
},
],
},
]);
// cancel
if (!si_action)
return cancel();
// print
if (['print', 'both'].includes(si_action)) {
debug('');
result(sx_out);
}
// save
if (['save', 'both'].includes(si_action)) {
// check writable again
if (await env_exists())
await check_writable_env();
// write to disk
await writeFile('.env', sx_out);
}
},
}),
};
//# sourceMappingURL=init.js.map