create-web3cart-store 1.0.0 ā 1.0.2
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/cli.js +129 -87
- package/lib/database.js +52 -35
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -33,10 +33,20 @@ ${chalk.gray('https://web3cart.site')}
|
|
|
33
33
|
program
|
|
34
34
|
.name('create-web3cart-store')
|
|
35
35
|
.description('Create a Web3Cart store with one command')
|
|
36
|
-
.version('1.0.
|
|
36
|
+
.version('1.0.1')
|
|
37
37
|
.argument('[directory]', 'Directory to install Web3Cart', '.')
|
|
38
|
-
.option('--license <key>', 'License key
|
|
39
|
-
.option('--skip-db', 'Skip database setup
|
|
38
|
+
.option('--license <key>', 'License key')
|
|
39
|
+
.option('--skip-db', 'Skip database setup')
|
|
40
|
+
.option('--db-host <host>', 'Database host')
|
|
41
|
+
.option('--db-name <name>', 'Database name')
|
|
42
|
+
.option('--db-user <user>', 'Database user')
|
|
43
|
+
.option('--db-pass <pass>', 'Database password')
|
|
44
|
+
.option('--site-url <url>', 'Site URL')
|
|
45
|
+
.option('--site-name <name>', 'Site name')
|
|
46
|
+
.option('--admin-user <username>', 'Admin username')
|
|
47
|
+
.option('--admin-email <email>', 'Admin email')
|
|
48
|
+
.option('--admin-pass <password>', 'Admin password')
|
|
49
|
+
.option('--yes', 'Skip all prompts and use defaults/flags')
|
|
40
50
|
.action(async (directory, options) => {
|
|
41
51
|
console.log(banner);
|
|
42
52
|
console.log(chalk.yellow('š Web3Cart Installation Wizard\n'));
|
|
@@ -44,9 +54,12 @@ program
|
|
|
44
54
|
const targetDir = path.resolve(process.cwd(), directory);
|
|
45
55
|
|
|
46
56
|
// Check if directory exists and is not empty
|
|
47
|
-
if (fs.existsSync(targetDir) &&
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
if (fs.existsSync(targetDir) && directory !== '.') {
|
|
58
|
+
const files = fs.readdirSync(targetDir);
|
|
59
|
+
if (files.length > 0) {
|
|
60
|
+
console.log(chalk.red(`ā Directory "${directory}" already exists and is not empty.`));
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
50
63
|
}
|
|
51
64
|
|
|
52
65
|
try {
|
|
@@ -83,34 +96,43 @@ program
|
|
|
83
96
|
// Step 2: Database Configuration
|
|
84
97
|
let dbConfig = null;
|
|
85
98
|
if (!options.skipDb) {
|
|
86
|
-
|
|
99
|
+
if (options.dbHost && options.dbName && options.dbUser) {
|
|
100
|
+
dbConfig = {
|
|
101
|
+
host: options.dbHost,
|
|
102
|
+
name: options.dbName,
|
|
103
|
+
user: options.dbUser,
|
|
104
|
+
password: options.dbPass || ''
|
|
105
|
+
};
|
|
106
|
+
} else {
|
|
107
|
+
console.log(chalk.cyan('\nš¦ Database Configuration\n'));
|
|
87
108
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
109
|
+
dbConfig = await inquirer.prompt([
|
|
110
|
+
{
|
|
111
|
+
type: 'input',
|
|
112
|
+
name: 'host',
|
|
113
|
+
message: 'Database host:',
|
|
114
|
+
default: 'localhost'
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
type: 'input',
|
|
118
|
+
name: 'name',
|
|
119
|
+
message: 'Database name:',
|
|
120
|
+
default: 'web3cart_db'
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
type: 'input',
|
|
124
|
+
name: 'user',
|
|
125
|
+
message: 'Database user:',
|
|
126
|
+
default: 'root'
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
type: 'password',
|
|
130
|
+
name: 'password',
|
|
131
|
+
message: 'Database password:',
|
|
132
|
+
mask: '*'
|
|
133
|
+
}
|
|
134
|
+
]);
|
|
135
|
+
}
|
|
114
136
|
|
|
115
137
|
// Test Database Connection
|
|
116
138
|
const dbSpinner = ora('Testing database connection...').start();
|
|
@@ -119,71 +141,91 @@ program
|
|
|
119
141
|
if (!dbTest.success) {
|
|
120
142
|
dbSpinner.fail('Database connection failed');
|
|
121
143
|
console.log(chalk.red(`\nā ${dbTest.error}`));
|
|
122
|
-
|
|
123
|
-
|
|
144
|
+
if (!options.yes) {
|
|
145
|
+
console.log(chalk.yellow('You can run with --skip-db to configure database manually later.'));
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
dbSpinner.succeed(`Database connection successful! (Host: ${dbTest.host})`);
|
|
124
150
|
}
|
|
125
|
-
dbSpinner.succeed('Database connection successful!');
|
|
126
151
|
}
|
|
127
152
|
|
|
128
153
|
// Step 3: Site Configuration
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
154
|
+
let siteConfig = null;
|
|
155
|
+
if (options.siteUrl && options.siteName) {
|
|
156
|
+
siteConfig = {
|
|
157
|
+
url: options.siteUrl,
|
|
158
|
+
siteName: options.siteName
|
|
159
|
+
};
|
|
160
|
+
} else {
|
|
161
|
+
console.log(chalk.cyan('\nš Site Configuration\n'));
|
|
162
|
+
|
|
163
|
+
siteConfig = await inquirer.prompt([
|
|
164
|
+
{
|
|
165
|
+
type: 'input',
|
|
166
|
+
name: 'url',
|
|
167
|
+
message: 'Your site URL (where Web3Cart will be installed):',
|
|
168
|
+
default: 'https://example.com',
|
|
169
|
+
validate: (input) => {
|
|
170
|
+
if (!input.startsWith('http')) {
|
|
171
|
+
return 'URL must start with http:// or https://';
|
|
172
|
+
}
|
|
173
|
+
return true;
|
|
140
174
|
}
|
|
141
|
-
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
type: 'input',
|
|
178
|
+
name: 'siteName',
|
|
179
|
+
message: 'Site name:',
|
|
180
|
+
default: 'My Web3 Store'
|
|
142
181
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
type: 'input',
|
|
146
|
-
name: 'siteName',
|
|
147
|
-
message: 'Site name:',
|
|
148
|
-
default: 'My Web3 Store'
|
|
149
|
-
}
|
|
150
|
-
]);
|
|
182
|
+
]);
|
|
183
|
+
}
|
|
151
184
|
|
|
152
185
|
// Step 4: Admin Configuration
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
186
|
+
let adminConfig = null;
|
|
187
|
+
if (options.adminUser && options.adminEmail && options.adminPass) {
|
|
188
|
+
adminConfig = {
|
|
189
|
+
username: options.adminUser,
|
|
190
|
+
email: options.adminEmail,
|
|
191
|
+
password: options.adminPass
|
|
192
|
+
};
|
|
193
|
+
} else {
|
|
194
|
+
console.log(chalk.cyan('\nš¤ Admin Account\n'));
|
|
195
|
+
|
|
196
|
+
adminConfig = await inquirer.prompt([
|
|
197
|
+
{
|
|
198
|
+
type: 'input',
|
|
199
|
+
name: 'username',
|
|
200
|
+
message: 'Admin username:',
|
|
201
|
+
default: 'admin'
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
type: 'input',
|
|
205
|
+
name: 'email',
|
|
206
|
+
message: 'Admin email:',
|
|
207
|
+
validate: (input) => {
|
|
208
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
209
|
+
if (!emailRegex.test(input)) {
|
|
210
|
+
return 'Please enter a valid email address';
|
|
211
|
+
}
|
|
212
|
+
return true;
|
|
170
213
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
type: 'password',
|
|
217
|
+
name: 'password',
|
|
218
|
+
message: 'Admin password:',
|
|
219
|
+
mask: '*',
|
|
220
|
+
validate: (input) => {
|
|
221
|
+
if (input.length < 6) {
|
|
222
|
+
return 'Password must be at least 6 characters';
|
|
223
|
+
}
|
|
224
|
+
return true;
|
|
182
225
|
}
|
|
183
|
-
return true;
|
|
184
226
|
}
|
|
185
|
-
|
|
186
|
-
|
|
227
|
+
]);
|
|
228
|
+
}
|
|
187
229
|
|
|
188
230
|
// Step 5: Download Package
|
|
189
231
|
console.log(chalk.cyan('\nš„ Downloading Web3Cart...\n'));
|
package/lib/database.js
CHANGED
|
@@ -12,54 +12,71 @@ const path = require('path');
|
|
|
12
12
|
* Test database connection
|
|
13
13
|
*/
|
|
14
14
|
async function testConnection(config) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
host: config.host,
|
|
18
|
-
user: config.user,
|
|
19
|
-
password: config.password,
|
|
20
|
-
connectTimeout: 10000
|
|
21
|
-
});
|
|
15
|
+
const hostsToTry = config.host.toLowerCase() === 'localhost' ? ['127.0.0.1', 'localhost'] : [config.host];
|
|
16
|
+
let lastError = null;
|
|
22
17
|
|
|
23
|
-
|
|
18
|
+
for (const host of hostsToTry) {
|
|
24
19
|
try {
|
|
25
|
-
await
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
const connection = await mysql.createConnection({
|
|
21
|
+
host: host,
|
|
22
|
+
user: config.user,
|
|
23
|
+
password: config.password,
|
|
24
|
+
connectTimeout: 5000 // Shorter timeout for faster fallback
|
|
25
|
+
});
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
// Try to select the database
|
|
28
|
+
try {
|
|
29
|
+
await connection.query(`USE \`${config.name}\``);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
// Database doesn't exist, that's OK - we'll create it
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
await connection.end();
|
|
35
|
+
return { success: true, host: host };
|
|
36
|
+
} catch (error) {
|
|
37
|
+
lastError = error;
|
|
38
|
+
// Only continue to next host if it was a connection refusal
|
|
39
|
+
if (error.code !== 'ECONNREFUSED') break;
|
|
40
|
+
}
|
|
37
41
|
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
success: false,
|
|
45
|
+
error: `Connection failed: ${lastError.message} (${lastError.code})`
|
|
46
|
+
};
|
|
38
47
|
}
|
|
39
48
|
|
|
40
49
|
/**
|
|
41
50
|
* Create database if it doesn't exist
|
|
42
51
|
*/
|
|
43
52
|
async function createDatabase(config) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
host: config.host,
|
|
47
|
-
user: config.user,
|
|
48
|
-
password: config.password
|
|
49
|
-
});
|
|
53
|
+
const hostsToTry = config.host.toLowerCase() === 'localhost' ? ['127.0.0.1', 'localhost'] : [config.host];
|
|
54
|
+
let lastError = null;
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
for (const host of hostsToTry) {
|
|
57
|
+
try {
|
|
58
|
+
const connection = await mysql.createConnection({
|
|
59
|
+
host: host,
|
|
60
|
+
user: config.user,
|
|
61
|
+
password: config.password
|
|
62
|
+
});
|
|
54
63
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
64
|
+
await connection.query(
|
|
65
|
+
`CREATE DATABASE IF NOT EXISTS \`${config.name}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
await connection.end();
|
|
69
|
+
return { success: true };
|
|
70
|
+
} catch (error) {
|
|
71
|
+
lastError = error;
|
|
72
|
+
if (error.code !== 'ECONNREFUSED') break;
|
|
73
|
+
}
|
|
62
74
|
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
success: false,
|
|
78
|
+
error: `Database creation failed: ${lastError.message}`
|
|
79
|
+
};
|
|
63
80
|
}
|
|
64
81
|
|
|
65
82
|
/**
|