smoonb 0.0.74 → 0.0.76

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 (29) hide show
  1. package/package.json +1 -1
  2. package/src/commands/backup/index.js +62 -65
  3. package/src/commands/backup/steps/00-docker-validation.js +6 -4
  4. package/src/commands/backup/steps/01-database.js +8 -4
  5. package/src/commands/backup/steps/02-database-separated.js +11 -8
  6. package/src/commands/backup/steps/03-database-settings.js +8 -4
  7. package/src/commands/backup/steps/04-auth-settings.js +6 -3
  8. package/src/commands/backup/steps/05-realtime-settings.js +5 -2
  9. package/src/commands/backup/steps/06-storage.js +29 -26
  10. package/src/commands/backup/steps/07-custom-roles.js +6 -3
  11. package/src/commands/backup/steps/08-edge-functions.js +15 -11
  12. package/src/commands/backup/steps/09-supabase-temp.js +9 -6
  13. package/src/commands/backup/steps/10-migrations.js +14 -10
  14. package/src/commands/check.js +5 -3
  15. package/src/commands/restore/index.js +51 -46
  16. package/src/commands/restore/steps/00-backup-selection.js +6 -4
  17. package/src/commands/restore/steps/01-components-selection.js +30 -28
  18. package/src/commands/restore/steps/03-database.js +21 -17
  19. package/src/commands/restore/steps/04-edge-functions.js +16 -13
  20. package/src/commands/restore/steps/05-auth-settings.js +10 -7
  21. package/src/commands/restore/steps/06-storage.js +50 -42
  22. package/src/commands/restore/steps/07-database-settings.js +10 -7
  23. package/src/commands/restore/steps/08-realtime-settings.js +10 -7
  24. package/src/commands/restore/utils.js +15 -13
  25. package/src/i18n/locales/en.json +427 -1
  26. package/src/i18n/locales/pt-BR.json +426 -1
  27. package/src/interactive/envMapper.js +30 -25
  28. package/src/utils/realtime-settings.js +15 -9
  29. package/src/utils/supabaseLink.js +11 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smoonb",
3
- "version": "0.0.74",
3
+ "version": "0.0.76",
4
4
  "description": "Complete Supabase backup and migration tool - EXPERIMENTAL VERSION - USE AT YOUR OWN RISK",
5
5
  "preferGlobal": false,
6
6
  "preventGlobalInstall": true,
