@bootmap/wpep-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/wpep.js ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import chalk from 'chalk';
4
+ import initCommand from '../src/commands/init.js';
5
+ import deployCommand from '../src/commands/deploy.js';
6
+
7
+ const program = new Command();
8
+
9
+ program
10
+ .name('wpep')
11
+ .description('Deploy Next.js static exports to WordPress via WP Elementor Publisher')
12
+ .version('1.0.0');
13
+
14
+ program
15
+ .command('init')
16
+ .description('Initialize WPEP configuration')
17
+ .action(async () => {
18
+ try {
19
+ await initCommand();
20
+ } catch (err) {
21
+ console.error(chalk.red(`Error: ${err.message}`));
22
+ process.exit(1);
23
+ }
24
+ });
25
+
26
+ program
27
+ .command('deploy')
28
+ .description('Build and deploy your Next.js project to WordPress')
29
+ .option('-d, --dir <dir>', 'The export directory to deploy', 'out')
30
+ .option('-u, --url <url>', 'WordPress site URL (overrides .wpeprc)')
31
+ .option('-k, --key <key>', 'WPEP API Key (overrides .wpeprc)')
32
+ .option('--no-build', 'Skip running the build step')
33
+ .action(async (options) => {
34
+ try {
35
+ await deployCommand(options);
36
+ } catch (err) {
37
+ console.error(chalk.red(`\nDeployment failed: ${err.message}`));
38
+ process.exit(1);
39
+ }
40
+ });
41
+
42
+ program.parse(process.argv);
43
+
44
+ if (!process.argv.slice(2).length) {
45
+ program.outputHelp();
46
+ }
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@bootmap/wpep-cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool for deploying Next.js static exports to WordPress via WP Elementor Publisher",
5
+ "main": "bin/wpep.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "wpep": "bin/wpep.js",
9
+ "wpep-cli": "bin/wpep.js"
10
+ },
11
+ "scripts": {
12
+ "test": "echo \"Error: no test specified\" && exit 1"
13
+ },
14
+ "keywords": [
15
+ "wordpress",
16
+ "nextjs",
17
+ "deploy",
18
+ "wpep"
19
+ ],
20
+ "author": "",
21
+ "license": "ISC",
22
+ "dependencies": {
23
+ "chalk": "^5.3.0",
24
+ "commander": "^11.1.0",
25
+ "inquirer": "^9.2.12",
26
+ "ora": "^7.0.1"
27
+ }
28
+ }
@@ -0,0 +1,141 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import crypto from 'crypto';
4
+ import chalk from 'chalk';
5
+ import ora from 'ora';
6
+ import { execSync } from 'child_process';
7
+
8
+ function getFiles(dir, files = []) {
9
+ if (!fs.existsSync(dir)) return files;
10
+ const fileList = fs.readdirSync(dir);
11
+ for (const file of fileList) {
12
+ const name = `${dir}/${file}`;
13
+ if (fs.statSync(name).isDirectory()) {
14
+ getFiles(name, files);
15
+ } else {
16
+ files.push(name);
17
+ }
18
+ }
19
+ return files;
20
+ }
21
+
22
+ export default async function deployCommand(options) {
23
+ let url = options.url;
24
+ let key = options.key;
25
+
26
+ if (!url || !key) {
27
+ const rcPath = path.join(process.cwd(), '.wpeprc.json');
28
+ if (fs.existsSync(rcPath)) {
29
+ try {
30
+ const config = JSON.parse(fs.readFileSync(rcPath, 'utf8'));
31
+ url = url || config.url;
32
+ key = key || config.key;
33
+ } catch (e) {
34
+ throw new Error('Could not read .wpeprc.json. Run "wpep init" first.');
35
+ }
36
+ }
37
+ }
38
+
39
+ if (!url || !key) {
40
+ throw new Error('Missing WordPress URL or API Key. Run "wpep init" or provide --url and --key arguments.');
41
+ }
42
+
43
+ // Remove trailing slash
44
+ url = url.replace(/\/$/, '');
45
+
46
+ console.log(chalk.blue.bold(`\nDeploying to ${url} ...\n`));
47
+
48
+ if (options.build !== false) {
49
+ console.log(chalk.gray('Running npm run build...'));
50
+ try {
51
+ execSync('npm run build', { stdio: 'inherit' });
52
+ } catch (e) {
53
+ throw new Error('Build failed. See output above.');
54
+ }
55
+ }
56
+
57
+ const outDir = path.join(process.cwd(), options.dir);
58
+ if (!fs.existsSync(outDir)) {
59
+ throw new Error(`Export directory "${options.dir}" does not exist. Did the build succeed?`);
60
+ }
61
+
62
+ const spinner = ora('Preparing files for upload...').start();
63
+ const allFiles = getFiles(outDir);
64
+ const filesList = {};
65
+
66
+ for (const file of allFiles) {
67
+ const relativePath = path.relative(outDir, file);
68
+ const data = fs.readFileSync(file);
69
+ filesList[relativePath] = crypto.createHash('sha256').update(data).digest('hex');
70
+ }
71
+
72
+ spinner.text = `Creating deployment session for ${allFiles.length} files...`;
73
+
74
+ let deployId;
75
+ try {
76
+ const createRes = await fetch(`${url}/wp-json/wpep/v1/deployments/create`, {
77
+ method: 'POST',
78
+ headers: { 'Content-Type': 'application/json', 'x-wpep-api-key': key },
79
+ body: JSON.stringify({ files: filesList })
80
+ });
81
+
82
+ if (!createRes.ok) {
83
+ throw new Error(`Server returned ${createRes.status} ${createRes.statusText}`);
84
+ }
85
+
86
+ const createData = await createRes.json();
87
+ if (!createData.deployment_id) {
88
+ throw new Error(`Invalid response from server: ${JSON.stringify(createData)}`);
89
+ }
90
+ deployId = createData.deployment_id;
91
+ } catch (e) {
92
+ spinner.fail('Failed to create deployment session.');
93
+ throw e;
94
+ }
95
+
96
+ spinner.succeed(`Created deployment session: ${chalk.bold(deployId)}`);
97
+
98
+ console.log(chalk.gray('\nUploading files...'));
99
+ let uploaded = 0;
100
+ for (const file of allFiles) {
101
+ const relativePath = path.relative(outDir, file);
102
+ const data = fs.readFileSync(file);
103
+ const base64Data = data.toString('base64');
104
+ const hash = filesList[relativePath];
105
+
106
+ const uploadSpinner = ora(`Uploading ${relativePath}...`).start();
107
+
108
+ try {
109
+ const uploadRes = await fetch(`${url}/wp-json/wpep/v1/deployments/${deployId}/upload`, {
110
+ method: 'POST',
111
+ headers: { 'Content-Type': 'application/json', 'x-wpep-api-key': key },
112
+ body: JSON.stringify({ path: relativePath, data: base64Data, hash })
113
+ });
114
+ if (!uploadRes.ok) {
115
+ throw new Error(`Failed to upload ${relativePath}: ${uploadRes.statusText}`);
116
+ }
117
+ uploadSpinner.succeed(`Uploaded ${relativePath}`);
118
+ uploaded++;
119
+ } catch (e) {
120
+ uploadSpinner.fail(`Failed to upload ${relativePath}`);
121
+ throw e;
122
+ }
123
+ }
124
+
125
+ const activateSpinner = ora('Activating deployment...').start();
126
+ try {
127
+ const activateRes = await fetch(`${url}/wp-json/wpep/v1/deployments/${deployId}/activate`, {
128
+ method: 'POST',
129
+ headers: { 'Content-Type': 'application/json', 'x-wpep-api-key': key }
130
+ });
131
+ if (!activateRes.ok) {
132
+ throw new Error(`Activation failed: ${activateRes.statusText}`);
133
+ }
134
+ activateSpinner.succeed('Deployment activated successfully!');
135
+ } catch (e) {
136
+ activateSpinner.fail('Failed to activate deployment.');
137
+ throw e;
138
+ }
139
+
140
+ console.log(chalk.green.bold(`\n🎉 Success! Your site is live at ${url}\n`));
141
+ }
@@ -0,0 +1,59 @@
1
+ import inquirer from 'inquirer';
2
+ import chalk from 'chalk';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+
6
+ export default async function initCommand() {
7
+ console.log(chalk.blue.bold('\nWelcome to WP Elementor Publisher (WPEP) CLI\n'));
8
+
9
+ const rcPath = path.join(process.cwd(), '.wpeprc.json');
10
+
11
+ let existingConfig = {};
12
+ if (fs.existsSync(rcPath)) {
13
+ try {
14
+ existingConfig = JSON.parse(fs.readFileSync(rcPath, 'utf8'));
15
+ } catch (e) {
16
+ // ignore
17
+ }
18
+ }
19
+
20
+ const answers = await inquirer.prompt([
21
+ {
22
+ type: 'input',
23
+ name: 'url',
24
+ message: 'What is your WordPress site URL?',
25
+ default: existingConfig.url || 'https://yoursite.com',
26
+ validate: (input) => {
27
+ if (!input.startsWith('http://') && !input.startsWith('https://')) {
28
+ return 'URL must start with http:// or https://';
29
+ }
30
+ return true;
31
+ }
32
+ },
33
+ {
34
+ type: 'password',
35
+ name: 'key',
36
+ message: 'Enter your WPEP API Key:',
37
+ default: existingConfig.key || '',
38
+ validate: (input) => {
39
+ if (input.trim() === '') {
40
+ return 'API Key is required';
41
+ }
42
+ return true;
43
+ }
44
+ }
45
+ ]);
46
+
47
+ // Clean URL (remove trailing slash)
48
+ const cleanUrl = answers.url.trim().replace(/\/$/, '');
49
+
50
+ const config = {
51
+ url: cleanUrl,
52
+ key: answers.key.trim()
53
+ };
54
+
55
+ fs.writeFileSync(rcPath, JSON.stringify(config, null, 2));
56
+
57
+ console.log(chalk.green(`\nSuccess! Saved configuration to ${chalk.bold('.wpeprc.json')}`));
58
+ console.log(`You can now run ${chalk.cyan('wpep deploy')} to deploy your site.\n`);
59
+ }