smoonb 0.0.70 → 0.0.72
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/LICENSE.pt-BR.md +24 -0
- package/README.md +446 -352
- package/README.pt-BR.md +730 -0
- package/bin/smoonb.js +187 -128
- package/package.json +4 -2
- package/src/commands/backup/index.js +22 -13
- package/src/commands/backup/steps/06-storage.js +228 -5
- package/src/commands/backup/utils.js +25 -31
- package/src/commands/check.js +13 -8
- package/src/commands/config.js +142 -134
- package/src/commands/functions.js +14 -10
- package/src/commands/import.js +22 -19
- package/src/commands/restore/index.js +13 -12
- package/src/i18n/index.js +217 -0
- package/src/i18n/locales/en.json +251 -0
- package/src/i18n/locales/pt-BR.json +251 -0
- package/src/index.js +19 -18
- package/src/utils/banner.js +19 -16
- package/src/utils/prompt.js +4 -1
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const fs = require('fs').promises;
|
|
4
|
+
const AdmZip = require('adm-zip');
|
|
5
|
+
const { createClient } = require('@supabase/supabase-js');
|
|
3
6
|
const { ensureDir, writeJson } = require('../../../utils/fsx');
|
|
7
|
+
const { confirm } = require('../../../utils/prompt');
|
|
4
8
|
|
|
5
9
|
/**
|
|
6
10
|
* Etapa 6: Backup Storage via Supabase API
|
|
11
|
+
* Agora faz backup completo: metadados + download de todos os arquivos + ZIP no padrão do Dashboard
|
|
7
12
|
*/
|
|
8
|
-
module.exports = async ({ projectId, accessToken, backupDir }) => {
|
|
13
|
+
module.exports = async ({ projectId, accessToken, backupDir, supabaseUrl, supabaseServiceKey }) => {
|
|
9
14
|
try {
|
|
10
15
|
const storageDir = path.join(backupDir, 'storage');
|
|
11
16
|
await ensureDir(storageDir);
|
|
@@ -37,7 +42,25 @@ module.exports = async ({ projectId, accessToken, backupDir }) => {
|
|
|
37
42
|
|
|
38
43
|
console.log(chalk.white(` - Encontrados ${buckets.length} buckets`));
|
|
39
44
|
|
|
45
|
+
// Validar credenciais do Supabase para download de arquivos
|
|
46
|
+
if (!supabaseUrl || !supabaseServiceKey) {
|
|
47
|
+
console.log(chalk.yellow(' ⚠️ Credenciais do Supabase não disponíveis. Fazendo backup apenas de metadados...'));
|
|
48
|
+
return await backupMetadataOnly(buckets, storageDir, projectId, accessToken);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Criar cliente Supabase para download de arquivos
|
|
52
|
+
const supabase = createClient(supabaseUrl, supabaseServiceKey);
|
|
53
|
+
|
|
54
|
+
// Criar estrutura temporária para armazenar arquivos baixados
|
|
55
|
+
const tempStorageDir = path.join(backupDir, 'storage_temp');
|
|
56
|
+
await ensureDir(tempStorageDir);
|
|
57
|
+
|
|
58
|
+
// Criar estrutura: storage_temp/project-id/bucket-name/arquivos...
|
|
59
|
+
const projectStorageDir = path.join(tempStorageDir, projectId);
|
|
60
|
+
await ensureDir(projectStorageDir);
|
|
61
|
+
|
|
40
62
|
const processedBuckets = [];
|
|
63
|
+
let totalFilesDownloaded = 0;
|
|
41
64
|
|
|
42
65
|
for (const bucket of buckets || []) {
|
|
43
66
|
try {
|
|
@@ -69,22 +92,222 @@ module.exports = async ({ projectId, accessToken, backupDir }) => {
|
|
|
69
92
|
const bucketPath = path.join(storageDir, `${bucket.name}.json`);
|
|
70
93
|
await writeJson(bucketPath, bucketInfo);
|
|
71
94
|
|
|
95
|
+
// Baixar todos os arquivos do bucket
|
|
96
|
+
const bucketDir = path.join(projectStorageDir, bucket.name);
|
|
97
|
+
await ensureDir(bucketDir);
|
|
98
|
+
|
|
99
|
+
// Listar todos os arquivos recursivamente usando Supabase client
|
|
100
|
+
console.log(chalk.white(` - Listando arquivos do bucket ${bucket.name}...`));
|
|
101
|
+
const allFiles = await listAllFilesRecursively(supabase, bucket.name, '');
|
|
102
|
+
|
|
103
|
+
let filesDownloaded = 0;
|
|
104
|
+
if (allFiles.length > 0) {
|
|
105
|
+
console.log(chalk.white(` - Baixando ${allFiles.length} arquivo(s) do bucket ${bucket.name}...`));
|
|
106
|
+
|
|
107
|
+
for (const filePath of allFiles) {
|
|
108
|
+
try {
|
|
109
|
+
// Baixar arquivo do Storage
|
|
110
|
+
const { data: fileData, error: downloadError } = await supabase.storage
|
|
111
|
+
.from(bucket.name)
|
|
112
|
+
.download(filePath);
|
|
113
|
+
|
|
114
|
+
if (downloadError) {
|
|
115
|
+
console.log(chalk.yellow(` ⚠️ Erro ao baixar ${filePath}: ${downloadError.message}`));
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Criar estrutura de pastas local se necessário
|
|
120
|
+
const localFilePath = path.join(bucketDir, filePath);
|
|
121
|
+
const localFileDir = path.dirname(localFilePath);
|
|
122
|
+
await ensureDir(localFileDir);
|
|
123
|
+
|
|
124
|
+
// Salvar arquivo localmente
|
|
125
|
+
const arrayBuffer = await fileData.arrayBuffer();
|
|
126
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
127
|
+
await fs.writeFile(localFilePath, buffer);
|
|
128
|
+
filesDownloaded++;
|
|
129
|
+
|
|
130
|
+
// Mostrar progresso a cada 10 arquivos ou se for o último
|
|
131
|
+
if (filesDownloaded % 10 === 0 || filesDownloaded === allFiles.length) {
|
|
132
|
+
console.log(chalk.white(` - Baixados ${filesDownloaded}/${allFiles.length} arquivo(s)...`));
|
|
133
|
+
}
|
|
134
|
+
} catch (fileError) {
|
|
135
|
+
console.log(chalk.yellow(` ⚠️ Erro ao processar arquivo ${filePath}: ${fileError.message}`));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
totalFilesDownloaded += filesDownloaded;
|
|
72
141
|
processedBuckets.push({
|
|
73
142
|
name: bucket.name,
|
|
74
|
-
objectCount: objects?.length || 0
|
|
143
|
+
objectCount: objects?.length || 0,
|
|
144
|
+
filesDownloaded: filesDownloaded,
|
|
145
|
+
totalFiles: allFiles.length
|
|
75
146
|
});
|
|
76
147
|
|
|
77
|
-
console.log(chalk.green(` ✅ Bucket ${bucket.name}: ${
|
|
148
|
+
console.log(chalk.green(` ✅ Bucket ${bucket.name}: ${filesDownloaded}/${allFiles.length} arquivo(s) baixado(s)`));
|
|
78
149
|
} catch (error) {
|
|
79
150
|
console.log(chalk.yellow(` ⚠️ Erro ao processar bucket ${bucket.name}: ${error.message}`));
|
|
80
151
|
}
|
|
81
152
|
}
|
|
82
153
|
|
|
83
|
-
|
|
84
|
-
|
|
154
|
+
// Criar ZIP no padrão do Dashboard: {project-id}.storage.zip
|
|
155
|
+
console.log(chalk.white('\n - Criando arquivo ZIP no padrão do Dashboard...'));
|
|
156
|
+
const zipFileName = `${projectId}.storage.zip`;
|
|
157
|
+
const zipFilePath = path.join(backupDir, zipFileName);
|
|
158
|
+
|
|
159
|
+
const zip = new AdmZip();
|
|
160
|
+
|
|
161
|
+
// Adicionar toda a estrutura de pastas ao ZIP
|
|
162
|
+
// Estrutura: project-id/bucket-name/arquivos...
|
|
163
|
+
await addDirectoryToZip(zip, projectStorageDir, projectId);
|
|
164
|
+
|
|
165
|
+
// Salvar ZIP
|
|
166
|
+
zip.writeZip(zipFilePath);
|
|
167
|
+
const zipStats = await fs.stat(zipFilePath);
|
|
168
|
+
const zipSizeMB = (zipStats.size / (1024 * 1024)).toFixed(2);
|
|
169
|
+
|
|
170
|
+
console.log(chalk.green(` ✅ Arquivo ZIP criado: ${zipFileName} (${zipSizeMB} MB)`));
|
|
171
|
+
|
|
172
|
+
// Perguntar ao usuário se deseja limpar a estrutura temporária
|
|
173
|
+
const tempDirName = path.basename(tempStorageDir);
|
|
174
|
+
const shouldCleanup = await confirm(` Deseja limpar ${tempDirName} após o backup`, false);
|
|
175
|
+
|
|
176
|
+
if (shouldCleanup) {
|
|
177
|
+
console.log(chalk.white(` - Limpando estrutura temporária...`));
|
|
178
|
+
try {
|
|
179
|
+
await fs.rm(tempStorageDir, { recursive: true, force: true });
|
|
180
|
+
console.log(chalk.green(` ✅ Estrutura temporária removida`));
|
|
181
|
+
} catch (cleanupError) {
|
|
182
|
+
console.log(chalk.yellow(` ⚠️ Erro ao limpar estrutura temporária: ${cleanupError.message}`));
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
console.log(chalk.white(` ℹ️ Estrutura temporária mantida em: ${path.relative(process.cwd(), tempStorageDir)}`));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
console.log(chalk.green(`✅ Storage backupado: ${processedBuckets.length} buckets, ${totalFilesDownloaded} arquivo(s) baixado(s)`));
|
|
189
|
+
return {
|
|
190
|
+
success: true,
|
|
191
|
+
buckets: processedBuckets,
|
|
192
|
+
zipFile: zipFileName,
|
|
193
|
+
zipSizeMB: zipSizeMB,
|
|
194
|
+
totalFiles: totalFilesDownloaded,
|
|
195
|
+
tempDirCleaned: shouldCleanup
|
|
196
|
+
};
|
|
85
197
|
} catch (error) {
|
|
86
198
|
console.log(chalk.yellow(`⚠️ Erro no backup do Storage: ${error.message}`));
|
|
87
199
|
return { success: false, buckets: [] };
|
|
88
200
|
}
|
|
89
201
|
};
|
|
90
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Backup apenas de metadados (fallback quando não há credenciais do Supabase)
|
|
205
|
+
*/
|
|
206
|
+
async function backupMetadataOnly(buckets, storageDir, projectId, accessToken) {
|
|
207
|
+
const processedBuckets = [];
|
|
208
|
+
|
|
209
|
+
for (const bucket of buckets || []) {
|
|
210
|
+
try {
|
|
211
|
+
console.log(chalk.white(` - Processando bucket: ${bucket.name}`));
|
|
212
|
+
|
|
213
|
+
const objectsResponse = await fetch(`https://api.supabase.com/v1/projects/${projectId}/storage/buckets/${bucket.name}/objects`, {
|
|
214
|
+
headers: {
|
|
215
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
216
|
+
'Content-Type': 'application/json'
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
let objects = [];
|
|
221
|
+
if (objectsResponse.ok) {
|
|
222
|
+
objects = await objectsResponse.json();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const bucketInfo = {
|
|
226
|
+
id: bucket.id,
|
|
227
|
+
name: bucket.name,
|
|
228
|
+
public: bucket.public,
|
|
229
|
+
file_size_limit: bucket.file_size_limit,
|
|
230
|
+
allowed_mime_types: bucket.allowed_mime_types,
|
|
231
|
+
objects: objects || []
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const bucketPath = path.join(storageDir, `${bucket.name}.json`);
|
|
235
|
+
await writeJson(bucketPath, bucketInfo);
|
|
236
|
+
|
|
237
|
+
processedBuckets.push({
|
|
238
|
+
name: bucket.name,
|
|
239
|
+
objectCount: objects?.length || 0
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
console.log(chalk.green(` ✅ Bucket ${bucket.name}: ${objects?.length || 0} objetos`));
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.log(chalk.yellow(` ⚠️ Erro ao processar bucket ${bucket.name}: ${error.message}`));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
console.log(chalk.green(`✅ Storage backupado (apenas metadados): ${processedBuckets.length} buckets`));
|
|
249
|
+
return { success: true, buckets: processedBuckets };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Lista todos os arquivos recursivamente de um bucket do Storage
|
|
254
|
+
*/
|
|
255
|
+
async function listAllFilesRecursively(supabase, bucketName, folderPath = '') {
|
|
256
|
+
const allFiles = [];
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
// Listar arquivos e pastas no caminho atual
|
|
260
|
+
const { data: items, error } = await supabase.storage
|
|
261
|
+
.from(bucketName)
|
|
262
|
+
.list(folderPath, {
|
|
263
|
+
limit: 1000,
|
|
264
|
+
sortBy: { column: 'name', order: 'asc' }
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
if (error) {
|
|
268
|
+
console.log(chalk.yellow(` ⚠️ Erro ao listar ${folderPath || 'raiz'}: ${error.message}`));
|
|
269
|
+
return allFiles;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (!items || items.length === 0) {
|
|
273
|
+
return allFiles;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
for (const item of items) {
|
|
277
|
+
const itemPath = folderPath ? `${folderPath}/${item.name}` : item.name;
|
|
278
|
+
|
|
279
|
+
if (item.id === null) {
|
|
280
|
+
// É uma pasta, listar recursivamente
|
|
281
|
+
const subFiles = await listAllFilesRecursively(supabase, bucketName, itemPath);
|
|
282
|
+
allFiles.push(...subFiles);
|
|
283
|
+
} else {
|
|
284
|
+
// É um arquivo
|
|
285
|
+
allFiles.push(itemPath);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
} catch (error) {
|
|
289
|
+
console.log(chalk.yellow(` ⚠️ Erro ao processar ${folderPath || 'raiz'}: ${error.message}`));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return allFiles;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Adiciona um diretório recursivamente ao ZIP mantendo a estrutura de pastas
|
|
297
|
+
*/
|
|
298
|
+
async function addDirectoryToZip(zip, dirPath, basePath = '') {
|
|
299
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
300
|
+
|
|
301
|
+
for (const entry of entries) {
|
|
302
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
303
|
+
const zipPath = basePath ? `${basePath}/${entry.name}` : entry.name;
|
|
304
|
+
|
|
305
|
+
if (entry.isDirectory()) {
|
|
306
|
+
await addDirectoryToZip(zip, fullPath, zipPath);
|
|
307
|
+
} else {
|
|
308
|
+
const fileContent = await fs.readFile(fullPath);
|
|
309
|
+
zip.addFile(zipPath, fileContent);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
@@ -1,63 +1,57 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
+
const { t } = require('../../i18n');
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Função para mostrar mensagens educativas e encerrar elegantemente
|
|
5
6
|
*/
|
|
6
7
|
function showDockerMessagesAndExit(reason) {
|
|
8
|
+
const getT = global.smoonbI18n?.t || t;
|
|
9
|
+
|
|
7
10
|
console.log('');
|
|
8
11
|
|
|
9
12
|
switch (reason) {
|
|
10
13
|
case 'docker_not_installed':
|
|
11
|
-
console.log(chalk.red(
|
|
14
|
+
console.log(chalk.red(`❌ ${getT('docker.notInstalled')}`));
|
|
12
15
|
console.log('');
|
|
13
|
-
console.log(chalk.yellow(
|
|
14
|
-
console.log(chalk.yellow(
|
|
15
|
-
console.log(chalk.yellow(
|
|
16
|
-
console.log(chalk.yellow(
|
|
16
|
+
console.log(chalk.yellow(`📋 ${getT('docker.instructions')}`));
|
|
17
|
+
console.log(chalk.yellow(` 1. ${getT('docker.installDocker')}`));
|
|
18
|
+
console.log(chalk.yellow(` 2. ${getT('docker.runDocker')}`));
|
|
19
|
+
console.log(chalk.yellow(` 3. ${getT('docker.repeatCommand')}`));
|
|
17
20
|
console.log('');
|
|
18
|
-
console.log(chalk.blue('
|
|
21
|
+
console.log(chalk.blue(`🔗 ${getT('docker.download')}`));
|
|
19
22
|
console.log('');
|
|
20
|
-
console.log(chalk.gray(
|
|
21
|
-
console.log(chalk.gray(' - Database PostgreSQL'));
|
|
22
|
-
console.log(chalk.gray(' - Edge Functions'));
|
|
23
|
-
console.log(chalk.gray(' - Todos os componentes via Supabase CLI'));
|
|
23
|
+
console.log(chalk.gray(`💡 ${getT('docker.requiredComponents')}`));
|
|
24
24
|
break;
|
|
25
25
|
|
|
26
26
|
case 'docker_not_running':
|
|
27
|
-
console.log(chalk.red(
|
|
27
|
+
console.log(chalk.red(`❌ ${getT('docker.notRunning')}`));
|
|
28
28
|
console.log('');
|
|
29
|
-
console.log(chalk.yellow(
|
|
30
|
-
console.log(chalk.yellow(
|
|
31
|
-
console.log(chalk.yellow(
|
|
32
|
-
console.log(chalk.yellow(
|
|
29
|
+
console.log(chalk.yellow(`📋 ${getT('docker.instructions')}`));
|
|
30
|
+
console.log(chalk.yellow(` 1. ${getT('docker.runDocker')}`));
|
|
31
|
+
console.log(chalk.yellow(` 2. ${getT('docker.waitInitialization')}`));
|
|
32
|
+
console.log(chalk.yellow(` 3. ${getT('docker.repeatCommand')}`));
|
|
33
33
|
console.log('');
|
|
34
|
-
console.log(chalk.blue(
|
|
34
|
+
console.log(chalk.blue(`💡 ${getT('docker.tip')}`));
|
|
35
35
|
console.log('');
|
|
36
|
-
console.log(chalk.gray(
|
|
37
|
-
console.log(chalk.gray(' - Database PostgreSQL'));
|
|
38
|
-
console.log(chalk.gray(' - Edge Functions'));
|
|
39
|
-
console.log(chalk.gray(' - Todos os componentes via Supabase CLI'));
|
|
36
|
+
console.log(chalk.gray(`💡 ${getT('docker.requiredComponents')}`));
|
|
40
37
|
break;
|
|
41
38
|
|
|
42
39
|
case 'supabase_cli_not_found':
|
|
43
|
-
console.log(chalk.red(
|
|
40
|
+
console.log(chalk.red(`❌ ${getT('supabase.cliNotFound')}`));
|
|
44
41
|
console.log('');
|
|
45
|
-
console.log(chalk.yellow(
|
|
46
|
-
console.log(chalk.yellow(
|
|
47
|
-
console.log(chalk.yellow(
|
|
42
|
+
console.log(chalk.yellow(`📋 ${getT('supabase.installInstructions')}`));
|
|
43
|
+
console.log(chalk.yellow(` 1. ${getT('supabase.installCli')}`));
|
|
44
|
+
console.log(chalk.yellow(` 2. ${getT('supabase.repeatCommand')}`));
|
|
48
45
|
console.log('');
|
|
49
|
-
console.log(chalk.blue('
|
|
46
|
+
console.log(chalk.blue(`🔗 ${getT('supabase.installLink')}`));
|
|
50
47
|
console.log('');
|
|
51
|
-
console.log(chalk.gray(
|
|
52
|
-
console.log(chalk.gray(' - Database PostgreSQL'));
|
|
53
|
-
console.log(chalk.gray(' - Edge Functions'));
|
|
54
|
-
console.log(chalk.gray(' - Todos os componentes via Docker'));
|
|
48
|
+
console.log(chalk.gray(`💡 ${getT('supabase.requiredComponents')}`));
|
|
55
49
|
break;
|
|
56
50
|
}
|
|
57
51
|
|
|
58
52
|
console.log('');
|
|
59
|
-
console.log(chalk.red(
|
|
60
|
-
console.log(chalk.gray(
|
|
53
|
+
console.log(chalk.red(`🚫 ${getT('docker.cancelled')}`));
|
|
54
|
+
console.log(chalk.gray(` ${getT('docker.installComponents')}`));
|
|
61
55
|
console.log('');
|
|
62
56
|
|
|
63
57
|
process.exit(1);
|
package/src/commands/check.js
CHANGED
|
@@ -5,17 +5,20 @@ const { readConfig, validateFor } = require('../utils/config');
|
|
|
5
5
|
const { writeJson } = require('../utils/fsx');
|
|
6
6
|
const { IntrospectionService } = require('../services/introspect');
|
|
7
7
|
const { showBetaBanner } = require('../utils/banner');
|
|
8
|
+
const { t } = require('../i18n');
|
|
8
9
|
|
|
9
10
|
// Exportar FUNÇÃO em vez de objeto Command
|
|
10
11
|
module.exports = async () => {
|
|
11
12
|
showBetaBanner();
|
|
12
13
|
|
|
13
14
|
try {
|
|
15
|
+
const getT = global.smoonbI18n?.t || t;
|
|
16
|
+
|
|
14
17
|
// Verificar se psql está disponível
|
|
15
18
|
const psqlPath = await ensureBin('psql');
|
|
16
19
|
if (!psqlPath) {
|
|
17
|
-
console.error(chalk.red(
|
|
18
|
-
console.log(chalk.yellow(
|
|
20
|
+
console.error(chalk.red(`❌ ${getT('check.psqlNotFound')}`));
|
|
21
|
+
console.log(chalk.yellow(`💡 ${getT('check.installPostgres')}`));
|
|
19
22
|
console.log(chalk.yellow(' https://www.postgresql.org/download/'));
|
|
20
23
|
process.exit(1);
|
|
21
24
|
}
|
|
@@ -26,12 +29,12 @@ module.exports = async () => {
|
|
|
26
29
|
|
|
27
30
|
const databaseUrl = config.supabase.databaseUrl;
|
|
28
31
|
if (!databaseUrl) {
|
|
29
|
-
console.error(chalk.red(
|
|
30
|
-
console.log(chalk.yellow('
|
|
32
|
+
console.error(chalk.red(`❌ ${getT('check.databaseUrlNotConfigured')}`));
|
|
33
|
+
console.log(chalk.yellow(`💡 ${getT('check.configureDatabaseUrl')}`));
|
|
31
34
|
process.exit(1);
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
console.log(chalk.blue(`🔍
|
|
37
|
+
console.log(chalk.blue(`🔍 ${getT('check.start', { projectId: config.supabase.projectId })}`));
|
|
35
38
|
|
|
36
39
|
// Executar verificações
|
|
37
40
|
const report = await performChecks(config, databaseUrl);
|
|
@@ -43,11 +46,13 @@ module.exports = async () => {
|
|
|
43
46
|
// Mostrar resumo
|
|
44
47
|
showCheckSummary(report);
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
console.log(chalk.
|
|
49
|
+
const getT = global.smoonbI18n?.t || t;
|
|
50
|
+
console.log(chalk.green(`\n🎉 ${getT('check.done')}`));
|
|
51
|
+
console.log(chalk.blue(`📋 ${getT('check.reportSaved', { path: reportPath })}`));
|
|
48
52
|
|
|
49
53
|
} catch (error) {
|
|
50
|
-
|
|
54
|
+
const getT = global.smoonbI18n?.t || t;
|
|
55
|
+
console.error(chalk.red(`❌ ${getT('check.error', { message: error.message })}`));
|
|
51
56
|
process.exit(1);
|
|
52
57
|
}
|
|
53
58
|
};
|