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 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.5');
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
- console.log(chalk.green(`✓ Logged in to ${platformName}`));
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
- // deploy
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(` ${data.user.email}`));
84
- console.log(chalk.gray(` Config: ~/.moontraze/config.json`));
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
- const startRes = await fetch(`${apiUrl}/api/platform/moonid/cli-start`, {
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 CLI session');
95
+ throw new Error(startData.error || 'Could not start MoonID session');
101
96
  }
102
97
 
103
- const redirectUri =
104
- startData.redirectUri ||
105
- `${apiUrl}/api/platform/moonid/cli-callback`;
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 pollCliStatus({ apiUrl, state, timeoutMs: 180000 });
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 pollCliStatus({ apiUrl, state, timeoutMs }) {
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/cli-status?state=${encodeURIComponent(state)}`
144
+ `${apiUrl}/api/platform/moonid/status?state=${encodeURIComponent(state)}`
152
145
  );
153
146
  const data = await res.json().catch(() => ({}));
154
147
 
155
- if (data.status === 'done' && data.token) {
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 === 'denied' || data.status === 'error') {
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 (e.message && /denied|failed|not found|mismatch|expired/i.test(e.message)) {
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(` Config: ~/.moontraze/config.json`));
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.7",
4
- "description": "Deploy to Moontraze hosting — like vercel CLI",
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": [