moontraze 1.0.1 → 1.0.3
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/moon.js +68 -0
- package/bin/moontraze.js +29 -14
- package/lib/auth.js +199 -16
- package/lib/config.js +10 -7
- package/lib/deploy.js +19 -17
- package/package.json +4 -3
package/bin/moon.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* moon <platform> <command>
|
|
4
|
+
* Example: moon moontraze login
|
|
5
|
+
* moon moontraze deploy --prod
|
|
6
|
+
*/
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const PLATFORMS = {
|
|
11
|
+
moontraze: {
|
|
12
|
+
label: 'Moontraze',
|
|
13
|
+
runner: path.join(__dirname, 'moontraze.js'),
|
|
14
|
+
},
|
|
15
|
+
// future:
|
|
16
|
+
// otherapp: { label: 'Other', runner: path.join(__dirname, 'other.js') },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function printRootHelp() {
|
|
20
|
+
console.log(`
|
|
21
|
+
${chalk.bold('moon')} — multi-platform CLI
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
moon <platform> <command>
|
|
25
|
+
|
|
26
|
+
Platforms:
|
|
27
|
+
moontraze Moontraze hosting (moontraze.com)
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
moon moontraze login
|
|
31
|
+
moon moontraze link my-site
|
|
32
|
+
moon moontraze deploy --prod
|
|
33
|
+
moon moontraze --prod
|
|
34
|
+
|
|
35
|
+
Same as:
|
|
36
|
+
npx moontraze login
|
|
37
|
+
npx moontraze deploy --prod
|
|
38
|
+
`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const args = process.argv.slice(2);
|
|
42
|
+
const platform = (args[0] || '').toLowerCase();
|
|
43
|
+
|
|
44
|
+
if (!platform || platform === '-h' || platform === '--help' || platform === 'help') {
|
|
45
|
+
printRootHelp();
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (platform === '-v' || platform === '--version') {
|
|
50
|
+
try {
|
|
51
|
+
console.log(require('../package.json').version);
|
|
52
|
+
} catch {
|
|
53
|
+
console.log('0.0.0');
|
|
54
|
+
}
|
|
55
|
+
process.exit(0);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const meta = PLATFORMS[platform];
|
|
59
|
+
if (!meta) {
|
|
60
|
+
console.error(chalk.red(`Unknown platform: "${platform}"`));
|
|
61
|
+
console.error(chalk.gray('Known: ' + Object.keys(PLATFORMS).join(', ')));
|
|
62
|
+
console.error(chalk.gray('Example: moon moontraze login'));
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Forward remaining args to platform CLI
|
|
67
|
+
process.argv = [process.argv[0], meta.runner, ...args.slice(1)];
|
|
68
|
+
require(meta.runner);
|
package/bin/moontraze.js
CHANGED
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
const { Command } = require('commander');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const { login } = require('../lib/auth');
|
|
5
|
-
const { getConfig,
|
|
5
|
+
const { getConfig, getProject, setProject } = require('../lib/config');
|
|
6
6
|
const { deploy } = require('../lib/deploy');
|
|
7
7
|
|
|
8
8
|
const program = new Command();
|
|
9
9
|
|
|
10
10
|
program
|
|
11
11
|
.name('moontraze')
|
|
12
|
-
.description('Deploy sites to Moontraze hosting')
|
|
13
|
-
.version('1.0.
|
|
12
|
+
.description('Deploy sites to Moontraze hosting (moontraze.com)')
|
|
13
|
+
.version('1.0.3');
|
|
14
14
|
|
|
15
|
-
// npx moontraze login
|
|
15
|
+
// moon moontraze login | npx moontraze login
|
|
16
16
|
program
|
|
17
17
|
.command('login')
|
|
18
|
-
.description('
|
|
19
|
-
.option('--token <jwt>', 'JWT token (
|
|
18
|
+
.description('Log in with email/password or token')
|
|
19
|
+
.option('--token <jwt>', 'JWT token (advanced, skip interactive login)')
|
|
20
20
|
.action(async (opts) => {
|
|
21
21
|
try {
|
|
22
22
|
await login(opts.token);
|
|
@@ -26,7 +26,7 @@ program
|
|
|
26
26
|
}
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
//
|
|
29
|
+
// moon moontraze link [name]
|
|
30
30
|
program
|
|
31
31
|
.command('link [name]')
|
|
32
32
|
.description('Link this folder to a hosting project name')
|
|
@@ -49,16 +49,17 @@ program
|
|
|
49
49
|
if (!projectName) process.exit(1);
|
|
50
50
|
projectName = projectName.toLowerCase().replace(/[^a-z0-9-]/g, '');
|
|
51
51
|
setProject({ projectName });
|
|
52
|
-
|
|
53
|
-
console.log(chalk.
|
|
52
|
+
const domain = getConfig().domain || 'moontraze.com';
|
|
53
|
+
console.log(chalk.green(`Linked → ${projectName}.${domain}`));
|
|
54
|
+
console.log(
|
|
55
|
+
chalk.gray('(saved .moontraze/project.json — same as .vercel)')
|
|
56
|
+
);
|
|
54
57
|
} catch (e) {
|
|
55
58
|
console.error(chalk.red(e.message));
|
|
56
59
|
process.exit(1);
|
|
57
60
|
}
|
|
58
61
|
});
|
|
59
62
|
|
|
60
|
-
// npx moontraze deploy --prod
|
|
61
|
-
// also: npx moontraze --prod (vercel style)
|
|
62
63
|
async function runDeploy(opts) {
|
|
63
64
|
try {
|
|
64
65
|
await deploy({
|
|
@@ -76,16 +77,15 @@ program
|
|
|
76
77
|
.description('Deploy current folder')
|
|
77
78
|
.option('--prod', 'Production redeploy')
|
|
78
79
|
.option('--production', 'Alias for --prod')
|
|
79
|
-
.option('-p, --project <name>', 'Project name (or use
|
|
80
|
+
.option('-p, --project <name>', 'Project name (or use link)')
|
|
80
81
|
.action(runDeploy);
|
|
81
82
|
|
|
82
|
-
//
|
|
83
|
+
// moon moontraze --prod
|
|
83
84
|
program
|
|
84
85
|
.option('--prod', 'Deploy to production')
|
|
85
86
|
.option('--production', 'Deploy to production')
|
|
86
87
|
.option('-p, --project <name>', 'Project name')
|
|
87
88
|
.action(async (opts, cmd) => {
|
|
88
|
-
// only if no subcommand
|
|
89
89
|
if (cmd.args?.length) return;
|
|
90
90
|
if (opts.prod || opts.production || opts.project) {
|
|
91
91
|
await runDeploy(opts);
|
|
@@ -94,6 +94,21 @@ program
|
|
|
94
94
|
}
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
+
program.addHelpText(
|
|
98
|
+
'after',
|
|
99
|
+
`
|
|
100
|
+
Examples:
|
|
101
|
+
npx moontraze login
|
|
102
|
+
npx moontraze link my-site
|
|
103
|
+
npx moontraze deploy --prod
|
|
104
|
+
|
|
105
|
+
moon moontraze login
|
|
106
|
+
moon moontraze link my-site
|
|
107
|
+
moon moontraze deploy --prod
|
|
108
|
+
moon moontraze --prod
|
|
109
|
+
`
|
|
110
|
+
);
|
|
111
|
+
|
|
97
112
|
program.parseAsync(process.argv).catch((e) => {
|
|
98
113
|
console.error(chalk.red(e.message));
|
|
99
114
|
process.exit(1);
|
package/lib/auth.js
CHANGED
|
@@ -1,38 +1,221 @@
|
|
|
1
1
|
const prompts = require('prompts');
|
|
2
2
|
const chalk = require('chalk');
|
|
3
|
+
const http = require('http');
|
|
4
|
+
const { URL } = require('url');
|
|
3
5
|
const { setConfig, getConfig } = require('./config');
|
|
4
6
|
|
|
5
7
|
async function login(tokenArg) {
|
|
6
|
-
|
|
7
|
-
if (
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
// Power user: --token still works (hidden)
|
|
9
|
+
if (tokenArg && String(tokenArg).trim()) {
|
|
10
|
+
return saveAndValidateToken(String(tokenArg).trim());
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
console.log('');
|
|
14
|
+
console.log(chalk.cyan('Moontraze Login'));
|
|
15
|
+
console.log('');
|
|
16
|
+
|
|
17
|
+
const { method } = await prompts({
|
|
18
|
+
type: 'select',
|
|
19
|
+
name: 'method',
|
|
20
|
+
message: 'How do you want to log in?',
|
|
21
|
+
choices: [
|
|
22
|
+
{ title: 'Email & Password', value: 'email' },
|
|
23
|
+
{ title: 'MoonID (scan QR with app)', value: 'moonid' },
|
|
24
|
+
],
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (!method) {
|
|
28
|
+
throw new Error('Login cancelled');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (method === 'email') {
|
|
32
|
+
await loginWithEmail();
|
|
33
|
+
} else {
|
|
34
|
+
await loginWithMoonID();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function loginWithEmail() {
|
|
39
|
+
const answers = await prompts([
|
|
40
|
+
{
|
|
41
|
+
type: 'text',
|
|
42
|
+
name: 'email',
|
|
43
|
+
message: 'Email',
|
|
44
|
+
validate: (v) =>
|
|
45
|
+
v && v.includes('@') ? true : 'Enter a valid email',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
12
48
|
type: 'password',
|
|
13
|
-
name: '
|
|
14
|
-
message: '
|
|
15
|
-
|
|
16
|
-
|
|
49
|
+
name: 'password',
|
|
50
|
+
message: 'Password',
|
|
51
|
+
validate: (v) => (v && v.length >= 1 ? true : 'Password required'),
|
|
52
|
+
},
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
if (!answers.email || !answers.password) {
|
|
56
|
+
throw new Error('Login cancelled');
|
|
17
57
|
}
|
|
18
|
-
|
|
19
|
-
|
|
58
|
+
|
|
59
|
+
const cfg = getConfig();
|
|
60
|
+
const fetch = require('node-fetch');
|
|
61
|
+
|
|
62
|
+
const res = await fetch(`${cfg.apiUrl}/api/platform/login`, {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers: { 'Content-Type': 'application/json' },
|
|
65
|
+
body: JSON.stringify({
|
|
66
|
+
email: answers.email.trim(),
|
|
67
|
+
password: answers.password,
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const data = await res.json().catch(() => ({}));
|
|
72
|
+
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
throw new Error(data.error || 'Invalid email or password');
|
|
20
75
|
}
|
|
21
|
-
token = String(token).trim();
|
|
22
76
|
|
|
77
|
+
if (!data.token) {
|
|
78
|
+
throw new Error('Login succeeded but no token returned');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
setConfig({ token: data.token });
|
|
82
|
+
console.log('');
|
|
83
|
+
console.log(chalk.green('✓ Logged in'));
|
|
84
|
+
if (data.user?.email) {
|
|
85
|
+
console.log(chalk.gray(` ${data.user.email}`));
|
|
86
|
+
}
|
|
87
|
+
console.log(chalk.gray(` Config: ~/.moontraze/config.json`));
|
|
88
|
+
console.log('');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function loginWithMoonID() {
|
|
92
|
+
const cfg = getConfig();
|
|
93
|
+
const state = Math.random().toString(36).substring(2, 12);
|
|
94
|
+
const port = 17321 + Math.floor(Math.random() * 100);
|
|
95
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
96
|
+
|
|
97
|
+
const appId = 'com.moonstorage.app';
|
|
98
|
+
const deepLink =
|
|
99
|
+
`moonid://auth` +
|
|
100
|
+
`?app_id=${encodeURIComponent(appId)}` +
|
|
101
|
+
`&action=login` +
|
|
102
|
+
`&redirect_uri=${encodeURIComponent(redirectUri)}` +
|
|
103
|
+
`&state=${encodeURIComponent(state)}`;
|
|
104
|
+
|
|
105
|
+
const qrImageUrl = `https://api.qrserver.com/v1/create-qr-code/?size=220x220&data=${encodeURIComponent(
|
|
106
|
+
deepLink
|
|
107
|
+
)}`;
|
|
108
|
+
|
|
109
|
+
console.log('');
|
|
110
|
+
console.log(chalk.cyan('MoonID Login'));
|
|
111
|
+
console.log(chalk.gray('1. Open MoonID app on your phone'));
|
|
112
|
+
console.log(chalk.gray('2. Scan the QR code (open link below in browser)'));
|
|
113
|
+
console.log(chalk.gray('3. Approve login'));
|
|
114
|
+
console.log('');
|
|
115
|
+
console.log(chalk.yellow('QR code image:'));
|
|
116
|
+
console.log(chalk.underline(qrImageUrl));
|
|
117
|
+
console.log('');
|
|
118
|
+
console.log(chalk.gray('Deep link (if needed):'));
|
|
119
|
+
console.log(chalk.gray(deepLink));
|
|
120
|
+
console.log('');
|
|
121
|
+
console.log(chalk.gray('Waiting for approval... (Ctrl+C to cancel)'));
|
|
122
|
+
console.log('');
|
|
123
|
+
|
|
124
|
+
// Local server — MoonID redirect yahan aayega
|
|
125
|
+
const token = await waitForMoonIDCallback({ port, state, timeoutMs: 120000 });
|
|
126
|
+
|
|
127
|
+
if (!token) {
|
|
128
|
+
throw new Error('MoonID login timed out or denied');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
await saveAndValidateToken(token);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function waitForMoonIDCallback({ port, state, timeoutMs }) {
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
const server = http.createServer((req, res) => {
|
|
137
|
+
try {
|
|
138
|
+
const u = new URL(req.url, `http://127.0.0.1:${port}`);
|
|
139
|
+
|
|
140
|
+
if (u.pathname !== '/callback') {
|
|
141
|
+
res.writeHead(404);
|
|
142
|
+
res.end('Not found');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const returnedState = u.searchParams.get('state');
|
|
147
|
+
const token =
|
|
148
|
+
u.searchParams.get('token') ||
|
|
149
|
+
u.searchParams.get('access_token') ||
|
|
150
|
+
u.searchParams.get('jwt');
|
|
151
|
+
const error = u.searchParams.get('error');
|
|
152
|
+
|
|
153
|
+
if (error) {
|
|
154
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
155
|
+
res.end(
|
|
156
|
+
'<html><body style="font-family:sans-serif;text-align:center;padding:40px"><h2>Login denied</h2><p>You can close this tab.</p></body></html>'
|
|
157
|
+
);
|
|
158
|
+
server.close();
|
|
159
|
+
resolve(null);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (returnedState && returnedState !== state) {
|
|
164
|
+
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
165
|
+
res.end('Invalid state');
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!token) {
|
|
170
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
171
|
+
res.end(
|
|
172
|
+
'<html><body style="font-family:sans-serif;text-align:center;padding:40px"><h2>No token received</h2><p>Close this tab and try again.</p></body></html>'
|
|
173
|
+
);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
178
|
+
res.end(
|
|
179
|
+
'<html><body style="font-family:sans-serif;text-align:center;padding:40px"><h2>✓ Login successful</h2><p>You can close this tab and return to the terminal.</p></body></html>'
|
|
180
|
+
);
|
|
181
|
+
server.close();
|
|
182
|
+
resolve(token);
|
|
183
|
+
} catch (e) {
|
|
184
|
+
res.writeHead(500);
|
|
185
|
+
res.end('Error');
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
server.listen(port, '127.0.0.1');
|
|
190
|
+
|
|
191
|
+
const timer = setTimeout(() => {
|
|
192
|
+
try {
|
|
193
|
+
server.close();
|
|
194
|
+
} catch (_) {}
|
|
195
|
+
resolve(null);
|
|
196
|
+
}, timeoutMs);
|
|
197
|
+
|
|
198
|
+
server.on('close', () => clearTimeout(timer));
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async function saveAndValidateToken(token) {
|
|
23
203
|
const cfg = getConfig();
|
|
24
|
-
// optional: validate token
|
|
25
204
|
const fetch = require('node-fetch');
|
|
205
|
+
|
|
26
206
|
const res = await fetch(`${cfg.apiUrl}/api/hosting/quota`, {
|
|
27
207
|
headers: { Authorization: `Bearer ${token}` },
|
|
28
208
|
});
|
|
209
|
+
|
|
29
210
|
if (res.status === 401) {
|
|
30
211
|
throw new Error('Invalid or expired token');
|
|
31
212
|
}
|
|
32
|
-
|
|
213
|
+
|
|
33
214
|
setConfig({ token });
|
|
215
|
+
console.log('');
|
|
34
216
|
console.log(chalk.green('✓ Logged in'));
|
|
35
|
-
console.log(chalk.gray(`Config: ~/.moontraze/config.json`));
|
|
217
|
+
console.log(chalk.gray(` Config: ~/.moontraze/config.json`));
|
|
218
|
+
console.log('');
|
|
36
219
|
}
|
|
37
220
|
|
|
38
221
|
module.exports = { login };
|
package/lib/config.js
CHANGED
|
@@ -11,17 +11,21 @@ function ensureDir(d) {
|
|
|
11
11
|
if (!fs.existsSync(d)) fs.mkdirSync(d, { recursive: true });
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
const DEFAULTS = {
|
|
15
|
+
token: null,
|
|
16
|
+
apiUrl: process.env.MOONTRAZE_API || 'https://api.moontraze.com',
|
|
17
|
+
domain: process.env.MOONTRAZE_DOMAIN || 'moontraze.com',
|
|
18
|
+
};
|
|
19
|
+
|
|
14
20
|
function getConfig() {
|
|
15
21
|
try {
|
|
16
22
|
if (fs.existsSync(GLOBAL_FILE)) {
|
|
17
|
-
|
|
23
|
+
const saved = JSON.parse(fs.readFileSync(GLOBAL_FILE, 'utf8'));
|
|
24
|
+
// merge defaults so old frelanceo.com cache auto-upgrade on missing keys
|
|
25
|
+
return { ...DEFAULTS, ...saved };
|
|
18
26
|
}
|
|
19
27
|
} catch (_) {}
|
|
20
|
-
return {
|
|
21
|
-
token: null,
|
|
22
|
-
apiUrl: process.env.MOONTRAZE_API || 'https://api.frelanceo.com',
|
|
23
|
-
domain: process.env.MOONTRAZE_DOMAIN || 'frelanceo.com',
|
|
24
|
-
};
|
|
28
|
+
return { ...DEFAULTS };
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
function setConfig(partial) {
|
|
@@ -43,7 +47,6 @@ function getProject() {
|
|
|
43
47
|
function setProject(data) {
|
|
44
48
|
ensureDir(LOCAL_DIR);
|
|
45
49
|
fs.writeFileSync(LOCAL_FILE, JSON.stringify(data, null, 2));
|
|
46
|
-
// ignore file so users don't commit token (project name only is ok)
|
|
47
50
|
const ignore = path.join(process.cwd(), '.gitignore');
|
|
48
51
|
try {
|
|
49
52
|
let g = fs.existsSync(ignore) ? fs.readFileSync(ignore, 'utf8') : '';
|
package/lib/deploy.js
CHANGED
|
@@ -10,26 +10,29 @@ const { zipCwd } = require('./zip');
|
|
|
10
10
|
async function deploy({ prod = true, projectName } = {}) {
|
|
11
11
|
const cfg = getConfig();
|
|
12
12
|
if (!cfg.token) {
|
|
13
|
-
throw new Error(
|
|
13
|
+
throw new Error(
|
|
14
|
+
'Not logged in. Run: moon moontraze login (or: npx moontraze login)'
|
|
15
|
+
);
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
const linked = getProject();
|
|
17
19
|
const name = (projectName || linked?.projectName || '')
|
|
18
20
|
.toLowerCase()
|
|
19
21
|
.replace(/[^a-z0-9-]/g, '');
|
|
20
|
-
|
|
21
22
|
if (!name || name.length < 3) {
|
|
22
|
-
throw new Error(
|
|
23
|
+
throw new Error(
|
|
24
|
+
'No project linked. Run: moon moontraze link my-site (or: npx moontraze link my-site)'
|
|
25
|
+
);
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
const domain = cfg.domain || '
|
|
26
|
-
const api = cfg.apiUrl || 'https://api.
|
|
28
|
+
const domain = cfg.domain || 'moontraze.com';
|
|
29
|
+
const api = cfg.apiUrl || 'https://api.moontraze.com';
|
|
27
30
|
|
|
28
31
|
console.log('');
|
|
29
32
|
console.log(chalk.cyan('Moontraze'));
|
|
30
|
-
console.log(`
|
|
31
|
-
console.log(`
|
|
32
|
-
console.log(`
|
|
33
|
+
console.log(` Inspect ${api}`);
|
|
34
|
+
console.log(` Project ${name}`);
|
|
35
|
+
console.log(` Target https://${name}.${domain}`);
|
|
33
36
|
console.log('');
|
|
34
37
|
|
|
35
38
|
const spinner = ora('Packaging...').start();
|
|
@@ -39,9 +42,8 @@ async function deploy({ prod = true, projectName } = {}) {
|
|
|
39
42
|
try {
|
|
40
43
|
zipPath = await zipCwd();
|
|
41
44
|
const mb = (fs.statSync(zipPath).size / 1024 / 1024).toFixed(2);
|
|
42
|
-
spinner.text = `Checking project...`;
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
spinner.text = 'Checking project...';
|
|
45
47
|
let alreadyExists = false;
|
|
46
48
|
try {
|
|
47
49
|
const statusRes = await fetch(`${api}/api/hosting/status/${name}`, {
|
|
@@ -52,7 +54,7 @@ async function deploy({ prod = true, projectName } = {}) {
|
|
|
52
54
|
alreadyExists = !!statusData.exists;
|
|
53
55
|
}
|
|
54
56
|
} catch (_) {
|
|
55
|
-
//
|
|
57
|
+
// assume new
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
spinner.text = `Uploading (${mb} MB)...`;
|
|
@@ -64,13 +66,14 @@ async function deploy({ prod = true, projectName } = {}) {
|
|
|
64
66
|
contentType: 'application/zip',
|
|
65
67
|
});
|
|
66
68
|
|
|
67
|
-
//
|
|
69
|
+
// existing → redeploy; new → deploy
|
|
68
70
|
const endpoint = alreadyExists
|
|
69
71
|
? `${api}/api/hosting/redeploy`
|
|
70
72
|
: `${api}/api/hosting/deploy`;
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
if (alreadyExists) {
|
|
75
|
+
form.append('redeploy', 'true');
|
|
76
|
+
} else {
|
|
74
77
|
form.append('redeploy', 'false');
|
|
75
78
|
}
|
|
76
79
|
|
|
@@ -100,11 +103,10 @@ async function deploy({ prod = true, projectName } = {}) {
|
|
|
100
103
|
|
|
101
104
|
spinner.succeed(`Ready in ${sec}s`);
|
|
102
105
|
const url = data.url || `https://${name}.${domain}`;
|
|
103
|
-
|
|
104
106
|
console.log('');
|
|
105
|
-
console.log(chalk.green(`
|
|
107
|
+
console.log(chalk.green(` Production ${url}`));
|
|
106
108
|
if (data.deployment?.version) {
|
|
107
|
-
console.log(chalk.gray(`
|
|
109
|
+
console.log(chalk.gray(` Version ${data.deployment.version}`));
|
|
108
110
|
}
|
|
109
111
|
console.log(
|
|
110
112
|
chalk.green(alreadyExists ? '✓ Redeployed' : '✓ Deployed')
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moontraze",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Deploy to Moontraze hosting — like vercel CLI",
|
|
5
5
|
"bin": {
|
|
6
|
-
"moontraze": "./bin/moontraze.js"
|
|
6
|
+
"moontraze": "./bin/moontraze.js",
|
|
7
|
+
"moon": "./bin/moon.js"
|
|
7
8
|
},
|
|
8
9
|
"files": ["bin", "lib"],
|
|
9
10
|
"engines": { "node": ">=18" },
|
|
@@ -16,6 +17,6 @@
|
|
|
16
17
|
"chalk": "^4.1.2",
|
|
17
18
|
"prompts": "^2.4.2"
|
|
18
19
|
},
|
|
19
|
-
"keywords": ["moontraze", "deploy", "hosting"],
|
|
20
|
+
"keywords": ["moontraze", "deploy", "hosting", "moon"],
|
|
20
21
|
"license": "MIT"
|
|
21
22
|
}
|