moontraze 1.0.7 → 1.0.9
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/moontraze.js +44 -5
- package/lib/auth.js +24 -93
- package/lib/selfUpdate.js +152 -0
- package/package.json +2 -3
package/bin/moontraze.js
CHANGED
|
@@ -4,6 +4,7 @@ const chalk = require('chalk');
|
|
|
4
4
|
const { login } = require('../lib/auth');
|
|
5
5
|
const { getConfig, setConfig, getProject, setProject } = require('../lib/config');
|
|
6
6
|
const { deploy } = require('../lib/deploy');
|
|
7
|
+
const { selfUpdate } = require('../lib/selfUpdate');
|
|
7
8
|
|
|
8
9
|
const program = new Command();
|
|
9
10
|
|
|
@@ -15,9 +16,9 @@ const domain = process.env.MOON_DOMAIN || getConfig().domain || 'moontraze.com';
|
|
|
15
16
|
program
|
|
16
17
|
.name(platformName)
|
|
17
18
|
.description(`Deploy sites using ${platformName}`)
|
|
18
|
-
.version('1.0.
|
|
19
|
+
.version('1.0.6');
|
|
19
20
|
|
|
20
|
-
// login
|
|
21
|
+
// ---------- login ----------
|
|
21
22
|
program
|
|
22
23
|
.command('login')
|
|
23
24
|
.description('Log in with email/password or token')
|
|
@@ -25,14 +26,14 @@ program
|
|
|
25
26
|
.action(async (opts) => {
|
|
26
27
|
try {
|
|
27
28
|
await login(opts.token, { apiUrl });
|
|
28
|
-
|
|
29
|
+
// auth.js already prints ✓ Logged in — avoid double line if you want
|
|
29
30
|
} catch (e) {
|
|
30
31
|
console.error(chalk.red('Login failed:'), e.message);
|
|
31
32
|
process.exit(1);
|
|
32
33
|
}
|
|
33
34
|
});
|
|
34
35
|
|
|
35
|
-
// link
|
|
36
|
+
// ---------- link ----------
|
|
36
37
|
program
|
|
37
38
|
.command('link [name]')
|
|
38
39
|
.description('Link this folder to a hosting project name')
|
|
@@ -63,7 +64,40 @@ program
|
|
|
63
64
|
}
|
|
64
65
|
});
|
|
65
66
|
|
|
66
|
-
//
|
|
67
|
+
// ---------- list ----------
|
|
68
|
+
program
|
|
69
|
+
.command('list')
|
|
70
|
+
.description('Show login + linked project status')
|
|
71
|
+
.action(() => {
|
|
72
|
+
const cfg = getConfig();
|
|
73
|
+
const proj = getProject();
|
|
74
|
+
console.log('');
|
|
75
|
+
console.log(chalk.bold('Moontraze'));
|
|
76
|
+
console.log(` API: ${cfg.apiUrl || apiUrl}`);
|
|
77
|
+
console.log(` Domain: ${cfg.domain || domain}`);
|
|
78
|
+
console.log(` Logged in: ${cfg.token ? 'yes' : 'no'}`);
|
|
79
|
+
console.log(
|
|
80
|
+
` Linked project: ${
|
|
81
|
+
proj?.projectName || '(none — run: moon moontraze link <name>)'
|
|
82
|
+
}`
|
|
83
|
+
);
|
|
84
|
+
console.log('');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// ---------- update (own server tarball — no npm registry for code) ----------
|
|
88
|
+
program
|
|
89
|
+
.command('update')
|
|
90
|
+
.description('Download latest Moontraze CLI from api.moontraze.com')
|
|
91
|
+
.action(async () => {
|
|
92
|
+
try {
|
|
93
|
+
await selfUpdate();
|
|
94
|
+
} catch (e) {
|
|
95
|
+
console.error(chalk.red('Update failed:'), e.message);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// ---------- deploy ----------
|
|
67
101
|
async function runDeploy(opts) {
|
|
68
102
|
try {
|
|
69
103
|
await deploy({
|
|
@@ -105,8 +139,13 @@ program.addHelpText(
|
|
|
105
139
|
Examples:
|
|
106
140
|
moon ${platformName} login
|
|
107
141
|
moon ${platformName} link my-site
|
|
142
|
+
moon ${platformName} list
|
|
108
143
|
moon ${platformName} deploy --prod
|
|
144
|
+
moon ${platformName} update
|
|
109
145
|
moon ${platformName} --prod
|
|
146
|
+
|
|
147
|
+
npx moontraze login
|
|
148
|
+
npx moontraze deploy --prod
|
|
110
149
|
`
|
|
111
150
|
);
|
|
112
151
|
|
package/lib/auth.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
const prompts = require('prompts');
|
|
2
2
|
const chalk = require('chalk');
|
|
3
|
-
const http = require('http');
|
|
4
|
-
const { URL } = require('url');
|
|
5
3
|
const { getConfig, setConfig } = require('./config');
|
|
6
4
|
|
|
7
5
|
async function login(tokenArg, options = {}) {
|
|
@@ -10,10 +8,8 @@ async function login(tokenArg, options = {}) {
|
|
|
10
8
|
process.env.MOON_API ||
|
|
11
9
|
getConfig().apiUrl ||
|
|
12
10
|
'https://api.moontraze.com';
|
|
13
|
-
|
|
14
11
|
const label = process.env.MOON_LABEL || process.env.MOON_PLATFORM || 'Moontraze';
|
|
15
12
|
|
|
16
|
-
// --token (hidden power user)
|
|
17
13
|
if (tokenArg && String(tokenArg).trim()) {
|
|
18
14
|
return saveAndValidateToken(String(tokenArg).trim(), { apiUrl, label });
|
|
19
15
|
}
|
|
@@ -72,16 +68,14 @@ async function loginWithEmail({ apiUrl, label }) {
|
|
|
72
68
|
});
|
|
73
69
|
|
|
74
70
|
const data = await res.json().catch(() => ({}));
|
|
75
|
-
|
|
76
71
|
if (!res.ok) throw new Error(data.error || 'Invalid email or password');
|
|
77
72
|
if (!data.token) throw new Error('Login succeeded but no token returned');
|
|
78
73
|
|
|
79
74
|
setConfig({ token: data.token, apiUrl });
|
|
80
|
-
|
|
81
75
|
console.log('');
|
|
82
76
|
console.log(chalk.green('✓ Logged in'));
|
|
83
|
-
if (data.user?.email) console.log(chalk.gray(`
|
|
84
|
-
console.log(chalk.gray(`
|
|
77
|
+
if (data.user?.email) console.log(chalk.gray(` ${data.user.email}`));
|
|
78
|
+
console.log(chalk.gray(` Config: ~/.moontraze/config.json`));
|
|
85
79
|
console.log('');
|
|
86
80
|
}
|
|
87
81
|
|
|
@@ -90,22 +84,21 @@ async function loginWithMoonID({ apiUrl, label }) {
|
|
|
90
84
|
const nonce = Math.random().toString(36).substring(2, 12);
|
|
91
85
|
const state = `${nonce}.login`;
|
|
92
86
|
|
|
93
|
-
|
|
87
|
+
// ★ Same flow as website (working)
|
|
88
|
+
const startRes = await fetch(`${apiUrl}/api/platform/moonid/web-start`, {
|
|
94
89
|
method: 'POST',
|
|
95
90
|
headers: { 'Content-Type': 'application/json' },
|
|
96
|
-
body: JSON.stringify({ state }),
|
|
91
|
+
body: JSON.stringify({ state, action: 'login' }),
|
|
97
92
|
});
|
|
98
93
|
const startData = await startRes.json().catch(() => ({}));
|
|
99
94
|
if (!startRes.ok) {
|
|
100
|
-
throw new Error(startData.error || 'Could not start MoonID
|
|
95
|
+
throw new Error(startData.error || 'Could not start MoonID session');
|
|
101
96
|
}
|
|
102
97
|
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
// App POST yahan karegi (web jaisa)
|
|
108
|
-
const notifyUrl = `${apiUrl}/api/platform/moonid/cli-complete`;
|
|
98
|
+
const notifyUrl = `${apiUrl}/api/platform/moonid/web-complete`;
|
|
99
|
+
const redirectUri = `${apiUrl}/api/platform/moonid/done?state=${encodeURIComponent(
|
|
100
|
+
state
|
|
101
|
+
)}`;
|
|
109
102
|
|
|
110
103
|
const appId = 'com.moonstorage.app';
|
|
111
104
|
const deepLink =
|
|
@@ -133,13 +126,13 @@ async function loginWithMoonID({ apiUrl, label }) {
|
|
|
133
126
|
console.log(chalk.gray('Waiting for approval... (Ctrl+C to cancel)'));
|
|
134
127
|
console.log('');
|
|
135
128
|
|
|
136
|
-
const token = await
|
|
129
|
+
const token = await pollWebStatus({ apiUrl, state, timeoutMs: 180000 });
|
|
137
130
|
if (!token) throw new Error('MoonID login timed out or denied');
|
|
138
131
|
|
|
139
132
|
await saveAndValidateToken(token, { apiUrl, label });
|
|
140
133
|
}
|
|
141
134
|
|
|
142
|
-
async function
|
|
135
|
+
async function pollWebStatus({ apiUrl, state, timeoutMs }) {
|
|
143
136
|
const fetch = require('node-fetch');
|
|
144
137
|
const start = Date.now();
|
|
145
138
|
const interval = 2000;
|
|
@@ -148,19 +141,25 @@ async function pollCliStatus({ apiUrl, state, timeoutMs }) {
|
|
|
148
141
|
await new Promise((r) => setTimeout(r, interval));
|
|
149
142
|
try {
|
|
150
143
|
const res = await fetch(
|
|
151
|
-
`${apiUrl}/api/platform/moonid/
|
|
144
|
+
`${apiUrl}/api/platform/moonid/status?state=${encodeURIComponent(state)}`
|
|
152
145
|
);
|
|
153
146
|
const data = await res.json().catch(() => ({}));
|
|
154
147
|
|
|
155
|
-
|
|
148
|
+
// web endpoint returns status: "success"
|
|
149
|
+
if (
|
|
150
|
+
(data.status === 'success' || data.status === 'done') &&
|
|
151
|
+
data.token
|
|
152
|
+
) {
|
|
156
153
|
return data.token;
|
|
157
154
|
}
|
|
158
|
-
if (data.status === '
|
|
155
|
+
if (data.status === 'error' || data.status === 'denied') {
|
|
159
156
|
throw new Error(data.error || 'MoonID login denied');
|
|
160
157
|
}
|
|
161
|
-
// pending / unknown → keep waiting
|
|
162
158
|
} catch (e) {
|
|
163
|
-
if (
|
|
159
|
+
if (
|
|
160
|
+
e.message &&
|
|
161
|
+
/denied|failed|not found|mismatch|expired|signup/i.test(e.message)
|
|
162
|
+
) {
|
|
164
163
|
throw e;
|
|
165
164
|
}
|
|
166
165
|
}
|
|
@@ -168,86 +167,18 @@ async function pollCliStatus({ apiUrl, state, timeoutMs }) {
|
|
|
168
167
|
return null;
|
|
169
168
|
}
|
|
170
169
|
|
|
171
|
-
function waitForMoonIDCallback({ port, state, timeoutMs }) {
|
|
172
|
-
return new Promise((resolve) => {
|
|
173
|
-
const server = http.createServer((req, res) => {
|
|
174
|
-
try {
|
|
175
|
-
const u = new URL(req.url, `http://127.0.0.1:${port}`);
|
|
176
|
-
if (u.pathname !== '/callback') {
|
|
177
|
-
res.writeHead(404);
|
|
178
|
-
res.end('Not found');
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const returnedState = u.searchParams.get('state');
|
|
183
|
-
const token =
|
|
184
|
-
u.searchParams.get('token') ||
|
|
185
|
-
u.searchParams.get('access_token') ||
|
|
186
|
-
u.searchParams.get('jwt');
|
|
187
|
-
const error = u.searchParams.get('error');
|
|
188
|
-
|
|
189
|
-
if (error) {
|
|
190
|
-
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
191
|
-
res.end(
|
|
192
|
-
'<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>'
|
|
193
|
-
);
|
|
194
|
-
server.close();
|
|
195
|
-
resolve(null);
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (returnedState && returnedState !== state) {
|
|
200
|
-
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
201
|
-
res.end('Invalid state');
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (!token) {
|
|
206
|
-
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
207
|
-
res.end(
|
|
208
|
-
'<html><body style="font-family:sans-serif;text-align:center;padding:40px"><h2>No token received</h2></body></html>'
|
|
209
|
-
);
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
214
|
-
res.end(
|
|
215
|
-
'<html><body style="font-family:sans-serif;text-align:center;padding:40px"><h2>✓ Login successful</h2><p>You can close this tab.</p></body></html>'
|
|
216
|
-
);
|
|
217
|
-
server.close();
|
|
218
|
-
resolve(token);
|
|
219
|
-
} catch {
|
|
220
|
-
res.writeHead(500);
|
|
221
|
-
res.end('Error');
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
server.listen(port, '127.0.0.1');
|
|
226
|
-
const timer = setTimeout(() => {
|
|
227
|
-
try {
|
|
228
|
-
server.close();
|
|
229
|
-
} catch (_) {}
|
|
230
|
-
resolve(null);
|
|
231
|
-
}, timeoutMs);
|
|
232
|
-
server.on('close', () => clearTimeout(timer));
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
|
|
236
170
|
async function saveAndValidateToken(token, { apiUrl, label }) {
|
|
237
171
|
const fetch = require('node-fetch');
|
|
238
172
|
const res = await fetch(`${apiUrl}/api/hosting/quota`, {
|
|
239
173
|
headers: { Authorization: `Bearer ${token}` },
|
|
240
174
|
});
|
|
241
|
-
|
|
242
175
|
if (res.status === 401) {
|
|
243
176
|
throw new Error('Invalid or expired token');
|
|
244
177
|
}
|
|
245
|
-
|
|
246
178
|
setConfig({ token, apiUrl });
|
|
247
|
-
|
|
248
179
|
console.log('');
|
|
249
180
|
console.log(chalk.green('✓ Logged in'));
|
|
250
|
-
console.log(chalk.gray(`
|
|
181
|
+
console.log(chalk.gray(` Config: ~/.moontraze/config.json`));
|
|
251
182
|
console.log('');
|
|
252
183
|
}
|
|
253
184
|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
const fetch = require('node-fetch');
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
|
|
8
|
+
const API = process.env.MOON_API || 'https://api.moontraze.com';
|
|
9
|
+
|
|
10
|
+
// Moontraze platform ka apna install folder
|
|
11
|
+
const INSTALL_DIR = path.join(os.homedir(), '.moontraze', 'cli');
|
|
12
|
+
const MOON_CFG = path.join(os.homedir(), '.moon', 'config.json');
|
|
13
|
+
|
|
14
|
+
// ★ Sirf yahan change — moontraze ka apna manifest
|
|
15
|
+
async function fetchManifest() {
|
|
16
|
+
const res = await fetch(`${API}/cli/platforms/moontraze/manifest.json`);
|
|
17
|
+
if (!res.ok) {
|
|
18
|
+
throw new Error(`Could not fetch moontraze manifest (${res.status})`);
|
|
19
|
+
}
|
|
20
|
+
return res.json();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function downloadTo(url, dest) {
|
|
24
|
+
const res = await fetch(url);
|
|
25
|
+
if (!res.ok) throw new Error('Download failed: ' + url);
|
|
26
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
27
|
+
fs.writeFileSync(dest, buf);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function extractTarball(tgz, destDir) {
|
|
31
|
+
const tmp = path.join(os.tmpdir(), 'moontraze-extract-' + Date.now());
|
|
32
|
+
fs.mkdirSync(tmp, { recursive: true });
|
|
33
|
+
|
|
34
|
+
execSync(`tar -xzf "${tgz}" -C "${tmp}"`, { stdio: 'inherit', shell: true });
|
|
35
|
+
|
|
36
|
+
const entries = fs.readdirSync(tmp).map(n => path.join(tmp, n));
|
|
37
|
+
const pkg = entries.find(p => fs.statSync(p).isDirectory());
|
|
38
|
+
|
|
39
|
+
if (!pkg) {
|
|
40
|
+
console.error('Extracted contents:', entries);
|
|
41
|
+
throw new Error('Invalid tarball layout (expected package/ directory)');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (fs.existsSync(destDir)) {
|
|
45
|
+
fs.rmSync(destDir, { recursive: true, force: true });
|
|
46
|
+
}
|
|
47
|
+
fs.mkdirSync(path.dirname(destDir), { recursive: true });
|
|
48
|
+
fs.renameSync(pkg, destDir);
|
|
49
|
+
|
|
50
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function pointMoonPlatformToInstall() {
|
|
54
|
+
const pkgJsonPath = path.join(INSTALL_DIR, 'package.json');
|
|
55
|
+
if (!fs.existsSync(pkgJsonPath)) {
|
|
56
|
+
throw new Error('package.json missing after extract');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
|
|
60
|
+
|
|
61
|
+
// bin field se runner path nikaalo
|
|
62
|
+
let runnerRel = 'bin/moontraze.js';
|
|
63
|
+
if (pkg.bin) {
|
|
64
|
+
if (typeof pkg.bin === 'string') {
|
|
65
|
+
runnerRel = pkg.bin;
|
|
66
|
+
} else if (pkg.bin.moontraze) {
|
|
67
|
+
runnerRel = pkg.bin.moontraze;
|
|
68
|
+
} else {
|
|
69
|
+
const first = Object.values(pkg.bin)[0];
|
|
70
|
+
if (first) runnerRel = first;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const runner = path.join(INSTALL_DIR, runnerRel);
|
|
75
|
+
|
|
76
|
+
if (!fs.existsSync(runner)) {
|
|
77
|
+
console.error(chalk.red('\n--- Debug: files after extract ---'));
|
|
78
|
+
console.error('INSTALL_DIR:', INSTALL_DIR);
|
|
79
|
+
try {
|
|
80
|
+
console.error(fs.readdirSync(INSTALL_DIR));
|
|
81
|
+
const binDir = path.join(INSTALL_DIR, 'bin');
|
|
82
|
+
if (fs.existsSync(binDir)) {
|
|
83
|
+
console.error('bin/ →', fs.readdirSync(binDir));
|
|
84
|
+
}
|
|
85
|
+
} catch (_) {}
|
|
86
|
+
console.error('----------------------------------\n');
|
|
87
|
+
throw new Error('Runner missing after extract: ' + runner);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// moon global config update (sirf moontraze entry)
|
|
91
|
+
let cfg = { defaultPlatform: null, platforms: {} };
|
|
92
|
+
try {
|
|
93
|
+
if (fs.existsSync(MOON_CFG)) {
|
|
94
|
+
cfg = JSON.parse(fs.readFileSync(MOON_CFG, 'utf8'));
|
|
95
|
+
}
|
|
96
|
+
} catch (_) {}
|
|
97
|
+
|
|
98
|
+
if (!cfg.platforms) cfg.platforms = {};
|
|
99
|
+
|
|
100
|
+
cfg.platforms.moontraze = {
|
|
101
|
+
label: 'Moontraze',
|
|
102
|
+
runner,
|
|
103
|
+
apiUrl: API,
|
|
104
|
+
addedAt: new Date().toISOString(),
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
if (!cfg.defaultPlatform) {
|
|
108
|
+
cfg.defaultPlatform = 'moontraze';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
fs.mkdirSync(path.dirname(MOON_CFG), { recursive: true });
|
|
112
|
+
fs.writeFileSync(MOON_CFG, JSON.stringify(cfg, null, 2));
|
|
113
|
+
|
|
114
|
+
return runner;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function selfUpdate() {
|
|
118
|
+
console.log(chalk.cyan('Checking Moontraze CLI updates...'));
|
|
119
|
+
|
|
120
|
+
const manifest = await fetchManifest();
|
|
121
|
+
const ver = manifest.version;
|
|
122
|
+
const url = manifest.tarball;
|
|
123
|
+
|
|
124
|
+
console.log(chalk.gray(` Latest: v${ver}`));
|
|
125
|
+
console.log(chalk.gray(` ${url}`));
|
|
126
|
+
|
|
127
|
+
const tgz = path.join(os.tmpdir(), `moontraze-${ver}.tgz`);
|
|
128
|
+
await downloadTo(url, tgz);
|
|
129
|
+
|
|
130
|
+
console.log(chalk.cyan('Extracting...'));
|
|
131
|
+
extractTarball(tgz, INSTALL_DIR);
|
|
132
|
+
|
|
133
|
+
console.log(chalk.cyan('Installing dependencies...'));
|
|
134
|
+
execSync('npm install --omit=dev', {
|
|
135
|
+
cwd: INSTALL_DIR,
|
|
136
|
+
stdio: 'inherit',
|
|
137
|
+
shell: true,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const runner = pointMoonPlatformToInstall();
|
|
141
|
+
|
|
142
|
+
try { fs.unlinkSync(tgz); } catch (_) {}
|
|
143
|
+
|
|
144
|
+
console.log('');
|
|
145
|
+
console.log(chalk.green(`✓ Moontraze CLI v${ver} installed`));
|
|
146
|
+
console.log(chalk.gray(` ${INSTALL_DIR}`));
|
|
147
|
+
console.log(chalk.gray(` Runner: ${runner}`));
|
|
148
|
+
console.log(chalk.gray(' Try: moon moontraze list'));
|
|
149
|
+
console.log('');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
module.exports = { selfUpdate, INSTALL_DIR };
|
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moontraze",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Deploy to Moontraze hosting
|
|
3
|
+
"version": "1.0.9",
|
|
4
|
+
"description": "Deploy to Moontraze hosting",
|
|
5
5
|
"bin": {
|
|
6
|
-
"moon": "./bin/moon.js",
|
|
7
6
|
"moontraze": "./bin/moontraze.js"
|
|
8
7
|
},
|
|
9
8
|
"files": [
|