@nivo-lat/cli 1.0.0 → 1.1.0
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/dist/commands/apps.js +141 -74
- package/dist/commands/auth.js +21 -27
- package/dist/commands/link.js +70 -79
- package/dist/ui.js +24 -8
- package/package.json +2 -2
package/dist/commands/apps.js
CHANGED
|
@@ -11,33 +11,35 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
11
11
|
const os_1 = __importDefault(require("os"));
|
|
12
12
|
const path_1 = __importDefault(require("path"));
|
|
13
13
|
const chalk_1 = __importDefault(require("chalk"));
|
|
14
|
-
const ora_1 = __importDefault(require("ora"));
|
|
15
|
-
const form_data_1 = __importDefault(require("form-data"));
|
|
16
14
|
const adm_zip_1 = __importDefault(require("adm-zip"));
|
|
15
|
+
const form_data_1 = __importDefault(require("form-data"));
|
|
17
16
|
const api_1 = require("../api");
|
|
18
17
|
const config_1 = require("../config");
|
|
19
18
|
const ui_1 = require("../ui");
|
|
20
19
|
const TERMINAL_STATUSES = new Set(['success', 'error', 'cancelled']);
|
|
21
20
|
const IGNORED_NAMES = new Set([
|
|
22
|
-
'.git',
|
|
23
|
-
'.
|
|
24
|
-
'.next',
|
|
25
|
-
'node_modules',
|
|
26
|
-
'.env',
|
|
27
|
-
'.env.local',
|
|
28
|
-
'.env.production',
|
|
29
|
-
'.env.development',
|
|
30
|
-
'.DS_Store',
|
|
21
|
+
'.git', '.nivo', '.next', 'node_modules',
|
|
22
|
+
'.env', '.env.local', '.env.production', '.env.development', '.DS_Store',
|
|
31
23
|
]);
|
|
24
|
+
const STATUS_COLOR = {
|
|
25
|
+
running: (s) => chalk_1.default.green(s),
|
|
26
|
+
success: (s) => chalk_1.default.green(s),
|
|
27
|
+
building: (s) => chalk_1.default.yellow(s),
|
|
28
|
+
pending: (s) => chalk_1.default.yellow(s),
|
|
29
|
+
error: (s) => chalk_1.default.red(s),
|
|
30
|
+
cancelled: (s) => chalk_1.default.dim(s),
|
|
31
|
+
stopped: (s) => chalk_1.default.dim(s),
|
|
32
|
+
provisioning: (s) => chalk_1.default.yellow(s),
|
|
33
|
+
};
|
|
34
|
+
function colorStatus(status) {
|
|
35
|
+
return (STATUS_COLOR[status] ?? chalk_1.default.dim)(status);
|
|
36
|
+
}
|
|
32
37
|
function ensureLoggedIn() {
|
|
33
38
|
if ((0, config_1.getCredentials)().token)
|
|
34
39
|
return true;
|
|
35
|
-
ui_1.logger.error('
|
|
40
|
+
ui_1.logger.error('nao autenticado · rode `nivo login`');
|
|
36
41
|
return false;
|
|
37
42
|
}
|
|
38
|
-
function readLinkedAppId() {
|
|
39
|
-
return readNivoProjectConfig()?.appId ?? null;
|
|
40
|
-
}
|
|
41
43
|
function readNivoProjectConfig() {
|
|
42
44
|
const configPath = path_1.default.join(process.cwd(), '.nivo');
|
|
43
45
|
if (!fs_1.default.existsSync(configPath))
|
|
@@ -66,16 +68,12 @@ async function applyLocalProjectConfig(appId) {
|
|
|
66
68
|
async function getAppId(explicit) {
|
|
67
69
|
if (explicit)
|
|
68
70
|
return explicit;
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
71
|
-
return
|
|
72
|
-
ui_1.logger.error('
|
|
71
|
+
const config = readNivoProjectConfig();
|
|
72
|
+
if (config?.appId)
|
|
73
|
+
return config.appId;
|
|
74
|
+
ui_1.logger.error('nao ha .nivo nesta pasta · rode `nivo link`');
|
|
73
75
|
return null;
|
|
74
76
|
}
|
|
75
|
-
async function fetchApps() {
|
|
76
|
-
const res = await api_1.api.get('/apps');
|
|
77
|
-
return res.data;
|
|
78
|
-
}
|
|
79
77
|
function addDir(zip, dir, root) {
|
|
80
78
|
for (const entry of fs_1.default.readdirSync(dir, { withFileTypes: true })) {
|
|
81
79
|
if (IGNORED_NAMES.has(entry.name) || entry.name.endsWith('.log'))
|
|
@@ -97,16 +95,15 @@ function createZip(sourceDir) {
|
|
|
97
95
|
}
|
|
98
96
|
const zip = new adm_zip_1.default();
|
|
99
97
|
addDir(zip, resolved, resolved);
|
|
100
|
-
const
|
|
101
|
-
zip.writeZip(
|
|
102
|
-
|
|
98
|
+
const zipPath = path_1.default.join(os_1.default.tmpdir(), `nivo-deploy-${Date.now()}.zip`);
|
|
99
|
+
zip.writeZip(zipPath);
|
|
100
|
+
const fileCount = zip.getEntries().length;
|
|
101
|
+
const sizeMb = (fs_1.default.statSync(zipPath).size / 1024 / 1024).toFixed(1);
|
|
102
|
+
return { zipPath, fileCount, sizeMb };
|
|
103
103
|
}
|
|
104
104
|
async function uploadZip(appId, zipPath) {
|
|
105
105
|
const form = new form_data_1.default();
|
|
106
|
-
form.append('file', fs_1.default.createReadStream(zipPath), {
|
|
107
|
-
filename: 'app.zip',
|
|
108
|
-
contentType: 'application/zip',
|
|
109
|
-
});
|
|
106
|
+
form.append('file', fs_1.default.createReadStream(zipPath), { filename: 'app.zip', contentType: 'application/zip' });
|
|
110
107
|
const res = await api_1.api.post(`/apps/${encodeURIComponent(appId)}/upload`, form, {
|
|
111
108
|
headers: form.getHeaders(),
|
|
112
109
|
maxBodyLength: Infinity,
|
|
@@ -114,88 +111,127 @@ async function uploadZip(appId, zipPath) {
|
|
|
114
111
|
});
|
|
115
112
|
return res.data;
|
|
116
113
|
}
|
|
114
|
+
function appUrl(app) {
|
|
115
|
+
return app.customDomain
|
|
116
|
+
? `https://${app.customDomain}`
|
|
117
|
+
: app.subdomain
|
|
118
|
+
? `https://${app.subdomain}.app.nivo.lat`
|
|
119
|
+
: '';
|
|
120
|
+
}
|
|
117
121
|
async function waitDeployment(appId, deploymentId) {
|
|
118
122
|
let printed = 0;
|
|
119
123
|
let lastStatus = '';
|
|
124
|
+
let headerShown = false;
|
|
120
125
|
while (true) {
|
|
121
126
|
const res = await api_1.api.get(`/apps/${encodeURIComponent(appId)}/deployments/${encodeURIComponent(deploymentId)}/logs`);
|
|
122
127
|
const data = res.data;
|
|
123
128
|
const log = data.log ?? '';
|
|
124
129
|
if (log.length > printed) {
|
|
130
|
+
if (!headerShown) {
|
|
131
|
+
ui_1.logger.blank();
|
|
132
|
+
ui_1.logger.rule();
|
|
133
|
+
headerShown = true;
|
|
134
|
+
}
|
|
125
135
|
process.stdout.write(log.slice(printed));
|
|
126
136
|
printed = log.length;
|
|
127
137
|
}
|
|
128
|
-
if (data.status !== lastStatus)
|
|
138
|
+
if (data.status !== lastStatus)
|
|
129
139
|
lastStatus = data.status;
|
|
130
|
-
ui_1.logger.info(`status ${data.status}`);
|
|
131
|
-
}
|
|
132
140
|
if (TERMINAL_STATUSES.has(data.status)) {
|
|
133
|
-
if (
|
|
134
|
-
ui_1.logger.
|
|
135
|
-
|
|
136
|
-
|
|
141
|
+
if (headerShown)
|
|
142
|
+
ui_1.logger.rule();
|
|
143
|
+
ui_1.logger.blank();
|
|
144
|
+
if (data.status === 'success') {
|
|
145
|
+
ui_1.logger.success('deploy finalizado');
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
ui_1.logger.error(`deploy terminou como ${data.status}`);
|
|
149
|
+
}
|
|
137
150
|
return;
|
|
138
151
|
}
|
|
139
152
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
140
153
|
}
|
|
141
154
|
}
|
|
155
|
+
// ── Commands ──────────────────────────────────────────────────────────────────
|
|
142
156
|
async function listApps() {
|
|
143
157
|
if (!ensureLoggedIn())
|
|
144
158
|
return;
|
|
145
159
|
try {
|
|
146
|
-
const apps = await
|
|
160
|
+
const apps = await (0, ui_1.runStep)('buscando apps...', () => api_1.api.get('/apps').then((r) => r.data));
|
|
147
161
|
if (!apps.length) {
|
|
148
|
-
ui_1.logger.warn('
|
|
162
|
+
ui_1.logger.warn('nenhum app encontrado');
|
|
149
163
|
return;
|
|
150
164
|
}
|
|
151
|
-
|
|
165
|
+
ui_1.logger.blank();
|
|
166
|
+
console.log(` ${chalk_1.default.dim('nome'.padEnd(22))}` +
|
|
167
|
+
`${chalk_1.default.dim('status'.padEnd(14))}` +
|
|
168
|
+
`${chalk_1.default.dim('fonte'.padEnd(10))}` +
|
|
169
|
+
`${chalk_1.default.dim('url')}`);
|
|
170
|
+
ui_1.logger.rule();
|
|
152
171
|
for (const app of apps) {
|
|
153
|
-
const url =
|
|
154
|
-
|
|
155
|
-
console.log(
|
|
172
|
+
const url = appUrl(app);
|
|
173
|
+
const runtime = app.runtime ? chalk_1.default.dim(` · ${app.runtime}`) : '';
|
|
174
|
+
console.log(` ${chalk_1.default.bold(app.name.padEnd(22))}` +
|
|
175
|
+
`${colorStatus(app.status).padEnd(14 + (colorStatus(app.status).length - app.status.length))}` +
|
|
176
|
+
`${chalk_1.default.dim(app.sourceType.padEnd(10))}` +
|
|
177
|
+
`${url ? chalk_1.default.underline(url) : chalk_1.default.dim('-')}${runtime}`);
|
|
178
|
+
console.log(` ${chalk_1.default.dim(app.id)}`);
|
|
156
179
|
}
|
|
180
|
+
ui_1.logger.blank();
|
|
157
181
|
}
|
|
158
182
|
catch (err) {
|
|
159
|
-
ui_1.logger.error(`
|
|
183
|
+
ui_1.logger.error(`falha ao listar apps: ${err.message}`);
|
|
160
184
|
}
|
|
161
185
|
}
|
|
162
186
|
async function deploy(sourceDir = '.', opts = {}) {
|
|
163
187
|
if (!ensureLoggedIn())
|
|
164
188
|
return;
|
|
189
|
+
ui_1.logger.blank();
|
|
190
|
+
let zipPath = null;
|
|
165
191
|
try {
|
|
166
192
|
const appId = await getAppId(opts.app);
|
|
167
193
|
if (!appId)
|
|
168
194
|
return;
|
|
169
|
-
await applyLocalProjectConfig(appId);
|
|
170
|
-
const
|
|
171
|
-
const app = appRes.data;
|
|
195
|
+
await (0, ui_1.runStep)('aplicando configuracao local...', async () => applyLocalProjectConfig(appId), () => 'configuracao aplicada');
|
|
196
|
+
const app = await (0, ui_1.runStep)('buscando app...', () => api_1.api.get(`/apps/${encodeURIComponent(appId)}`).then((r) => r.data), (a) => `app encontrado · ${chalk_1.default.bold(a.name)} ${chalk_1.default.dim(`(${a.sourceType} · ${a.runtime ?? 'node20'})`)}`);
|
|
172
197
|
let deploymentId;
|
|
173
198
|
if (app.sourceType === 'zip') {
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
199
|
+
const { zipPath: zp, fileCount, sizeMb } = await (0, ui_1.runStep)('compactando projeto...', async () => createZip(sourceDir), ({ fileCount, sizeMb }) => `compactado · ${fileCount} arquivos · ${sizeMb} MB`);
|
|
200
|
+
zipPath = zp;
|
|
201
|
+
const result = await (0, ui_1.runStep)('enviando deploy...', async () => {
|
|
202
|
+
try {
|
|
203
|
+
return await uploadZip(appId, zp);
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
fs_1.default.rmSync(zp, { force: true });
|
|
207
|
+
zipPath = null;
|
|
208
|
+
}
|
|
209
|
+
}, ({ deploymentId }) => `enviado · ${chalk_1.default.dim(deploymentId)}`);
|
|
210
|
+
deploymentId = result.deploymentId;
|
|
185
211
|
}
|
|
186
212
|
else {
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
deploymentId = res.data.deploymentId;
|
|
190
|
-
spinner.succeed(`Deploy criado ${deploymentId}`);
|
|
213
|
+
const result = await (0, ui_1.runStep)('iniciando redeploy...', () => api_1.api.post(`/apps/${encodeURIComponent(appId)}/deploy`).then((r) => r.data), ({ deploymentId }) => `redeploy iniciado · ${chalk_1.default.dim(deploymentId)}`);
|
|
214
|
+
deploymentId = result.deploymentId;
|
|
191
215
|
}
|
|
192
|
-
if (opts.watch)
|
|
216
|
+
if (opts.watch) {
|
|
193
217
|
await waitDeployment(appId, deploymentId);
|
|
194
|
-
|
|
195
|
-
|
|
218
|
+
const url = appUrl(app);
|
|
219
|
+
if (url)
|
|
220
|
+
ui_1.logger.info(url);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
ui_1.logger.blank();
|
|
224
|
+
ui_1.logger.info(`acompanhe os logs: nivo logs --deployment ${deploymentId}`);
|
|
225
|
+
}
|
|
226
|
+
ui_1.logger.blank();
|
|
196
227
|
}
|
|
197
228
|
catch (err) {
|
|
198
|
-
ui_1.logger.
|
|
229
|
+
ui_1.logger.blank();
|
|
230
|
+
ui_1.logger.error(`deploy falhou: ${err.message}`);
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
if (zipPath)
|
|
234
|
+
fs_1.default.rmSync(zipPath, { force: true });
|
|
199
235
|
}
|
|
200
236
|
}
|
|
201
237
|
async function deployments(opts = {}) {
|
|
@@ -205,18 +241,31 @@ async function deployments(opts = {}) {
|
|
|
205
241
|
const appId = await getAppId(opts.app);
|
|
206
242
|
if (!appId)
|
|
207
243
|
return;
|
|
208
|
-
const
|
|
209
|
-
const items = res.data;
|
|
244
|
+
const items = await (0, ui_1.runStep)('buscando deployments...', () => api_1.api.get(`/apps/${encodeURIComponent(appId)}/deployments`).then((r) => r.data));
|
|
210
245
|
if (!items.length) {
|
|
211
|
-
ui_1.logger.warn('
|
|
246
|
+
ui_1.logger.warn('nenhum deployment encontrado');
|
|
212
247
|
return;
|
|
213
248
|
}
|
|
249
|
+
ui_1.logger.blank();
|
|
250
|
+
console.log(` ${chalk_1.default.dim('status'.padEnd(14))}` +
|
|
251
|
+
`${chalk_1.default.dim('trigger'.padEnd(10))}` +
|
|
252
|
+
`${chalk_1.default.dim('data'.padEnd(22))}` +
|
|
253
|
+
`${chalk_1.default.dim('id')}`);
|
|
254
|
+
ui_1.logger.rule();
|
|
214
255
|
for (const dep of items) {
|
|
215
|
-
|
|
256
|
+
const date = new Date(dep.createdAt).toLocaleString('pt-BR');
|
|
257
|
+
const duration = dep.finishedAt
|
|
258
|
+
? chalk_1.default.dim(` · ${Math.round((new Date(dep.finishedAt).getTime() - new Date(dep.createdAt).getTime()) / 1000)}s`)
|
|
259
|
+
: '';
|
|
260
|
+
console.log(` ${colorStatus(dep.status).padEnd(14 + (colorStatus(dep.status).length - dep.status.length))}` +
|
|
261
|
+
`${chalk_1.default.dim(dep.trigger.padEnd(10))}` +
|
|
262
|
+
`${chalk_1.default.dim(date.padEnd(22))}` +
|
|
263
|
+
`${chalk_1.default.dim(dep.id)}${duration}`);
|
|
216
264
|
}
|
|
265
|
+
ui_1.logger.blank();
|
|
217
266
|
}
|
|
218
267
|
catch (err) {
|
|
219
|
-
ui_1.logger.error(`
|
|
268
|
+
ui_1.logger.error(`falha ao listar deployments: ${err.message}`);
|
|
220
269
|
}
|
|
221
270
|
}
|
|
222
271
|
async function logs(opts = {}) {
|
|
@@ -228,13 +277,31 @@ async function logs(opts = {}) {
|
|
|
228
277
|
return;
|
|
229
278
|
if (opts.deployment) {
|
|
230
279
|
const res = await api_1.api.get(`/apps/${encodeURIComponent(appId)}/deployments/${encodeURIComponent(opts.deployment)}/logs`);
|
|
231
|
-
|
|
280
|
+
const log = res.data.log ?? '';
|
|
281
|
+
if (!log.trim()) {
|
|
282
|
+
ui_1.logger.warn('nenhum log de build encontrado');
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
ui_1.logger.blank();
|
|
286
|
+
ui_1.logger.rule();
|
|
287
|
+
process.stdout.write(log.endsWith('\n') ? log : log + '\n');
|
|
288
|
+
ui_1.logger.rule();
|
|
289
|
+
ui_1.logger.blank();
|
|
232
290
|
return;
|
|
233
291
|
}
|
|
234
292
|
const res = await api_1.api.get(`/apps/${encodeURIComponent(appId)}/logs`);
|
|
235
|
-
|
|
293
|
+
const log = res.data.log ?? '';
|
|
294
|
+
if (!log.trim()) {
|
|
295
|
+
ui_1.logger.warn('nenhum log de runtime encontrado');
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
ui_1.logger.blank();
|
|
299
|
+
ui_1.logger.rule();
|
|
300
|
+
process.stdout.write(log.endsWith('\n') ? log : log + '\n');
|
|
301
|
+
ui_1.logger.rule();
|
|
302
|
+
ui_1.logger.blank();
|
|
236
303
|
}
|
|
237
304
|
catch (err) {
|
|
238
|
-
ui_1.logger.error(`
|
|
305
|
+
ui_1.logger.error(`falha ao buscar logs: ${err.message}`);
|
|
239
306
|
}
|
|
240
307
|
}
|
package/dist/commands/auth.js
CHANGED
|
@@ -7,7 +7,6 @@ exports.login = login;
|
|
|
7
7
|
exports.logout = logout;
|
|
8
8
|
exports.me = me;
|
|
9
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
-
const ora_1 = __importDefault(require("ora"));
|
|
11
10
|
const child_process_1 = require("child_process");
|
|
12
11
|
const api_1 = require("../api");
|
|
13
12
|
const config_1 = require("../config");
|
|
@@ -50,69 +49,64 @@ async function pollForToken(deviceCode, intervalSec, expiresInSec) {
|
|
|
50
49
|
async function login() {
|
|
51
50
|
const existing = (0, config_1.getCredentials)();
|
|
52
51
|
if (existing.token) {
|
|
53
|
-
ui_1.logger.warn('Voce ja esta logado. Rode `nivo logout` primeiro
|
|
52
|
+
ui_1.logger.warn('Voce ja esta logado. Rode `nivo logout` primeiro.');
|
|
54
53
|
return;
|
|
55
54
|
}
|
|
56
|
-
ui_1.logger.step('Login');
|
|
57
55
|
let start;
|
|
58
56
|
try {
|
|
59
|
-
|
|
60
|
-
start = res.data;
|
|
57
|
+
start = (await api_1.api.post('/auth/cli/start', {})).data;
|
|
61
58
|
}
|
|
62
59
|
catch (err) {
|
|
63
|
-
ui_1.logger.error(`Nao
|
|
60
|
+
ui_1.logger.error(`Nao foi possivel iniciar o login: ${err.message}`);
|
|
64
61
|
return;
|
|
65
62
|
}
|
|
66
63
|
const url = `${start.verifyUrl}?user_code=${encodeURIComponent(start.userCode)}`;
|
|
67
|
-
|
|
68
|
-
console.log(
|
|
69
|
-
console.log();
|
|
70
|
-
|
|
71
|
-
console.log();
|
|
64
|
+
ui_1.logger.blank();
|
|
65
|
+
console.log(` ${chalk_1.default.dim('codigo')} ${chalk_1.default.bold.hex('#4ade80')(start.userCode)}`);
|
|
66
|
+
console.log(` ${chalk_1.default.dim('url')} ${chalk_1.default.underline(url)}`);
|
|
67
|
+
ui_1.logger.blank();
|
|
72
68
|
openBrowser(url);
|
|
73
|
-
const spinner = (0, ora_1.default)({ text: 'Aguardando autorizacao...', color: 'green' }).start();
|
|
74
69
|
try {
|
|
75
|
-
const apiKey = await pollForToken(start.deviceCode, start.interval, start.expiresIn);
|
|
70
|
+
const apiKey = await (0, ui_1.runStep)('aguardando autorizacao no browser...', () => pollForToken(start.deviceCode, start.interval, start.expiresIn), () => 'autorizado');
|
|
76
71
|
(0, config_1.saveCredentials)({ token: apiKey });
|
|
77
|
-
spinner.succeed('Login concluido');
|
|
78
72
|
try {
|
|
79
73
|
const res = await api_1.api.get('/auth/me');
|
|
80
|
-
ui_1.logger.success(`
|
|
74
|
+
ui_1.logger.success(`logado como ${chalk_1.default.bold(res.data.email)}`);
|
|
81
75
|
}
|
|
82
76
|
catch {
|
|
83
|
-
ui_1.logger.success('
|
|
77
|
+
ui_1.logger.success('credenciais salvas');
|
|
84
78
|
}
|
|
85
79
|
}
|
|
86
80
|
catch (err) {
|
|
87
|
-
|
|
81
|
+
ui_1.logger.error(err.message);
|
|
88
82
|
}
|
|
89
83
|
}
|
|
90
84
|
async function logout() {
|
|
91
85
|
(0, config_1.deleteCredentials)();
|
|
92
|
-
ui_1.logger.success('
|
|
93
|
-
ui_1.logger.info('
|
|
86
|
+
ui_1.logger.success('sessao local removida');
|
|
87
|
+
ui_1.logger.info('para revogar a chave, acesse Configuracoes > CLI no dashboard');
|
|
94
88
|
}
|
|
95
89
|
async function me() {
|
|
96
90
|
const creds = (0, config_1.getCredentials)();
|
|
97
91
|
if (!creds.token) {
|
|
98
|
-
ui_1.logger.error('
|
|
92
|
+
ui_1.logger.error('voce nao esta logado · rode `nivo login`');
|
|
99
93
|
return;
|
|
100
94
|
}
|
|
101
95
|
try {
|
|
102
96
|
const res = await api_1.api.get('/auth/me');
|
|
103
97
|
const user = res.data;
|
|
104
|
-
ui_1.logger.
|
|
105
|
-
console.log(
|
|
106
|
-
console.log(
|
|
107
|
-
console.log(
|
|
108
|
-
|
|
98
|
+
ui_1.logger.blank();
|
|
99
|
+
console.log(` ${chalk_1.default.dim('email')} ${chalk_1.default.white(user.email)}`);
|
|
100
|
+
console.log(` ${chalk_1.default.dim('id')} ${chalk_1.default.dim(user.id)}`);
|
|
101
|
+
console.log(` ${chalk_1.default.dim('tipo')} ${user.isAdmin ? chalk_1.default.yellow('admin') : chalk_1.default.dim('user')}`);
|
|
102
|
+
ui_1.logger.blank();
|
|
109
103
|
}
|
|
110
104
|
catch (err) {
|
|
111
105
|
if (err?.response?.status === 401) {
|
|
112
|
-
ui_1.logger.error('
|
|
106
|
+
ui_1.logger.error('sessao expirada ou revogada · rode `nivo login` de novo');
|
|
113
107
|
}
|
|
114
108
|
else {
|
|
115
|
-
ui_1.logger.error(`
|
|
109
|
+
ui_1.logger.error(`falha ao buscar usuario: ${err.message}`);
|
|
116
110
|
}
|
|
117
111
|
}
|
|
118
112
|
}
|
package/dist/commands/link.js
CHANGED
|
@@ -8,35 +8,28 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
8
8
|
const os_1 = __importDefault(require("os"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
-
const ora_1 = __importDefault(require("ora"));
|
|
12
|
-
const form_data_1 = __importDefault(require("form-data"));
|
|
13
11
|
const adm_zip_1 = __importDefault(require("adm-zip"));
|
|
12
|
+
const form_data_1 = __importDefault(require("form-data"));
|
|
14
13
|
const api_1 = require("../api");
|
|
15
14
|
const config_1 = require("../config");
|
|
16
15
|
const ui_1 = require("../ui");
|
|
17
16
|
const CONFIG_FILE = '.nivo';
|
|
18
17
|
const IGNORED_NAMES = new Set([
|
|
19
|
-
'.git',
|
|
20
|
-
'.
|
|
21
|
-
'node_modules',
|
|
22
|
-
'.env',
|
|
23
|
-
'.env.local',
|
|
24
|
-
'.env.production',
|
|
25
|
-
'.env.development',
|
|
26
|
-
'.DS_Store',
|
|
18
|
+
'.git', '.next', 'node_modules',
|
|
19
|
+
'.env', '.env.local', '.env.production', '.env.development', '.DS_Store',
|
|
27
20
|
]);
|
|
28
|
-
const EXAMPLE_CONFIG = `{
|
|
29
|
-
"name": "
|
|
30
|
-
"projectId": "PROJECT_ID",
|
|
31
|
-
"sourceType": "zip",
|
|
32
|
-
"type": "site",
|
|
33
|
-
"buildSystem": "nivopack",
|
|
34
|
-
"runtime": "node20",
|
|
35
|
-
"installCmd": "npm install",
|
|
36
|
-
"buildCmd": "npm run build",
|
|
37
|
-
"startCmd": "npm start",
|
|
38
|
-
"ramMb": 256,
|
|
39
|
-
"subdomain": "
|
|
21
|
+
const EXAMPLE_CONFIG = `{
|
|
22
|
+
"name": "meu-app",
|
|
23
|
+
"projectId": "PROJECT_ID",
|
|
24
|
+
"sourceType": "zip",
|
|
25
|
+
"type": "site",
|
|
26
|
+
"buildSystem": "nivopack",
|
|
27
|
+
"runtime": "node20",
|
|
28
|
+
"installCmd": "npm install",
|
|
29
|
+
"buildCmd": "npm run build",
|
|
30
|
+
"startCmd": "npm start",
|
|
31
|
+
"ramMb": 256,
|
|
32
|
+
"subdomain": "meu-app"
|
|
40
33
|
}`;
|
|
41
34
|
function readConfig(configPath) {
|
|
42
35
|
if (!fs_1.default.existsSync(configPath))
|
|
@@ -68,9 +61,8 @@ function validateConfig(config) {
|
|
|
68
61
|
missing.push('type');
|
|
69
62
|
if (config.ramMb !== undefined && (!Number.isFinite(Number(config.ramMb)) || Number(config.ramMb) < 100))
|
|
70
63
|
missing.push('ramMb');
|
|
71
|
-
if (missing.length)
|
|
64
|
+
if (missing.length)
|
|
72
65
|
throw new Error(`.nivo incompleto ou invalido. Corrija: ${missing.join(', ')}`);
|
|
73
|
-
}
|
|
74
66
|
}
|
|
75
67
|
function cleanOptional(value) {
|
|
76
68
|
const trimmed = value?.trim();
|
|
@@ -109,10 +101,7 @@ function updatePayload(config) {
|
|
|
109
101
|
return payload;
|
|
110
102
|
}
|
|
111
103
|
function writeConfig(configPath, config) {
|
|
112
|
-
fs_1.default.writeFileSync(configPath, JSON.stringify({
|
|
113
|
-
...config,
|
|
114
|
-
linkedAt: new Date().toISOString(),
|
|
115
|
-
}, null, 2));
|
|
104
|
+
fs_1.default.writeFileSync(configPath, JSON.stringify({ ...config, linkedAt: new Date().toISOString() }, null, 2));
|
|
116
105
|
}
|
|
117
106
|
function addDir(zip, dir, root) {
|
|
118
107
|
for (const entry of fs_1.default.readdirSync(dir, { withFileTypes: true })) {
|
|
@@ -132,16 +121,15 @@ function createZip(sourceDir) {
|
|
|
132
121
|
const resolved = path_1.default.resolve(sourceDir);
|
|
133
122
|
const zip = new adm_zip_1.default();
|
|
134
123
|
addDir(zip, resolved, resolved);
|
|
135
|
-
const
|
|
136
|
-
zip.writeZip(
|
|
137
|
-
|
|
124
|
+
const zipPath = path_1.default.join(os_1.default.tmpdir(), `nivo-link-${Date.now()}.zip`);
|
|
125
|
+
zip.writeZip(zipPath);
|
|
126
|
+
const entries = zip.getEntries().length;
|
|
127
|
+
const sizeMb = (fs_1.default.statSync(zipPath).size / 1024 / 1024).toFixed(1);
|
|
128
|
+
return { zipPath, fileCount: entries, sizeMb };
|
|
138
129
|
}
|
|
139
130
|
async function uploadZipSource(appId, zipPath) {
|
|
140
131
|
const form = new form_data_1.default();
|
|
141
|
-
form.append('file', fs_1.default.createReadStream(zipPath), {
|
|
142
|
-
filename: 'app.zip',
|
|
143
|
-
contentType: 'application/zip',
|
|
144
|
-
});
|
|
132
|
+
form.append('file', fs_1.default.createReadStream(zipPath), { filename: 'app.zip', contentType: 'application/zip' });
|
|
145
133
|
await api_1.api.post(`/apps/${encodeURIComponent(appId)}/upload-source`, form, {
|
|
146
134
|
headers: form.getHeaders(),
|
|
147
135
|
maxBodyLength: Infinity,
|
|
@@ -150,75 +138,78 @@ async function uploadZipSource(appId, zipPath) {
|
|
|
150
138
|
}
|
|
151
139
|
async function link() {
|
|
152
140
|
if (!(0, config_1.getCredentials)().token) {
|
|
153
|
-
ui_1.logger.error('
|
|
141
|
+
ui_1.logger.error('nao autenticado · rode `nivo login`');
|
|
154
142
|
return;
|
|
155
143
|
}
|
|
144
|
+
ui_1.logger.blank();
|
|
156
145
|
const configPath = path_1.default.join(process.cwd(), CONFIG_FILE);
|
|
157
146
|
let config;
|
|
158
147
|
try {
|
|
159
|
-
|
|
160
|
-
if (!
|
|
161
|
-
ui_1.logger.error('
|
|
162
|
-
ui_1.logger.info('
|
|
163
|
-
|
|
164
|
-
console.log(chalk_1.default.
|
|
148
|
+
const raw = readConfig(configPath);
|
|
149
|
+
if (!raw) {
|
|
150
|
+
ui_1.logger.error('.nivo nao encontrado na pasta atual');
|
|
151
|
+
ui_1.logger.info('crie o arquivo .nivo e rode `nivo link` de novo');
|
|
152
|
+
ui_1.logger.blank();
|
|
153
|
+
console.log(chalk_1.default.dim(EXAMPLE_CONFIG));
|
|
165
154
|
return;
|
|
166
155
|
}
|
|
167
|
-
validateConfig(
|
|
156
|
+
validateConfig(raw);
|
|
157
|
+
config = raw;
|
|
168
158
|
}
|
|
169
159
|
catch (err) {
|
|
170
160
|
ui_1.logger.error(err.message);
|
|
171
|
-
|
|
172
|
-
console.log(chalk_1.default.
|
|
161
|
+
ui_1.logger.blank();
|
|
162
|
+
console.log(chalk_1.default.dim(EXAMPLE_CONFIG));
|
|
173
163
|
return;
|
|
174
164
|
}
|
|
175
|
-
|
|
165
|
+
ui_1.logger.success('autenticado');
|
|
166
|
+
ui_1.logger.success(`.nivo lido · ${chalk_1.default.bold(config.name ?? config.appId)} ${chalk_1.default.dim(`(${config.sourceType ?? 'zip'} · ${config.runtime ?? 'node20'})`)}`);
|
|
176
167
|
let zipPath = null;
|
|
177
168
|
try {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
169
|
+
const app = await (0, ui_1.runStep)(config.appId ? 'aplicando configuracao...' : 'criando app...', async () => {
|
|
170
|
+
if (config.appId) {
|
|
171
|
+
const payload = updatePayload(config);
|
|
172
|
+
if (Object.keys(payload).length) {
|
|
173
|
+
try {
|
|
174
|
+
return (await api_1.api.patch(`/apps/${encodeURIComponent(config.appId)}`, payload)).data;
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
if (err?.response?.status === 404)
|
|
178
|
+
throw new Error('appId do .nivo nao existe. Remova "appId" para criar um novo app.');
|
|
179
|
+
throw err;
|
|
180
|
+
}
|
|
185
181
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
182
|
+
else {
|
|
183
|
+
try {
|
|
184
|
+
return (await api_1.api.get(`/apps/${encodeURIComponent(config.appId)}`)).data;
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
if (err?.response?.status === 404)
|
|
188
|
+
throw new Error('appId do .nivo nao existe. Remova "appId" para criar um novo app.');
|
|
189
|
+
throw err;
|
|
189
190
|
}
|
|
190
|
-
throw err;
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
else {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
catch (err) {
|
|
199
|
-
if (err?.response?.status === 404) {
|
|
200
|
-
throw new Error('appId do .nivo nao existe. Remova "appId" do .nivo para criar um app novo, ou coloque o appId correto.');
|
|
201
|
-
}
|
|
202
|
-
throw err;
|
|
203
|
-
}
|
|
194
|
+
const res = await api_1.api.post('/apps', appPayload(config));
|
|
195
|
+
config.appId = res.data.id;
|
|
196
|
+
return res.data;
|
|
204
197
|
}
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
const res = await api_1.api.post('/apps', appPayload(config));
|
|
208
|
-
app = res.data;
|
|
209
|
-
config.appId = app.id;
|
|
210
|
-
}
|
|
198
|
+
}, (app) => `${config.appId ? 'configuracao aplicada' : 'app criado'} · ${chalk_1.default.dim(app.id)}`);
|
|
211
199
|
if ((config.sourceType ?? 'zip') === 'zip') {
|
|
212
|
-
|
|
213
|
-
zipPath =
|
|
214
|
-
await uploadZipSource(app.id,
|
|
200
|
+
const { zipPath: zp, fileCount, sizeMb } = await (0, ui_1.runStep)('compactando projeto...', async () => createZip(process.cwd()), ({ fileCount, sizeMb }) => `compactado · ${fileCount} arquivos · ${sizeMb} MB`);
|
|
201
|
+
zipPath = zp;
|
|
202
|
+
await (0, ui_1.runStep)('enviando codigo...', async () => uploadZipSource(app.id, zp), () => 'codigo enviado');
|
|
215
203
|
}
|
|
216
204
|
writeConfig(configPath, config);
|
|
217
|
-
|
|
218
|
-
ui_1.logger.
|
|
205
|
+
ui_1.logger.success('.nivo atualizado');
|
|
206
|
+
ui_1.logger.blank();
|
|
207
|
+
ui_1.logger.info('para fazer deploy: nivo deploy --watch');
|
|
208
|
+
ui_1.logger.blank();
|
|
219
209
|
}
|
|
220
210
|
catch (err) {
|
|
221
|
-
|
|
211
|
+
ui_1.logger.blank();
|
|
212
|
+
ui_1.logger.error(err.message);
|
|
222
213
|
}
|
|
223
214
|
finally {
|
|
224
215
|
if (zipPath)
|
package/dist/ui.js
CHANGED
|
@@ -5,16 +5,32 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.logger = void 0;
|
|
7
7
|
exports.printBanner = printBanner;
|
|
8
|
+
exports.runStep = runStep;
|
|
8
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
11
|
function printBanner() {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
console.log(
|
|
12
|
+
console.log();
|
|
13
|
+
console.log(' ' + chalk_1.default.bold.hex('#22c55e')('nivo') + chalk_1.default.dim(' platform cli'));
|
|
14
|
+
console.log();
|
|
13
15
|
}
|
|
14
16
|
exports.logger = {
|
|
15
|
-
success: (msg) => console.log(
|
|
16
|
-
error: (msg) => console.log(
|
|
17
|
-
info: (msg) => console.log(
|
|
18
|
-
warn: (msg) => console.log(
|
|
19
|
-
|
|
17
|
+
success: (msg) => console.log(` ${chalk_1.default.green('✓')} ${msg}`),
|
|
18
|
+
error: (msg) => console.log(` ${chalk_1.default.red('✗')} ${chalk_1.default.red(msg)}`),
|
|
19
|
+
info: (msg) => console.log(` ${chalk_1.default.dim('·')} ${chalk_1.default.dim(msg)}`),
|
|
20
|
+
warn: (msg) => console.log(` ${chalk_1.default.yellow('!')} ${chalk_1.default.yellow(msg)}`),
|
|
21
|
+
label: (msg) => console.log(`\n ${chalk_1.default.bold(msg)}`),
|
|
22
|
+
blank: () => console.log(),
|
|
23
|
+
rule: () => console.log(' ' + chalk_1.default.dim('─'.repeat(48))),
|
|
20
24
|
};
|
|
25
|
+
async function runStep(label, fn, done) {
|
|
26
|
+
const spinner = (0, ora_1.default)({ text: chalk_1.default.dim(label), color: 'green', indent: 2 }).start();
|
|
27
|
+
try {
|
|
28
|
+
const result = await fn(spinner);
|
|
29
|
+
spinner.succeed(done ? done(result) : label);
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
spinner.fail(chalk_1.default.dim(label));
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
}
|
package/package.json
CHANGED