Files
2026-07-13 12:30:28 +08:00

239 lines
6.5 KiB
TypeScript

import dotenv from 'dotenv';
dotenv.config();
import { checkNodeVersion } from './utils/checkNodeVersion';
checkNodeVersion();
import { Command } from 'commander';
import chalk from 'chalk';
import figlet from 'figlet';
import { version } from '../package.json';
import upload from './upload';
import importFile from './importCar';
import exportFile from './exportCar';
import remove from './remove';
import { displayUploadHistory, clearUploadHistory } from './utils/history';
import setAppKeyCmd from './set-appkey';
import logoutCmd from './logout';
import showAppKeyCmd from './show-appkey';
import myDomainsCmd from './my-domains';
import walletBalanceCmd from './wallet-balance';
import bindCmd from './bind';
import loginCmd, { EnvOption } from './login';
import createCmd from './create';
import saveCmd from './save';
import updateDbCmd from './updateDb';
import updateWorkerCmd from './updateWorker';
import updateWebCmd from './updateWeb';
import deleteCmd from './delete';
interface SaveOptions {
name?: string;
domain?: string;
}
// display the ASCII art logo
function showBanner(): void {
console.log(
chalk.cyan(figlet.textSync('Pinme', { horizontalLayout: 'full' })),
);
console.log(chalk.cyan('A command-line tool for uploading files to IPFS\n'));
}
const program = new Command();
program
.name('pinme')
.version(version)
.option('-v, --version', 'output the current version');
program
.command('upload')
.description(
'upload a file or directory to IPFS. Supports --domain to bind after upload',
)
.option('-d, --domain <name>', 'Domain name to bind')
.option('--dns', 'Force DNS domain mode')
.action(() => upload());
program
.command('import')
.description("import a CAR file to IPFS. Supports --domain to bind after import")
.option('-d, --domain <name>', 'Pinme subdomain')
.action(() => importFile());
program
.command('export')
.description('export IPFS content as CAR file')
.option('-o, --output <path>', 'output file path for CAR file')
.action(() => exportFile());
program
.command('rm')
.description('remove a file from IPFS network')
.action(() => remove());
program
.command('login')
.description('Login via browser (opens web login page)')
.option('-e, --env <env>', 'Environment: test, prod')
.action((options: EnvOption) => loginCmd(options));
program
.command('set-appkey')
.description(
'Set AppKey for authentication (alternative to login command)',
)
.action(() => setAppKeyCmd());
program
.command('logout')
.description('log out and clear authentication')
.action(() => logoutCmd());
program
.command('show-appkey')
.alias('appkey')
.description('show current AppKey information (masked)')
.action(() => showAppKeyCmd());
program
.command('my-domains')
.alias('domain')
.description('List domains owned by current account')
.action(() => myDomainsCmd());
program
.command('wallet')
.alias('wallet-balance')
.alias('balance')
.description('Show current wallet balance')
.action(() => walletBalanceCmd());
program
.command('bind')
.description('Upload and bind to a domain (requires wallet balance)')
.option('-d, --domain <name>', 'Domain name to bind')
.option('--dns', 'Force DNS domain mode')
.action(() => bindCmd());
program
.command('create')
.description('Create a new project from template')
.argument('[name]', 'Project name')
.option('-f, --force', 'Overwrite if exists')
.action((name: string | undefined, options: { force?: boolean }) => createCmd({ name, force: options?.force }));
program
.command('save')
.description('Deploy the project (frontend + backend)')
.option('-d, --domain <name>', 'Bind a domain after frontend deploy')
.action((options: SaveOptions) => saveCmd(options));
program
.command('update-db')
.description('Execute database migration')
.action(() => updateDbCmd());
program
.command('update-worker')
.description('Execute worker migration')
.action(() => updateWorkerCmd());
program
.command('update-web')
.description('Deploy frontend to IPFS')
.action((options: { name?: string }) => updateWebCmd(options));
program
.command('delete')
.description('Delete a project (Worker, domain, D1 database)')
.argument('[name]', 'Project name')
.option('-f, --force', 'Skip confirmation')
.action((name: string | undefined, options: { force?: boolean }) => deleteCmd({ name, force: options?.force }));
program
.command('domain')
.description("Alias for 'my-domains' command")
.action(() => myDomainsCmd());
program
.command('list')
.description('show upload history')
.option(
'-l, --limit <number>',
'limit the number of records to show',
parseInt,
)
.option('-c, --clear', 'clear all upload history')
.action(async (options: { limit?: number; clear?: boolean }) => {
if (options.clear) {
clearUploadHistory();
} else {
await displayUploadHistory(options.limit || 10);
}
});
// add ls command as an alias for list command
program
.command('ls')
.description("alias for 'list' command")
.option(
'-l, --limit <number>',
'limit the number of records to show',
parseInt,
)
.option('-c, --clear', 'clear all upload history')
.action(async (options: { limit?: number; clear?: boolean }) => {
if (options.clear) {
clearUploadHistory();
} else {
await displayUploadHistory(options.limit || 10);
}
});
// add help command
program
.command('help')
.description('display help information')
.action(() => {
showBanner();
program.help();
});
// custom help output format
program.on('--help', () => {
console.log('');
console.log('Examples:');
console.log(' $ pinme upload');
console.log(' $ pinme upload <path> --domain <name>');
console.log(' $ pinme import');
console.log(' $ pinme import <path> --domain <name>');
console.log(' $ pinme export <cid> --output <path>');
console.log(' $ pinme rm <hash>');
console.log(' $ pinme login');
console.log(' $ pinme set-appkey <AppKey>');
console.log(' $ pinme show-appkey');
console.log(' $ pinme logout');
console.log(' $ pinme my-domains');
console.log(' $ pinme domain');
console.log(' $ pinme list -l 5');
console.log(' $ pinme ls');
console.log(' $ pinme help');
console.log('');
console.log(
'For more information, visit: https://github.com/glitternetwork/pinme',
);
});
// parse the command line arguments
program.parse(process.argv);
// If no arguments provided, show banner and help
if (process.argv.length === 2) {
showBanner();
program.help();
}