UNPKG

dwnpm

Version:

Decentralized Registry Package Manager (DRPM) helps developers publish, install, find and manage Decentralized Packages (DPKs) published to Decentralized Web Nodes (DWNs). DRPM does this by looking up a Decentralized Identifier (DID) to find its DID docum

300 lines 15.3 kB
#!/usr/bin/env node import { program } from 'commander'; import { readFileSync } from 'fs'; import { dirname, join } from 'path'; import { fileURLToPath } from 'url'; import { DRPM_HOME, DRPM_PROFILE } from '../config.js'; import { ConnectCommand } from './commands/connect.js'; import { ContextCommand } from './commands/context.js'; import { PackageCommand } from './commands/package.js'; import { ProfileCommand } from './commands/profile.js'; import { RegistryCommand } from './commands/registry.js'; import { SetupCommand } from './commands/setup.js'; import { DwnCommand } from './commands/dwn.js'; import { Logger } from '../utils/logger.js'; export const DEFAULT_DATAPATH = `${DRPM_HOME}/DHT/<ENDPOINT>/<0|cuid>/DATA/AGENT)`; class DRegistryPackageManager { DRPM = program; VERSION = 'latest'; constructor() { this.addDetails(); this.addCommands(); } addProfileCommands() { /* ============ PROFILE COMMANDS ============ */ const profileCommand = new ProfileCommand(); // drpm profile const profile = this.DRPM.command('profile'); profile.description(`Manage your profile (location: ${DRPM_PROFILE}`); // profile read profile .command('read') .description('Prints the entire profile.json') .option('-t, --text', 'Prints the profile in plain text') .addHelpText('after', `Examples:\n drpm profile read # Returns the profile.json`).action(async (options) => await this.invokeCommand({ options, command: profileCommand, subcommand: 'read' })); // profile delete profile.command('delete') .description('Delete the current profile.json') .option('-f, --force', 'Force delete the profile.json without backing up') .option('-p, --password [PASSWORD]', `Provide a custom password to encypt backup (default: random saved to ${DRPM_HOME}/bak/<randhex>/profile.key)`) .addHelpText('after', `Examples: drpm profile delete # Delete profile.json, creates backup w/ random password drpm profile delete -p "correct horse battery staple" # Delete profile.json, creates backup w/ custom password`).action(async (options) => await this.invokeCommand({ options, command: profileCommand, subcommand: 'delete' })); // profile add profile .command('add') .description('Add a new context to profile.json') .option('-n, --name <NAME>', 'Name of the context to add; Names are based on DID Methods') .allowUnknownOption() .addHelpText('after', `Examples:\n drpm profile add -n btc1 {...} # Adds a new profile context called btc1`).action(async (options) => await this.invokeCommand({ options, command: profileCommand, subcommand: 'add' })); // profile list profile .command('list') .description('Shows a list of available profile contexts') .addHelpText('after', `Examples:\n drpm profile list # Lists out available profile contexts`).action(async () => await this.invokeCommand({ command: profileCommand, subcommand: 'list' })); // profile switch profile .command('switch') .description('Switch between different DID profiles.') .option('-n, --name <NAME>', 'Name of the context to switch to; Names are based on DID Methods') .addHelpText('after', `Examples: drpm profile switch # Display a list of available profiles to switch to drpm profile switch -n dht # Switch to your dht profile drpm profile switch -n web # Switch to your web profile drpm profile switch -n btc # Switch to your btc profile`).action(async (options) => await this.invokeCommand({ options, command: profileCommand, subcommand: 'switch' })); // profile backup profile .command('backup') .description('Backup the current profile.json file') .option('-p, --password [PASSWORD]', `Provide a custom password to encypt backup (default: random written to ${DRPM_HOME}/profile.key)`).addHelpText('after', `Examples: drpm profile backup # Backup profile.json with random, autogenerated password drpm profile backup -p 'correct horse battery staple' # Backup profile.json with custom password`).action(async (options) => await this.invokeCommand({ options, command: profileCommand, subcommand: 'backup' })); // profile recover profile .command('recover') .description('Recover an existing profile.json from a backup file and password') .option('-f, --file <FILEPATH>', 'Path to a profile.enc backup file').option('-p, --password <PASSWORD>', 'Provide the password to decrypt the profile backup (required)').addHelpText('after', `Examples: drpm profile recover -f /path/to/profile.enc -p 'correct horse battery staple' # Recover profile.json from profile.env file and custom password`).action(async (options) => await this.invokeCommand({ options, command: profileCommand, subcommand: 'recover' })); } addContextCommands() { /* ============ CONTEXT COMMANDS ============ */ const contextCommand = new ContextCommand(); const context = this.DRPM.command('context').description('Interact with different profile contexts'); // context create context .command('create') .description('Create a new profile context') .option('-e, --dwnEndpoints <DWNENDPOINTS>', 'Provide one or more DWN endpoints') .option('-p, --password <PASSWORD>', 'Provide a password to encrypt Web5 data (default: random)') .option('-w, --web5DataPath <WEB5DATAPATH>', `Provide file path for storing Web5 data (default: ${DEFAULT_DATAPATH})`) .option('-m, --method <METHOD>', 'Provide a desired did method (default: dht)') .option('-d, --did <METHOD>', 'The method specific id; Required for -m web (e.g. did:web:example.com => example.com)') .addHelpText('after', `Examples: drpm profile create -e https://dwn.mydomain.org # Create new profile with 1 DWN endpoint (REQUIRED: -e) drpm profile create -e https://dwn.example.com,http://localhost:3000 # Create new profile with multiple DWN endpoints (REQUIRED: -e)) drpm profile create -m web -d example.com # Create new profile with did:web method (REQUIRED: -d)`).action(async (options) => await this.invokeCommand({ options, command: contextCommand, subcommand: 'create' })); // context read context .command('read') .description('Read values from the current profile context') .option('-d, --did', 'Read the DID') .option('-p, --password', 'Read the password in plain text') .option('-r, --recoveryPhrase', 'Read the recovery phrase in plain text') .option('-e, --dwnEndpoints', 'Read the DWN endpoints') .option('-w, --web5DataPath', `Read the web5 DATA dir path`) .addHelpText('after', `Examples: drpm profile read # Returns the profile drpm profile read -d # Returns the profile.did drpm profile read -p # Returns the profile.password drpm profile read -r # Returns the profile.recoveryPhrase drpm profile read -e # Returns the profile.dwnEndpoints drpm profile read -w # Returns the profile.web5DataPath`).action(async (options) => await this.invokeCommand({ options, command: contextCommand, subcommand: 'read' })); // context update context .command('update') .description('Update values in the current profile context') .option('-d, --did <DID>', 'Update the DID') .option('-p, --password <PASSWORD>', 'Update the password') .option('-r, --recoveryPhrase <RECOVERYPHRASE>', 'Update the recovery phrase') .option('-e, --dwnEndpoints <DWNENDPOINTS>', 'Update the DWN endpoints') .option('-w, --web5DataPath <WEB5DATAPATH>', `Update the path to the web5 DATA dir`) .addHelpText('after', `Examples: drpm profile update -d did:example:abc123 # Update the profile.did drpm profile update -p "correct horse battery staple" # Update the profile.password drpm profile update -e https://dwn.mydomain.org # Update the profile.dwnEndpoints`).action(async (options) => await this.invokeCommand({ options, command: contextCommand, subcommand: 'update' })); // context delete context .command('delete') .description('Delete the current profile context') .option('-f, --force', 'Force delete the profile context') .option('-p, --password [PASSWORD]', `Provide a custom password to encypt backup (default: random saved to ${DRPM_HOME}/bak/<randhex>/profile.key)`) .addHelpText('after', `Examples: drpm profile delete # Delete profile.json, creates backup w/ random password drpm profile delete -p "correct horse battery staple" # Delete profile.json, creates backup w/ custom password`).action(async (options) => await this.invokeCommand({ options, command: contextCommand, subcommand: 'delete' })); // TODO: context backup /*context .command('backup') .description('Add a new profile context to profile.json') .action( async (options) => await this.invokeCommand({ options, command: contextCommand, subcommand: 'backup' }));*/ // TODO: context recover /*context .command('recover') .description('Add a new profile context to profile.json') .action( async (options) => await this.invokeCommand({ options, command: contextCommand, subcommand: 'recover' }));*/ } addPackageCommands() { /* ============ PACKAGE COMMANDS ============ */ const packageCommand = new PackageCommand(); const dpackage = this.DRPM.command('package').description('Interact with DPKs'); dpackage .command('init') .description('Init/create a new DPK project template') .action(async (options) => await this.invokeCommand({ options, command: packageCommand, subcommand: 'init' })); dpackage .command('create') .description('Alias of init; Create a new DPK project template') .action(async (options) => await this.invokeCommand({ options, command: packageCommand, subcommand: 'create' })); const publish = dpackage.command('publish').description('Publish package metadata or release'); publish .command('metadata') .option('-d, --data <DATA>', 'The metadata to publish as JSON (only required if -p is not provided)') .option('-p, --path [PATH]', 'Path to a metadata file to publish (only required if -d is not provided)') .action(async (options) => await this.invokeCommand({ options, command: packageCommand, subcommand: 'publish metadata', })); publish .command('release') .option('-d, --did <DID>', 'The did to use to publish the package') .option('-r, --release <RELEASE>', 'The type of record to publish; Options: package or release (aka: package/release') .action(async (options) => await this.invokeCommand({ options, command: packageCommand, subcommand: 'publish release', })); dpackage .command('run') .description('Run a given JS file containing DPIs without installing DPKs') .option('-f, --file <FILE>', 'The file to run') .action(async (options) => await this.invokeCommand({ options, command: packageCommand, subcommand: 'run' })); } addRegistryCommands() { /* ============ REGISTRY COMMANDS ============ */ const registryCommands = new RegistryCommand(); this.DRPM.command('registry') .description('Interact with the registry server') .command('start') .action(async (options) => await this.invokeCommand({ options, command: registryCommands })); } addDwnCommands() { /* ============ DWN COMMANDS ============ */ const dwnCommand = new DwnCommand(); this.DRPM .command('dwn') .description('Interact with your DWN or other DWNs') .action(async (options) => await this.invokeCommand({ command: dwnCommand, options })); } addCommands() { this.DRPM.command('setup') .description('Run DRPM setup (src/lib/setup.ts)') .action(async () => await this.invokeCommand({ command: new SetupCommand() })); this.DRPM.command('connect') .description('Connect to web5 using the current profile context or the context provided with -n') .option('-n, --name <NAME>', 'Name of the context to use to connect') .action(async (options) => await this.invokeCommand({ command: new ConnectCommand(), options })); this.addProfileCommands(); this.addContextCommands(); this.addRegistryCommands(); this.addPackageCommands(); this.addDwnCommands(); } addDetails() { const __dirname = dirname(fileURLToPath(import.meta.url)); const packageJsonPath = join(__dirname, '..', '..', 'package.json'); try { const data = JSON.parse(readFileSync(packageJsonPath, 'utf8')); this.VERSION = data.version; } catch (error) { Logger.error('Error reading package.json:', error); } this.DRPM.name('drpm'); this.DRPM.version(`Decentralized Registry Package Manager (drpm) v${this.VERSION} `, '-v, --version', 'Output the current version'); } async invokeCommand({ command, options, subcommand }) { try { await command.execute({ options, subcommand }); process.exit(0); } catch (error) { console.error('Error executing command:', error); } } run() { this.DRPM.parse(); } } // Initialize and run the CLI export default new DRegistryPackageManager().run(); //# sourceMappingURL=drpm.js.map