mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-07 12:57:47 +00:00
* Move now-cli to /packages/now-cli * Fix .gitignore paths * Add now-client * Add lerna to top level * Add scripts * Update codeowners * Fix `/now-cli/build.ts` script * Fix circleci path to artifacts * Use relative paths * Fix path to scripts * Add test-lint script * Add missing return type * Fix typo in test-lint * Fix string match in shell scripts * Fix path to hugo * Add package node_modules * Delete lock files in packages, use root yarn.lock * Add missing b.js file * Add test-integration-now-dev script * Add missing test files * Add missing integration test script * Add missing test files * Delete travis.yml * Fix ts-jest in now-client * Add support for Node 8 (ES2015 target) * Add support for Node 8 * Add polyfill for Node 8 * Fix polyfill for Node 8 * Only run coverage for now-cli * Add packages from now-builders * Run integration tests for builders * Add node_modules to cache * Add root readme.md * Move readme to top level * Add yarn bootstrap * Add bootstrap step * Add dist to `persist_to_workspace` * Fix 08-yarn-npm integration test * Remove duplicate path * Change stdio to inherit * Add back store_artifacts * testing - remove bootstrap step * Add back now-build-utils * Remove bootstrap step * Fix test again * Add console.log() * Fix lint * Use local ncc version * Install go * Revert changes to stdio and console.log() * Add missing now-go test * Add missing integration tests * Add --runInBand flag * Fix now-node-bridge persistence * Add missing symlinks * Add codeowners * Consolidate into single run.sh function * Run uniq * Fix typo * Change now-routing-utils to test-unit * Special case test for node 8 * Add docs from builders * Only run script for modified packages * Add test-integration-once which only runs once * Fix set intersection
172 lines
4.9 KiB
JavaScript
172 lines
4.9 KiB
JavaScript
import ansiEscapes from 'ansi-escapes';
|
|
import chalk from 'chalk';
|
|
import ccValidator from 'credit-card';
|
|
import textInput from '../../util/input/text';
|
|
import cardBrands from '../../util/billing/card-brands';
|
|
import success from '../../util/output/success';
|
|
import wait from '../../util/output/wait';
|
|
import chars from '../../util/output/chars';
|
|
import rightPad from '../../util/output/right-pad';
|
|
import error from '../../util/output/error';
|
|
|
|
const expDateMiddleware = data => data;
|
|
|
|
export default async function({ creditCards, clear = false, contextName }) {
|
|
const state = {
|
|
error: undefined,
|
|
cardGroupLabel: `> ${chalk.bold(
|
|
`Enter your card details for ${chalk.bold(contextName)}`
|
|
)}`,
|
|
|
|
name: {
|
|
label: rightPad('Full Name', 12),
|
|
placeholder: 'John Appleseed',
|
|
validateValue: data => data.trim().length > 0
|
|
},
|
|
|
|
cardNumber: {
|
|
label: rightPad('Number', 12),
|
|
mask: 'cc',
|
|
placeholder: '#### #### #### ####',
|
|
validateKeypress: (data, value) => /\d/.test(data) && value.length < 19,
|
|
validateValue: data => {
|
|
data = data.replace(/ /g, '');
|
|
const type = ccValidator.determineCardType(data);
|
|
if (!type) {
|
|
return false;
|
|
}
|
|
return ccValidator.isValidCardNumber(data, type);
|
|
}
|
|
},
|
|
|
|
ccv: {
|
|
label: rightPad('CCV', 12),
|
|
mask: 'ccv',
|
|
placeholder: '###',
|
|
validateValue: data => {
|
|
const brand = state.cardNumber.brand.toLowerCase();
|
|
return ccValidator.doesCvvMatchType(data, brand);
|
|
}
|
|
},
|
|
|
|
expDate: {
|
|
label: rightPad('Exp. Date', 12),
|
|
mask: 'expDate',
|
|
placeholder: 'mm / yyyy',
|
|
middleware: expDateMiddleware,
|
|
validateValue: data => !ccValidator.isExpired(...data.split(' / '))
|
|
}
|
|
};
|
|
|
|
async function render() {
|
|
for (const key in state) {
|
|
if (!Object.hasOwnProperty.call(state, key)) {
|
|
continue;
|
|
}
|
|
|
|
const piece = state[key];
|
|
|
|
if (typeof piece === 'string') {
|
|
console.log(piece);
|
|
} else if (typeof piece === 'object') {
|
|
let result;
|
|
|
|
try {
|
|
/* eslint-disable no-await-in-loop */
|
|
result = await textInput({
|
|
label: `- ${piece.label}`,
|
|
initialValue: piece.initialValue || piece.value,
|
|
placeholder: piece.placeholder,
|
|
mask: piece.mask,
|
|
validateKeypress: piece.validateKeypress,
|
|
validateValue: piece.validateValue,
|
|
autoComplete: piece.autoComplete
|
|
});
|
|
|
|
piece.value = result;
|
|
|
|
if (key === 'cardNumber') {
|
|
let brand = cardBrands[ccValidator.determineCardType(result)];
|
|
piece.brand = brand;
|
|
|
|
if (brand === 'American Express') {
|
|
state.ccv.placeholder = '#'.repeat(4);
|
|
} else {
|
|
state.ccv.placeholder = '#'.repeat(3);
|
|
}
|
|
|
|
brand = chalk.cyan(`[${brand}]`);
|
|
const masked = chalk.gray('#### '.repeat(3)) + result.split(' ')[3];
|
|
process.stdout.write(
|
|
`${chalk.cyan(chars.tick)} ${piece.label}${masked} ${brand}\n`
|
|
);
|
|
} else if (key === 'ccv') {
|
|
process.stdout.write(
|
|
`${chalk.cyan(chars.tick)} ${piece.label}${'*'.repeat(
|
|
result.length
|
|
)}\n`
|
|
);
|
|
} else if (key === 'expDate') {
|
|
let text = result.split(' / ');
|
|
text = text[0] + chalk.gray(' / ') + text[1];
|
|
process.stdout.write(
|
|
`${chalk.cyan(chars.tick)} ${piece.label}${text}\n`
|
|
);
|
|
} else {
|
|
process.stdout.write(
|
|
`${chalk.cyan(chars.tick)} ${piece.label}${result}\n`
|
|
);
|
|
}
|
|
} catch (err) {
|
|
if (err.message === 'USER_ABORT') {
|
|
process.exit(1);
|
|
} else {
|
|
console.error(error(err));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log(''); // New line
|
|
const stopSpinner = wait('Saving card');
|
|
|
|
try {
|
|
const res = await creditCards.add({
|
|
name: state.name.value,
|
|
cardNumber: state.cardNumber.value,
|
|
ccv: state.ccv.value,
|
|
expDate: state.expDate.value
|
|
});
|
|
|
|
stopSpinner();
|
|
|
|
if (clear) {
|
|
const linesToClear = state.error ? 15 : 14;
|
|
process.stdout.write(ansiEscapes.eraseLines(linesToClear));
|
|
}
|
|
|
|
console.log(
|
|
success(
|
|
`${state.cardNumber.brand ||
|
|
state.cardNumber.card.brand} ending in ${res.last4 ||
|
|
res.card.last4} was added to ${chalk.bold(contextName)}`
|
|
)
|
|
);
|
|
} catch (err) {
|
|
stopSpinner();
|
|
const linesToClear = state.error ? 15 : 14;
|
|
process.stdout.write(ansiEscapes.eraseLines(linesToClear));
|
|
state.error = `${chalk.red(
|
|
'> Error!'
|
|
)} ${err.message} Please make sure the info is correct`;
|
|
await render();
|
|
}
|
|
}
|
|
|
|
try {
|
|
await render();
|
|
} catch (err) {
|
|
console.erorr(err);
|
|
}
|
|
}
|