moontraze 2.0.6 → 2.0.8

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.
Files changed (2) hide show
  1. package/lib/deploy.js +150 -23
  2. package/package.json +1 -1
package/lib/deploy.js CHANGED
@@ -6,6 +6,72 @@ const chalk = require('chalk');
6
6
  const { getConfig, getProject } = require('./config');
7
7
  const { zipCwd } = require('./zip');
8
8
 
9
+ /**
10
+ * Job status poll + Vercel-style gray progress
11
+ */
12
+ async function waitForDeployJob({ apiUrl, token, jobId }) {
13
+ const start = Date.now();
14
+ const timeoutMs = 15 * 60 * 1000; // 15 min
15
+ let lastMessage = '';
16
+
17
+ const printProgress = (msg) => {
18
+ if (!msg || msg === lastMessage) return;
19
+ lastMessage = msg;
20
+ process.stdout.write('\r\x1b[K' + chalk.gray(' ' + msg));
21
+ };
22
+
23
+ printProgress('Queued...');
24
+
25
+ while (Date.now() - start < timeoutMs) {
26
+ await new Promise((r) => setTimeout(r, 1500));
27
+
28
+ let data = {};
29
+ try {
30
+ const res = await fetch(
31
+ `${apiUrl}/api/hosting/deployments/job/${encodeURIComponent(jobId)}`,
32
+ { headers: { Authorization: `Bearer ${token}` } }
33
+ );
34
+ data = await res.json().catch(() => ({}));
35
+ if (!res.ok) {
36
+ throw new Error(data.error || `Status check failed (${res.status})`);
37
+ }
38
+ } catch (e) {
39
+ printProgress('Checking status...');
40
+ continue;
41
+ }
42
+
43
+ const state = data.state;
44
+ const progress = data.progress;
45
+ let message = 'Working...';
46
+
47
+ if (typeof progress === 'object' && progress?.message) {
48
+ message = progress.message;
49
+ } else if (typeof progress === 'number') {
50
+ message = `Building... ${progress}%`;
51
+ } else if (state === 'waiting' || state === 'delayed') {
52
+ message = 'Queued — waiting for worker...';
53
+ } else if (state === 'active') {
54
+ message = 'Building...';
55
+ } else if (state === 'completed') {
56
+ message = 'Done';
57
+ }
58
+
59
+ printProgress(message);
60
+
61
+ if (state === 'completed') {
62
+ process.stdout.write('\n');
63
+ return data.result || {};
64
+ }
65
+ if (state === 'failed') {
66
+ process.stdout.write('\n');
67
+ throw new Error(data.error || 'Deploy failed');
68
+ }
69
+ }
70
+
71
+ process.stdout.write('\n');
72
+ throw new Error('Deploy timed out. Check dashboard or try again.');
73
+ }
74
+
9
75
  async function deploy({
10
76
  prod = true,
11
77
  projectName,
@@ -13,21 +79,19 @@ async function deploy({
13
79
  domain: domainArg,
14
80
  } = {}) {
15
81
  const cfg = getConfig();
16
-
17
82
  const api =
18
83
  apiUrlArg ||
19
84
  process.env.MOON_API ||
20
85
  cfg.apiUrl ||
21
86
  'https://api.moontraze.com';
22
-
23
87
  const domain =
24
88
  domainArg ||
25
89
  process.env.MOON_DOMAIN ||
26
90
  cfg.domain ||
27
91
  'moontraze.com';
28
-
29
92
  const token = cfg.token || process.env.MOON_TOKEN || null;
30
- const label = process.env.MOON_LABEL || process.env.MOON_PLATFORM || 'Moontraze';
93
+ const label =
94
+ process.env.MOON_LABEL || process.env.MOON_PLATFORM || 'Moontraze';
31
95
 
32
96
  if (!token) {
33
97
  throw new Error(
@@ -38,7 +102,10 @@ async function deploy({
38
102
  const linked = getProject();
39
103
  const name = (projectName || linked?.projectName || '')
40
104
  .toLowerCase()
41
- .replace(/[^a-z0-9-]/g, '');
105
+ .trim()
106
+ .replace(/[^a-z0-9-]/g, '-')
107
+ .replace(/-+/g, '-')
108
+ .replace(/^-|-$/g, '');
42
109
 
43
110
  if (!name || name.length < 3) {
44
111
  throw new Error(
@@ -50,8 +117,6 @@ async function deploy({
50
117
  console.log(chalk.cyan(label));
51
118
  console.log(` API ${api}`);
52
119
  console.log(` Project ${name}`);
53
- console.log(` Target https://${name}.${domain}`);
54
- console.log('');
55
120
 
56
121
  const spinner = ora('Packaging...').start();
57
122
  const t0 = Date.now();
@@ -61,22 +126,47 @@ async function deploy({
61
126
  zipPath = await zipCwd();
62
127
  const mb = (fs.statSync(zipPath).size / 1024 / 1024).toFixed(2);
63
128
 
129
+ // -------- Check if project already exists --------
64
130
  spinner.text = 'Checking project...';
65
131
  let alreadyExists = false;
132
+ let existingUrl = null;
133
+ let hostLabel = null;
66
134
 
67
135
  try {
68
- const statusRes = await fetch(`${api}/api/hosting/status/${name}`, {
69
- headers: { Authorization: `Bearer ${token}` },
70
- });
71
- if (statusRes.ok) {
72
- const statusData = await statusRes.json();
73
- alreadyExists = !!statusData.exists;
136
+ const statusRes = await fetch(
137
+ `${api}/api/hosting/status/${encodeURIComponent(name)}`,
138
+ { headers: { Authorization: `Bearer ${token}` } }
139
+ );
140
+ const statusData = await statusRes.json().catch(() => ({}));
141
+
142
+ // exists true = deployed / building / failed (status API fix ke baad)
143
+ if (statusRes.ok && statusData.exists) {
144
+ alreadyExists = true;
145
+ existingUrl = statusData.primaryUrl || statusData.url || null;
146
+ hostLabel = statusData.hostLabel || null;
74
147
  }
75
148
  } catch (_) {
76
- // assume new
149
+ // network fail → backend khud decide karega
77
150
  }
78
151
 
79
- spinner.text = `Uploading (${mb} MB)...`;
152
+ // Target URL dikhao
153
+ const previewUrl =
154
+ existingUrl ||
155
+ (hostLabel
156
+ ? `https://${hostLabel}.${domain}`
157
+ : `https://${name}.${domain}`);
158
+ spinner.stop();
159
+ console.log(` Target ${previewUrl}`);
160
+ console.log(
161
+ chalk.gray(
162
+ alreadyExists
163
+ ? ' Mode Redeploy (existing project)'
164
+ : ' Mode New deploy'
165
+ )
166
+ );
167
+ console.log('');
168
+
169
+ spinner.start(`Uploading (${mb} MB)...`);
80
170
 
81
171
  const form = new FormData();
82
172
  form.append('projectName', name);
@@ -84,12 +174,10 @@ async function deploy({
84
174
  filename: `${name}.zip`,
85
175
  contentType: 'application/zip',
86
176
  });
177
+ // Backend bhi force-redeploy karta hai agar same name exist kare
87
178
  form.append('redeploy', alreadyExists ? 'true' : 'false');
88
179
 
89
- const endpoint = alreadyExists
90
- ? `${api}/api/hosting/redeploy`
91
- : `${api}/api/hosting/deploy`;
92
-
180
+ const endpoint = `${api}/api/hosting/deploy`;
93
181
  const res = await fetch(endpoint, {
94
182
  method: 'POST',
95
183
  headers: {
@@ -107,23 +195,62 @@ async function deploy({
107
195
  data = { error: text };
108
196
  }
109
197
 
110
- const sec = ((Date.now() - t0) / 1000).toFixed(1);
198
+ // ---------- Queued flow ----------
199
+ if (res.status === 202 && data.jobId) {
200
+ spinner.stop();
201
+ console.log(chalk.gray(' Upload done — build starting...'));
202
+ console.log('');
111
203
 
204
+ const result = await waitForDeployJob({
205
+ apiUrl: api,
206
+ token,
207
+ jobId: data.jobId,
208
+ });
209
+
210
+ const sec = ((Date.now() - t0) / 1000).toFixed(1);
211
+ const url =
212
+ result?.url ||
213
+ existingUrl ||
214
+ data.url ||
215
+ `https://${name}.${domain}`;
216
+
217
+ const wasRedeploy =
218
+ alreadyExists || data.redeploy === true || result?.redeploy === true;
219
+
220
+ console.log('');
221
+ console.log(chalk.green(` Production ${url}`));
222
+ if (result?.version || data.deployment?.version) {
223
+ console.log(
224
+ chalk.gray(
225
+ ` Version ${result?.version || data.deployment?.version}`
226
+ )
227
+ );
228
+ }
229
+ console.log(chalk.gray(` Time ${sec}s`));
230
+ console.log(chalk.green(wasRedeploy ? '✓ Redeployed' : '✓ Deployed'));
231
+ console.log('');
232
+ return result;
233
+ }
234
+
235
+ // ---------- Sync fallback ----------
236
+ const sec = ((Date.now() - t0) / 1000).toFixed(1);
112
237
  if (!res.ok) {
113
238
  spinner.fail(`Failed (${sec}s)`);
114
239
  throw new Error(data.error || `HTTP ${res.status}`);
115
240
  }
116
241
 
117
242
  spinner.succeed(`Ready in ${sec}s`);
118
-
119
- const url = data.url || `https://${name}.${domain}`;
243
+ const url = data.url || existingUrl || `https://${name}.${domain}`;
120
244
  console.log('');
121
245
  console.log(chalk.green(` Production ${url}`));
122
246
  if (data.deployment?.version) {
123
247
  console.log(chalk.gray(` Version ${data.deployment.version}`));
124
248
  }
125
- console.log(chalk.green(alreadyExists ? '✓ Redeployed' : '✓ Deployed'));
249
+ console.log(
250
+ chalk.green(alreadyExists || data.redeploy ? '✓ Redeployed' : '✓ Deployed')
251
+ );
126
252
  console.log('');
253
+ return data;
127
254
  } finally {
128
255
  if (zipPath && fs.existsSync(zipPath)) {
129
256
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moontraze",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "description": "Deploy to Moontraze hosting",
5
5
  "main": "./bin/moontraze.js",
6
6
  "bin": {