@@ -79,10 +79,10 @@ module.exports = async (options) => {
79
79
  try {
80
80
  await fs.access(envPath);
81
81
  await backupEnvFile(envPath, envBackupPath);
82
- console.log(chalk.blue(`📁 Backup do .env.local: ${path.relative(process.cwd(), envBackupPath)}`));
82
+ console.log(chalk.blue(`📁 ${getT('env.mapping.backupCreated', { path: path.relative(process.cwd(), envBackupPath) })}`));
83
83
  } catch {
84
84
  // Arquivo não existe, não fazer backup
85
- console.log(chalk.yellow('⚠️ Arquivo .env.local não encontrado. Será criado durante o mapeamento.'));
85
+ console.log(chalk.yellow(`⚠️ ${getT('env.mapping.fileNotFound')}`));
86
86
  }
87
87
 
88
88
  const expectedKeys = [
@@ -98,7 +98,7 @@ module.exports = async (options) => {
98
98
  const { finalEnv, dePara } = await mapEnvVariablesInteractively(currentEnv, expectedKeys);
99
99
  await writeEnvFile(envPath, finalEnv);
100
100
  await saveEnvMap(dePara, path.join(backupDir, 'env', 'env-map.json'));
101
- console.log(chalk.green('✅ .env.local atualizado com sucesso. Nenhuma chave renomeada; valores sincronizados.'));
101
+ console.log(chalk.green(`✅ ${getT('env.mapping.updated')}`));
102
102
 
103
103
  function getValue(expectedKey) {
104
104
  const clientKey = Object.keys(dePara).find(k => dePara[k] === expectedKey);
@@ -124,33 +124,33 @@ module.exports = async (options) => {
124
124
  const supabaseServiceKey = getValue('SUPABASE_SERVICE_ROLE_KEY');
125
125
 
126
126
  if (!databaseUrl) {
127
- console.log(chalk.red('❌ DATABASE_URL NÃO CONFIGURADA'));
127
+ console.log(chalk.red(`❌ ${getT('backup.error.databaseUrlNotConfigured')}`));
128
128
  console.log('');
129
- console.log(chalk.yellow('📋 Para fazer backup completo do Supabase, você precisa:'));
130
- console.log(chalk.yellow(' 1. Configurar SUPABASE_DB_URL no .env.local'));
131
- console.log(chalk.yellow(' 2. Repetir o comando de backup'));
129
+ console.log(chalk.yellow(`📋 ${getT('backup.error.databaseUrlInstructions')}`));
130
+ console.log(chalk.yellow(` 1. ${getT('backup.error.databaseUrlStep1')}`));
131
+ console.log(chalk.yellow(` 2. ${getT('backup.error.databaseUrlStep2')}`));
132
132
  console.log('');
133
- console.log(chalk.blue('💡 Exemplo de configuração:'));
134
- console.log(chalk.gray(' "databaseUrl": "postgresql://postgres:[senha]@db.[projeto].supabase.co:5432/postgres"'));
133
+ console.log(chalk.blue(`💡 ${getT('backup.error.databaseUrlExample')}:`));
134
+ console.log(chalk.gray(` ${getT('backup.error.databaseUrlExampleValue')}`));
135
135
  console.log('');
136
- console.log(chalk.red('🚫 Backup cancelado - Configuração incompleta'));
136
+ console.log(chalk.red(`🚫 ${getT('backup.error.databaseUrlCancelled')}`));
137
137
  process.exit(1);
138
138
  }
139
139
 
140
140
  if (!accessToken) {
141
- console.log(chalk.red('❌ ACCESS_TOKEN NÃO CONFIGURADO'));
141
+ console.log(chalk.red(`❌ ${getT('backup.error.accessTokenNotConfigured')}`));
142
142
  console.log('');
143
- console.log(chalk.yellow('📋 Para fazer backup completo do Supabase, você precisa:'));
144
- console.log(chalk.yellow(' 1. Obter Personal Access Token do Supabase'));
145
- console.log(chalk.yellow(' 2. Configurar SUPABASE_ACCESS_TOKEN no .env.local'));
146
- console.log(chalk.yellow(' 3. Repetir o comando de backup'));
143
+ console.log(chalk.yellow(`📋 ${getT('backup.error.accessTokenInstructions')}`));
144
+ console.log(chalk.yellow(` 1. ${getT('backup.error.accessTokenStep1')}`));
145
+ console.log(chalk.yellow(` 2. ${getT('backup.error.accessTokenStep2')}`));
146
+ console.log(chalk.yellow(` 3. ${getT('backup.error.accessTokenStep3')}`));
147
147
  console.log('');
148
- console.log(chalk.blue('🔗 Como obter o token:'));
149
- console.log(chalk.gray(' 1. Acesse: https://supabase.com/dashboard/account/tokens'));
150
- console.log(chalk.gray(' 2. Clique: "Generate new token"'));
151
- console.log(chalk.gray(' 3. Copie o token (formato: sbp_...)'));
148
+ console.log(chalk.blue(`🔗 ${getT('backup.error.accessTokenHowTo')}:`));
149
+ console.log(chalk.gray(` ${getT('backup.error.accessTokenStep1Detail')}`));
150
+ console.log(chalk.gray(` ${getT('backup.error.accessTokenStep2Detail')}`));
151
+ console.log(chalk.gray(` ${getT('backup.error.accessTokenStep3Detail')}`));
152
152
  console.log('');
153
- console.log(chalk.red('🚫 Backup cancelado - Token não configurado'));
153
+ console.log(chalk.red(`🚫 ${getT('backup.error.accessTokenCancelled')}`));
154
154
  process.exit(1);
155
155
  }
156
156
 
@@ -158,32 +158,32 @@ module.exports = async (options) => {
158
158
  const flags = await askComponentsFlags();
159
159
 
160
160
  // Mostrar resumo e pedir confirmação final
161
- console.log(chalk.cyan('\n📋 RESUMO DAS CONFIGURAÇÕES:\n'));
162
- console.log(chalk.white(` ✅ Edge Functions: ${flags.includeFunctions ? 'Sim' : 'Não'}`));
161
+ console.log(chalk.cyan(`\n📋 ${getT('backup.summary.title')}\n`));
162
+ console.log(chalk.white(` ✅ ${getT('backup.summary.edgeFunctions', { value: flags.includeFunctions ? getT('backup.summary.yes') : getT('backup.summary.no') })}`));
163
163
  if (flags.includeFunctions) {
164
- console.log(chalk.white(` 🗑️ Limpar após backup: ${flags.cleanFunctions ? 'Sim' : 'Não'}`));
164
+ console.log(chalk.white(` 🗑️ ${getT('backup.summary.edgeFunctionsCleanup', { value: flags.cleanFunctions ? getT('backup.summary.yes') : getT('backup.summary.no') })}`));
165
165
  }
166
- console.log(chalk.white(` ✅ Supabase .temp: ${flags.includeTemp ? 'Sim' : 'Não'}`));
166
+ console.log(chalk.white(` ✅ ${getT('backup.summary.temp', { value: flags.includeTemp ? getT('backup.summary.yes') : getT('backup.summary.no') })}`));
167
167
  if (flags.includeTemp) {
168
- console.log(chalk.white(` 🗑️ Apagar após backup: ${flags.cleanTemp ? 'Sim' : 'Não'}`));
168
+ console.log(chalk.white(` 🗑️ ${getT('backup.summary.tempCleanup', { value: flags.cleanTemp ? getT('backup.summary.yes') : getT('backup.summary.no') })}`));
169
169
  }
170
- console.log(chalk.white(` ✅ Migrations: ${flags.includeMigrations ? 'Sim' : 'Não'}`));
170
+ console.log(chalk.white(` ✅ ${getT('backup.summary.migrations', { value: flags.includeMigrations ? getT('backup.summary.yes') : getT('backup.summary.no') })}`));
171
171
  if (flags.includeMigrations) {
172
- console.log(chalk.white(` 🗑️ Apagar após backup: ${flags.cleanMigrations ? 'Sim' : 'Não'}`));
172
+ console.log(chalk.white(` 🗑️ ${getT('backup.summary.migrationsCleanup', { value: flags.cleanMigrations ? getT('backup.summary.yes') : getT('backup.summary.no') })}`));
173
173
  }
174
- console.log(chalk.white(` ✅ Storage: ${flags.includeStorage ? 'Sim' : 'Não'}`));
175
- console.log(chalk.white(` ✅ Auth: ${flags.includeAuth ? 'Sim' : 'Não'}`));
176
- console.log(chalk.white(` ✅ Realtime: ${flags.includeRealtime ? 'Sim' : 'Não'}`));
177
- console.log(chalk.white(` 📁 Diretório de backup: ${finalBackupDir}\n`));
174
+ console.log(chalk.white(` ✅ ${getT('backup.summary.storage', { value: flags.includeStorage ? getT('backup.summary.yes') : getT('backup.summary.no') })}`));
175
+ console.log(chalk.white(` ✅ ${getT('backup.summary.auth', { value: flags.includeAuth ? getT('backup.summary.yes') : getT('backup.summary.no') })}`));
176
+ console.log(chalk.white(` ✅ ${getT('backup.summary.realtime', { value: flags.includeRealtime ? getT('backup.summary.yes') : getT('backup.summary.no') })}`));
177
+ console.log(chalk.white(` 📁 ${getT('backup.summary.backupDir', { path: finalBackupDir })}\n`));
178
178
 
179
- const finalOk = await confirm('Deseja iniciar o backup com estas configurações?', true);
179
+ const finalOk = await confirm(getT('backup.summary.confirm'), true);
180
180
 
181
181
  if (!finalOk) {
182
- console.log(chalk.red('🚫 Operação cancelada pelo usuário.'));
182
+ console.log(chalk.red(`🚫 ${getT('disclaimer.operationCancelled')}`));
183
183
  process.exit(1);
184
184
  }
185
185
 
186
- console.log(chalk.blue(`\n🚀 Iniciando backup do projeto: ${projectId}`));
186
+ console.log(chalk.blue(`\n🚀 ${getT('backup.start.title', { projectId })}`));
187
187
 
188
188
  // Criar contexto compartilhado para as etapas
189
189
  const context = {
@@ -214,8 +214,8 @@ module.exports = async (options) => {
214
214
  };
215
215
 
216
216
  // Executar todas as etapas na ordem
217
- console.log(chalk.blue(`📁 Diretório: ${finalBackupDir}`));
218
- console.log(chalk.white(`🐳 Backup via Docker Desktop`));
217
+ console.log(chalk.blue(`📁 ${getT('backup.start.directory', { path: finalBackupDir })}`));
218
+ console.log(chalk.white(`🐳 ${getT('backup.start.docker')}`));
219
219
 
220
220
  // Contar etapas totais para numeração
221
221
  // Etapas fixas: Database, Database Separado, Database Settings, Custom Roles (4)
@@ -225,13 +225,13 @@ module.exports = async (options) => {
225
225
 
226
226
  // 1. Backup Database via pg_dumpall Docker
227
227
  stepNumber++;
228
- console.log(chalk.blue(`\n📊 ${stepNumber}/${totalSteps} - Backup da Database PostgreSQL via pg_dumpall Docker...`));
228
+ console.log(chalk.blue(`\n📊 ${stepNumber}/${totalSteps} - ${getT('backup.steps.database.title')}`));
229
229
  const databaseResult = await step01Database(context);
230
230
  manifest.components.database = databaseResult;
231
231
 
232
232
  // 2. Backup Database Separado
233
233
  stepNumber++;
234
- console.log(chalk.blue(`\n📊 ${stepNumber}/${totalSteps} - Backup da Database PostgreSQL (arquivos SQL separados)...`));
234
+ console.log(chalk.blue(`\n📊 ${stepNumber}/${totalSteps} - ${getT('backup.steps.database.separated.title')}`));
235
235
  const dbSeparatedResult = await step02DatabaseSeparated(context);
236
236
  manifest.components.database_separated = {
237
237
  success: dbSeparatedResult.success,
@@ -242,14 +242,14 @@ module.exports = async (options) => {
242
242
 
243
243
  // 3. Backup Database Settings
244
244
  stepNumber++;
245
- console.log(chalk.blue(`\n🔧 ${stepNumber}/${totalSteps} - Backup das Database Extensions and Settings via SQL...`));
245
+ console.log(chalk.blue(`\n🔧 ${stepNumber}/${totalSteps} - ${getT('backup.steps.databaseSettings.title')}`));
246
246
  const databaseSettingsResult = await step03DatabaseSettings(context);
247
247
  manifest.components.database_settings = databaseSettingsResult;
248
248
 
249
249
  // 4. Backup Auth Settings
250
250
  if (flags?.includeAuth) {
251
251
  stepNumber++;
252
- console.log(chalk.blue(`\n🔐 ${stepNumber}/${totalSteps} - Backup das Auth Settings via API...`));
252
+ console.log(chalk.blue(`\n🔐 ${stepNumber}/${totalSteps} - ${getT('backup.steps.auth.title')}`));
253
253
  const authResult = await step04AuthSettings(context);
254
254
  manifest.components.auth_settings = authResult;
255
255
  }
@@ -257,7 +257,7 @@ module.exports = async (options) => {
257
257
  // 5. Backup Realtime Settings
258
258
  if (flags?.includeRealtime) {
259
259
  stepNumber++;
260
- console.log(chalk.blue(`\n🔄 ${stepNumber}/${totalSteps} - Backup das Realtime Settings via Captura Interativa...`));
260
+ console.log(chalk.blue(`\n🔄 ${stepNumber}/${totalSteps} - ${getT('backup.steps.realtime.title')}`));
261
261
  const realtimeResult = await step05RealtimeSettings(context);
262
262
  manifest.components.realtime = realtimeResult;
263
263
  }
@@ -265,21 +265,21 @@ module.exports = async (options) => {
265
265
  // 6. Backup Storage
266
266
  if (flags?.includeStorage) {
267
267
  stepNumber++;
268
- console.log(chalk.blue(`\n📦 ${stepNumber}/${totalSteps} - Backup do Storage via API...`));
268
+ console.log(chalk.blue(`\n📦 ${stepNumber}/${totalSteps} - ${getT('backup.steps.storage.title')}`));
269
269
  const storageResult = await step06Storage(context);
270
270
  manifest.components.storage = storageResult;
271
271
  }
272
272
 
273
273
  // 7. Backup Custom Roles
274
274
  stepNumber++;
275
- console.log(chalk.blue(`\n👥 ${stepNumber}/${totalSteps} - Backup dos Custom Roles via SQL...`));
275
+ console.log(chalk.blue(`\n👥 ${stepNumber}/${totalSteps} - ${getT('backup.steps.roles.title')}`));
276
276
  const rolesResult = await step07CustomRoles(context);
277
277
  manifest.components.custom_roles = rolesResult;
278
278
 
279
279
  // 8. Backup Edge Functions
280
280
  if (flags?.includeFunctions) {
281
281
  stepNumber++;
282
- console.log(chalk.blue(`\n⚡ ${stepNumber}/${totalSteps} - Backup das Edge Functions via Docker...`));
282
+ console.log(chalk.blue(`\n⚡ ${stepNumber}/${totalSteps} - ${getT('backup.steps.functions.title')}`));
283
283
  const functionsResult = await step08EdgeFunctions(context);
284
284
  manifest.components.edge_functions = functionsResult;
285
285
  }
@@ -287,7 +287,7 @@ module.exports = async (options) => {
287
287
  // 9. Backup Supabase .temp
288
288
  if (flags?.includeTemp) {
289
289
  stepNumber++;
290
- console.log(chalk.blue(`\n📁 ${stepNumber}/${totalSteps} - Backup do Supabase .temp...`));
290
+ console.log(chalk.blue(`\n📁 ${stepNumber}/${totalSteps} - ${getT('backup.steps.temp.title')}`));
291
291
  const supabaseTempResult = await step09SupabaseTemp(context);
292
292
  manifest.components.supabase_temp = supabaseTempResult;
293
293
  }
@@ -295,7 +295,7 @@ module.exports = async (options) => {
295
295
  // 10. Backup Migrations
296
296
  if (flags?.includeMigrations) {
297
297
  stepNumber++;
298
- console.log(chalk.blue(`\n📋 ${stepNumber}/${totalSteps} - Backup das Migrations...`));
298
+ console.log(chalk.blue(`\n📋 ${stepNumber}/${totalSteps} - ${getT('backup.steps.migrations.title')}`));
299
299
  const migrationsResult = await step10Migrations(context);
300
300
  manifest.components.migrations = migrationsResult;
301
301
  }
@@ -304,27 +304,24 @@ module.exports = async (options) => {
304
304
  await writeJson(path.join(finalBackupDir, 'backup-manifest.json'), manifest);
305
305
 
306
306
  // Exibir resumo final (na ordem de captura)
307
- console.log(chalk.green('\n🎉 BACKUP COMPLETO FINALIZADO VIA DOCKER!'));
308
- console.log(chalk.blue(`📁 Localização: ${finalBackupDir}`));
309
- console.log(chalk.green(`📊 Database: ${databaseResult.fileName} (${databaseResult.size} KB) - Idêntico ao Dashboard`));
310
- console.log(chalk.green(`📊 Database SQL: ${dbSeparatedResult.files?.length || 0} arquivos separados (${dbSeparatedResult.totalSizeKB} KB) - Para troubleshooting`));
311
- console.log(chalk.green(`🔧 Database Settings: ${databaseSettingsResult.fileName} (${databaseSettingsResult.size} KB) - Extensions e Configurações`));
307
+ console.log(chalk.green(`\n🎉 ${getT('backup.complete.title')}`));
308
+ console.log(chalk.blue(`📁 ${getT('backup.complete.location', { path: finalBackupDir })}`));
309
+ console.log(chalk.green(`📊 ${getT('backup.complete.database', { fileName: databaseResult.fileName, size: `${databaseResult.size} KB` })}`));
310
+ console.log(chalk.green(`📊 ${getT('backup.complete.databaseSql', { count: dbSeparatedResult.files?.length || 0, size: `${dbSeparatedResult.totalSizeKB} KB` })}`));
311
+ console.log(chalk.green(`🔧 ${getT('backup.complete.databaseSettings', { fileName: databaseSettingsResult.fileName, size: `${databaseSettingsResult.size} KB` })}`));
312
312
 
313
313
  if (flags?.includeAuth && manifest.components.auth_settings) {
314
- const authResult = manifest.components.auth_settings;
315
- console.log(chalk.green(`🔐 Auth Settings: ${authResult.success ? 'Exportadas via API' : 'Falharam'}`));
314
+ console.log(chalk.green(`🔐 ${getT('backup.complete.auth')}`));
316
315
  }
317
316
 
318
317
  // Determinar mensagem correta baseada no método usado
319
318
  if (flags?.includeRealtime && manifest.components.realtime) {
320
319
  const realtimeResult = manifest.components.realtime;
321
- let realtimeMessage = 'Falharam';
322
- if (realtimeResult.success) {
323
- if (options.skipRealtime) {
324
- realtimeMessage = 'Configurações copiadas do backup anterior';
325
- } else {
326
- realtimeMessage = 'Configurações capturadas interativamente';
327
- }
320
+ let realtimeMessage = getT('backup.complete.realtime');
321
+ if (!realtimeResult.success) {
322
+ realtimeMessage = 'Falharam';
323
+ } else if (options.skipRealtime) {
324
+ realtimeMessage = 'Configurações copiadas do backup anterior';
328
325
  }
329
326
  console.log(chalk.green(`🔄 Realtime: ${realtimeMessage}`));
330
327
  }
@@ -332,27 +329,27 @@ module.exports = async (options) => {
332
329
  if (flags?.includeStorage && manifest.components.storage) {
333
330
  const storageResult = manifest.components.storage;
334
331
  if (storageResult.zipFile) {
335
- console.log(chalk.green(`📦 Storage: ${storageResult.buckets?.length || 0} buckets, ${storageResult.totalFiles || 0} arquivo(s) baixado(s), ZIP: ${storageResult.zipFile} (${storageResult.zipSizeMB || 0} MB)`));
332
+ console.log(chalk.green(`📦 ${getT('backup.complete.storage', { buckets: storageResult.buckets?.length || 0, files: storageResult.totalFiles || 0, zipFile: storageResult.zipFile, size: `${storageResult.zipSizeMB || 0} MB` })}`));
336
333
  } else {
337
334
  console.log(chalk.green(`📦 Storage: ${storageResult.buckets?.length || 0} buckets verificados via API (apenas metadados)`));
338
335
  }
339
336
  }
340
337
 
341
- console.log(chalk.green(`👥 Custom Roles: ${rolesResult.roles?.length || 0} roles exportados via SQL`));
338
+ console.log(chalk.green(`👥 ${getT('backup.complete.roles', { count: rolesResult.roles?.length || 0 })}`));
342
339
 
343
340
  if (flags?.includeFunctions && manifest.components.edge_functions) {
344
341
  const functionsResult = manifest.components.edge_functions;
345
- console.log(chalk.green(`⚡ Edge Functions: ${functionsResult.success_count || 0}/${functionsResult.functions_count || 0} functions baixadas via Docker`));
342
+ console.log(chalk.green(`⚡ ${getT('backup.complete.functions', { downloaded: functionsResult.success_count || 0, total: functionsResult.functions_count || 0 })}`));
346
343
  }
347
344
 
348
345
  if (flags?.includeTemp && manifest.components.supabase_temp) {
349
346
  const tempResult = manifest.components.supabase_temp;
350
- console.log(chalk.green(`📁 Supabase .temp: ${tempResult.file_count || 0} arquivo(s) copiado(s)`));
347
+ console.log(chalk.green(`📁 ${getT('backup.complete.temp', { count: tempResult.file_count || 0 })}`));
351
348
  }
352
349
 
353
350
  if (flags?.includeMigrations && manifest.components.migrations) {
354
351
  const migrationsResult = manifest.components.migrations;
355
- console.log(chalk.green(`📋 Migrations: ${migrationsResult.file_count || 0} migration(s) copiada(s)`));
352
+ console.log(chalk.green(`📋 ${getT('backup.complete.migrations', { count: migrationsResult.file_count || 0 })}`));
356
353
  }
357
354
 
358
355
  // report.json
@@ -1,14 +1,16 @@
1
1
  const chalk = require('chalk');
2
2
  const { canPerformCompleteBackup } = require('../../../utils/docker');
3
3
  const { showDockerMessagesAndExit } = require('../utils');
4
+ const { t } = require('../../../i18n');
4
5
 
5
6
  /**
6
7
  * Etapa 0: Validação Docker
7
8
  * Deve ocorrer antes de tudo
8
9
  */
9
10
  module.exports = async () => {
10
- console.log(chalk.blue('\n🐳 Validação Docker...'));
11
- console.log(chalk.cyan('🔍 Verificando dependências Docker...'));
11
+ const getT = global.smoonbI18n?.t || t;
12
+ console.log(chalk.blue(`\n🐳 ${getT('docker.validation.title')}`));
13
+ console.log(chalk.cyan(`🔍 ${getT('docker.validation.checking')}`));
12
14
 
13
15
  const backupCapability = await canPerformCompleteBackup();
14
16
 
@@ -16,8 +18,8 @@ module.exports = async () => {
16
18
  showDockerMessagesAndExit(backupCapability.reason);
17
19
  }
18
20
 
19
- console.log(chalk.green('✅ Docker Desktop detectado e funcionando'));
20
- console.log(chalk.white(`🐳 Versão: ${backupCapability.dockerStatus.version}`));
21
+ console.log(chalk.green(`✅ ${getT('docker.validation.detected')}`));
22
+ console.log(chalk.white(`🐳 ${getT('docker.validation.version', { version: backupCapability.dockerStatus.version })}`));
21
23
 
22
24
  return { success: true };
23
25
  };
@@ -2,19 +2,22 @@ const chalk = require('chalk');
2
2
  const path = require('path');
3
3
  const fs = require('fs').promises;
4
4
  const { execSync } = require('child_process');
5
+ const { t } = require('../../../i18n');
5
6
 
6
7
  /**
7
8
  * Etapa 1: Backup Database via pg_dumpall Docker (idêntico ao Dashboard)
8
9
  */
9
10
  module.exports = async ({ databaseUrl, backupDir }) => {
10
11
  try {
11
- console.log(chalk.white(' - Criando backup completo via pg_dumpall...'));
12
+ const getT = global.smoonbI18n?.t || t;
13
+ console.log(chalk.white(` - ${getT('backup.steps.database.creating')}`));
12
14
 
13
15
  // Extrair credenciais da databaseUrl
14
16
  const urlMatch = databaseUrl.match(/postgresql:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/(.+)/);
15
17
 
16
18
  if (!urlMatch) {
17
- throw new Error('Database URL inválida');
19
+ const getT = global.smoonbI18n?.t || t;
20
+ throw new Error(getT('error.databaseUrlInvalidSimple'));
18
21
  }
19
22
 
20
23
  const [, username, password, host, port] = urlMatch;
@@ -45,7 +48,7 @@ module.exports = async ({ databaseUrl, backupDir }) => {
45
48
  `-f /host/${fileName}`
46
49
  ].join(' ');
47
50
 
48
- console.log(chalk.white(' - Executando pg_dumpall via Docker...'));
51
+ console.log(chalk.white(` - ${getT('backup.steps.database.executing')}`));
49
52
  execSync(dockerCmd, { stdio: 'pipe' });
50
53
 
51
54
  // Compactar igual ao Supabase Dashboard
@@ -65,7 +68,8 @@ module.exports = async ({ databaseUrl, backupDir }) => {
65
68
 
66
69
  return { success: true, size: sizeKB, fileName: finalFileName };
67
70
  } catch (error) {
68
- console.log(chalk.yellow(` ⚠️ Erro no backup do database: ${error.message}`));
71
+ const getT = global.smoonbI18n?.t || t;
72
+ console.log(chalk.yellow(` ⚠️ ${getT('backup.steps.database.error', { message: error.message })}`));
69
73
  return { success: false };
70
74
  }
71
75
  };
@@ -2,20 +2,22 @@ const chalk = require('chalk');
2
2
  const path = require('path');
3
3
  const fs = require('fs').promises;
4
4
  const { execSync } = require('child_process');
5
+ const { t } = require('../../../i18n');
5
6
 
6
7
  /**
7
8
  * Etapa 2: Backup Database Separado (SQL files para troubleshooting)
8
9
  */
9
10
  module.exports = async ({ databaseUrl, backupDir, accessToken }) => {
10
11
  try {
11
- console.log(chalk.white(' - Criando backups SQL separados via Supabase CLI...'));
12
+ const getT = global.smoonbI18n?.t || t;
13
+ console.log(chalk.white(` - ${getT('backup.steps.database.separated.creating')}`));
12
14
 
13
15
  const dbUrl = databaseUrl;
14
16
  const files = [];
15
17
  let totalSizeKB = 0;
16
18
 
17
19
  // 1. Backup do Schema
18
- console.log(chalk.white(' - Exportando schema...'));
20
+ console.log(chalk.white(` - ${getT('backup.steps.database.separated.exportingSchema')}`));
19
21
  const schemaFile = path.join(backupDir, 'schema.sql');
20
22
 
21
23
  try {
@@ -29,11 +31,11 @@ module.exports = async ({ databaseUrl, backupDir, accessToken }) => {
29
31
  totalSizeKB += parseFloat(sizeKB);
30
32
  console.log(chalk.green(` ✅ Schema: ${sizeKB} KB`));
31
33
  } catch (error) {
32
- console.log(chalk.yellow(` ⚠️ Erro no schema: ${error.message}`));
34
+ console.log(chalk.yellow(` ⚠️ ${getT('backup.steps.database.separated.schemaError', { message: error.message })}`));
33
35
  }
34
36
 
35
37
  // 2. Backup dos Dados
36
- console.log(chalk.white(' - Exportando dados...'));
38
+ console.log(chalk.white(` - ${getT('backup.steps.database.separated.exportingData')}`));
37
39
  const dataFile = path.join(backupDir, 'data.sql');
38
40
 
39
41
  try {
@@ -47,11 +49,11 @@ module.exports = async ({ databaseUrl, backupDir, accessToken }) => {
47
49
  totalSizeKB += parseFloat(sizeKB);
48
50
  console.log(chalk.green(` ✅ Data: ${sizeKB} KB`));
49
51
  } catch (error) {
50
- console.log(chalk.yellow(` ⚠️ Erro nos dados: ${error.message}`));
52
+ console.log(chalk.yellow(` ⚠️ ${getT('backup.steps.database.separated.dataError', { message: error.message })}`));
51
53
  }
52
54
 
53
55
  // 3. Backup dos Roles
54
- console.log(chalk.white(' - Exportando roles...'));
56
+ console.log(chalk.white(` - ${getT('backup.steps.database.separated.exportingRoles')}`));
55
57
  const rolesFile = path.join(backupDir, 'roles.sql');
56
58
 
57
59
  try {
@@ -65,7 +67,7 @@ module.exports = async ({ databaseUrl, backupDir, accessToken }) => {
65
67
  totalSizeKB += parseFloat(sizeKB);
66
68
  console.log(chalk.green(` ✅ Roles: ${sizeKB} KB`));
67
69
  } catch (error) {
68
- console.log(chalk.yellow(` ⚠️ Erro nos roles: ${error.message}`));
70
+ console.log(chalk.yellow(` ⚠️ ${getT('backup.steps.database.separated.rolesError', { message: error.message })}`));
69
71
  }
70
72
 
71
73
  return {
@@ -75,7 +77,8 @@ module.exports = async ({ databaseUrl, backupDir, accessToken }) => {
75
77
  };
76
78
 
77
79
  } catch (error) {
78
- console.log(chalk.yellow(` ⚠️ Erro nos backups SQL separados: ${error.message}`));
80
+ const getT = global.smoonbI18n?.t || t;
81
+ console.log(chalk.yellow(` ⚠️ ${getT('backup.steps.database.separated.error', { message: error.message })}`));
79
82
  return { success: false, files: [], totalSizeKB: '0.0' };
80
83
  }
81
84
  };
@@ -2,19 +2,22 @@ const chalk = require('chalk');
2
2
  const path = require('path');
3
3
  const fs = require('fs').promises;
4
4
  const { execSync } = require('child_process');
5
+ const { t } = require('../../../i18n');
5
6
 
6
7
  /**
7
8
  * Etapa 3: Backup Database Extensions and Settings via SQL
8
9
  */
9
10
  module.exports = async ({ databaseUrl, projectId, backupDir }) => {
10
11
  try {
11
- console.log(chalk.white(' - Capturando Database Extensions and Settings...'));
12
+ const getT = global.smoonbI18n?.t || t;
13
+ console.log(chalk.white(` - ${getT('backup.steps.databaseSettings.capturing')}`));
12
14
 
13
15
  // Extrair credenciais da databaseUrl
14
16
  const urlMatch = databaseUrl.match(/postgresql:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/(.+)/);
15
17
 
16
18
  if (!urlMatch) {
17
- throw new Error('Database URL inválida');
19
+ const getT = global.smoonbI18n?.t || t;
20
+ throw new Error(getT('error.databaseUrlInvalidSimple'));
18
21
  }
19
22
 
20
23
  const [, username, password, host, port, database] = urlMatch;
@@ -125,7 +128,7 @@ AND EXISTS (
125
128
  '-A' // Unaligned output
126
129
  ].join(' ');
127
130
 
128
- console.log(chalk.white(' - Executando queries de configurações via Docker...'));
131
+ console.log(chalk.white(` - ${getT('backup.steps.databaseSettings.executing')}`));
129
132
  const output = execSync(dockerCmd, { stdio: 'pipe', encoding: 'utf8' });
130
133
 
131
134
  // Processar output e criar JSON estruturado
@@ -171,7 +174,8 @@ AND EXISTS (
171
174
 
172
175
  return { success: true, size: sizeKB, fileName: fileName };
173
176
  } catch (error) {
174
- console.log(chalk.yellow(` ⚠️ Erro no backup das Database Settings: ${error.message}`));
177
+ const getT = global.smoonbI18n?.t || t;
178
+ console.log(chalk.yellow(` ⚠️ ${getT('backup.steps.databaseSettings.error', { message: error.message })}`));
175
179
  return { success: false };
176
180
  }
177
181
  };
@@ -1,13 +1,15 @@
1
1
  const chalk = require('chalk');
2
2
  const path = require('path');
3
3
  const { writeJson } = require('../../../utils/fsx');
4
+ const { t } = require('../../../i18n');
4
5
 
5
6
  /**
6
7
  * Etapa 4: Backup Auth Settings via Management API
7
8
  */
8
9
  module.exports = async ({ projectId, accessToken, backupDir }) => {
9
10
  try {
10
- console.log(chalk.white(' - Exportando configurações de Auth via Management API...'));
11
+ const getT = global.smoonbI18n?.t || t;
12
+ console.log(chalk.white(` - ${getT('backup.steps.auth.exporting')}`));
11
13
 
12
14
  // Usar fetch direto para Management API com Personal Access Token
13
15
  const authResponse = await fetch(`https://api.supabase.com/v1/projects/${projectId}/config/auth`, {
@@ -18,7 +20,7 @@ module.exports = async ({ projectId, accessToken, backupDir }) => {
18
20
  });
19
21
 
20
22
  if (!authResponse.ok) {
21
- console.log(chalk.yellow(` ⚠️ Erro ao obter Auth Settings: ${authResponse.status} ${authResponse.statusText}`));
23
+ console.log(chalk.yellow(` ⚠️ ${getT('backup.steps.auth.getError', { status: authResponse.status, statusText: authResponse.statusText })}`));
22
24
  return { success: false };
23
25
  }
24
26
 
@@ -36,7 +38,8 @@ module.exports = async ({ projectId, accessToken, backupDir }) => {
36
38
  return { success: true };
37
39
 
38
40
  } catch (error) {
39
- console.log(chalk.yellow(` ⚠️ Erro no backup das Auth Settings: ${error.message}`));
41
+ const getT = global.smoonbI18n?.t || t;
42
+ console.log(chalk.yellow(` ⚠️ ${getT('backup.steps.auth.error', { message: error.message })}`));
40
43
  return { success: false };
41
44
  }
42
45
  };
@@ -2,13 +2,15 @@ const chalk = require('chalk');
2
2
  const path = require('path');
3
3
  const fs = require('fs').promises;
4
4
  const { captureRealtimeSettings } = require('../../../utils/realtime-settings');
5
+ const { t } = require('../../../i18n');
5
6
 
6
7
  /**
7
8
  * Etapa 5: Backup Realtime Settings via Captura Interativa
8
9
  */
9
10
  module.exports = async ({ projectId, backupDir, options }) => {
10
11
  try {
11
- console.log(chalk.white(' - Capturando Realtime Settings interativamente...'));
12
+ const getT = global.smoonbI18n?.t || t;
13
+ console.log(chalk.white(` - ${getT('backup.steps.realtime.capturing')}`));
12
14
 
13
15
  const result = await captureRealtimeSettings(projectId, backupDir, options?.skipRealtime);
14
16
 
@@ -19,7 +21,8 @@ module.exports = async ({ projectId, backupDir, options }) => {
19
21
 
20
22
  return { success: true, settings: result };
21
23
  } catch (error) {
22
- console.log(chalk.yellow(` ⚠️ Erro ao capturar Realtime Settings: ${error.message}`));
24
+ const getT = global.smoonbI18n?.t || t;
25
+ console.log(chalk.yellow(` ⚠️ ${getT('backup.steps.realtime.error', { message: error.message })}`));
23
26
  return { success: false };
24
27
  }
25
28
  };