smoonb 0.0.48 → 0.0.50
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/README.md +339 -87
- package/bin/smoonb.js +2 -2
- package/package.json +1 -1
- package/src/commands/backup/index.js +45 -19
- package/src/commands/backup/steps/00-docker-validation.js +1 -1
- package/src/commands/backup/steps/08-edge-functions.js +6 -12
- package/src/commands/backup/steps/09-supabase-temp.js +4 -10
- package/src/commands/backup/steps/10-migrations.js +4 -10
- package/src/commands/check.js +0 -1
- package/src/commands/config.js +0 -1
- package/src/commands/functions.js +1 -1
- package/src/commands/restore/index.js +25 -9
- package/src/commands/restore/steps/01-components-selection.js +35 -48
- package/src/commands/restore/steps/02-confirmation.js +8 -13
- package/src/commands/restore/steps/04-edge-functions.js +3 -3
- package/src/commands/restore/steps/07-database-settings.js +1 -1
- package/src/commands/restore/steps/08-realtime-settings.js +1 -1
- package/src/commands/restore/utils.js +1 -1
- package/src/index.js +3 -3
- package/src/interactive/envMapper.js +38 -14
- package/src/utils/cli.js +1 -1
- package/src/utils/config.js +1 -3
- package/src/utils/docker.js +3 -3
- package/src/utils/env.js +2 -3
- package/src/utils/envMap.js +1 -1
- package/src/utils/fsx.js +2 -2
- package/src/utils/prompt.js +34 -0
- package/src/utils/realtime-settings.js +2 -2
- package/src/utils/supabase.js +10 -10
- package/src/utils/supabaseLink.js +1 -1
- package/src/utils/validation.js +2 -2
|
@@ -8,6 +8,7 @@ const { getDockerVersion } = require('../../utils/docker');
|
|
|
8
8
|
const { readEnvFile, writeEnvFile, backupEnvFile } = require('../../utils/env');
|
|
9
9
|
const { saveEnvMap } = require('../../utils/envMap');
|
|
10
10
|
const { mapEnvVariablesInteractively, askComponentsFlags } = require('../../interactive/envMapper');
|
|
11
|
+
const { confirm } = require('../../utils/prompt');
|
|
11
12
|
|
|
12
13
|
// Importar todas as etapas
|
|
13
14
|
const step00DockerValidation = require('./steps/00-docker-validation');
|
|
@@ -27,11 +28,16 @@ module.exports = async (options) => {
|
|
|
27
28
|
showBetaBanner();
|
|
28
29
|
|
|
29
30
|
try {
|
|
31
|
+
// Executar validação Docker ANTES de tudo
|
|
32
|
+
await step00DockerValidation();
|
|
33
|
+
|
|
30
34
|
// Consentimento para leitura e escrita do .env.local
|
|
31
|
-
console.log(chalk.yellow('⚠️ O smoonb irá ler e escrever o arquivo .env.local localmente.'));
|
|
35
|
+
console.log(chalk.yellow('\n⚠️ O smoonb irá ler e escrever o arquivo .env.local localmente.'));
|
|
32
36
|
console.log(chalk.yellow(' Um backup automático do .env.local será criado antes de qualquer alteração.'));
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
console.log(chalk.yellow(' Vamos mapear suas variáveis de ambiente para garantir que todas as chaves necessárias'));
|
|
38
|
+
console.log(chalk.yellow(' estejam presentes e com os valores corretos do projeto alvo.'));
|
|
39
|
+
const consentOk = await confirm('Você consente em prosseguir', true);
|
|
40
|
+
if (!consentOk) {
|
|
35
41
|
console.log(chalk.red('🚫 Operação cancelada pelo usuário.'));
|
|
36
42
|
process.exit(1);
|
|
37
43
|
}
|
|
@@ -128,13 +134,28 @@ module.exports = async (options) => {
|
|
|
128
134
|
process.exit(1);
|
|
129
135
|
}
|
|
130
136
|
|
|
131
|
-
|
|
137
|
+
// Flags de componentes (perguntas interativas)
|
|
138
|
+
const flags = await askComponentsFlags();
|
|
132
139
|
|
|
133
|
-
//
|
|
134
|
-
|
|
140
|
+
// Mostrar resumo e pedir confirmação final
|
|
141
|
+
console.log(chalk.cyan('\n📋 RESUMO DAS CONFIGURAÇÕES:\n'));
|
|
142
|
+
console.log(chalk.gray(` ✅ Edge Functions: ${flags.includeFunctions ? 'Sim' : 'Não'}`));
|
|
143
|
+
console.log(chalk.gray(` ✅ Storage: ${flags.includeStorage ? 'Sim' : 'Não'}`));
|
|
144
|
+
console.log(chalk.gray(` ✅ Auth: ${flags.includeAuth ? 'Sim' : 'Não'}`));
|
|
145
|
+
console.log(chalk.gray(` ✅ Realtime: ${flags.includeRealtime ? 'Sim' : 'Não'}`));
|
|
146
|
+
console.log(chalk.gray(` 🗑️ Limpar supabase/functions após backup: ${flags.cleanFunctions ? 'Sim' : 'Não'}`));
|
|
147
|
+
console.log(chalk.gray(` 🗑️ Apagar supabase/.temp após backup: ${flags.cleanTemp ? 'Sim' : 'Não'}`));
|
|
148
|
+
console.log(chalk.gray(` 🗑️ Apagar supabase/migrations após backup: ${flags.cleanMigrations ? 'Sim' : 'Não'}`));
|
|
149
|
+
console.log(chalk.gray(` 📁 Diretório de backup: ${finalBackupDir}\n`));
|
|
135
150
|
|
|
136
|
-
|
|
137
|
-
|
|
151
|
+
const finalOk = await confirm('Deseja iniciar o backup com estas configurações?', true);
|
|
152
|
+
|
|
153
|
+
if (!finalOk) {
|
|
154
|
+
console.log(chalk.red('🚫 Operação cancelada pelo usuário.'));
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
console.log(chalk.blue(`\n🚀 Iniciando backup do projeto: ${projectId}`));
|
|
138
159
|
|
|
139
160
|
// Criar contexto compartilhado para as etapas
|
|
140
161
|
const context = {
|
|
@@ -143,7 +164,12 @@ module.exports = async (options) => {
|
|
|
143
164
|
databaseUrl,
|
|
144
165
|
backupDir: finalBackupDir,
|
|
145
166
|
outputDir: resolvedOutputDir,
|
|
146
|
-
options: { ...options, flags }
|
|
167
|
+
options: { ...options, flags },
|
|
168
|
+
cleanupFlags: {
|
|
169
|
+
cleanFunctions: flags.cleanFunctions || false,
|
|
170
|
+
cleanTemp: flags.cleanTemp || false,
|
|
171
|
+
cleanMigrations: flags.cleanMigrations || false
|
|
172
|
+
}
|
|
147
173
|
};
|
|
148
174
|
|
|
149
175
|
// Criar manifest
|
|
@@ -162,12 +188,12 @@ module.exports = async (options) => {
|
|
|
162
188
|
console.log(chalk.gray(`🐳 Backup via Docker Desktop`));
|
|
163
189
|
|
|
164
190
|
// 1. Backup Database via pg_dumpall Docker
|
|
165
|
-
console.log(chalk.blue('\n📊 1/
|
|
191
|
+
console.log(chalk.blue('\n📊 1/11 - Backup da Database PostgreSQL via pg_dumpall Docker...'));
|
|
166
192
|
const databaseResult = await step01Database(context);
|
|
167
193
|
manifest.components.database = databaseResult;
|
|
168
194
|
|
|
169
195
|
// 2. Backup Database Separado
|
|
170
|
-
console.log(chalk.blue('\n📊 2/
|
|
196
|
+
console.log(chalk.blue('\n📊 2/11 - Backup da Database PostgreSQL (arquivos SQL separados)...'));
|
|
171
197
|
const dbSeparatedResult = await step02DatabaseSeparated(context);
|
|
172
198
|
manifest.components.database_separated = {
|
|
173
199
|
success: dbSeparatedResult.success,
|
|
@@ -177,50 +203,50 @@ module.exports = async (options) => {
|
|
|
177
203
|
};
|
|
178
204
|
|
|
179
205
|
// 3. Backup Database Settings
|
|
180
|
-
console.log(chalk.blue('\n🔧 3/
|
|
206
|
+
console.log(chalk.blue('\n🔧 3/11 - Backup das Database Extensions and Settings via SQL...'));
|
|
181
207
|
const databaseSettingsResult = await step03DatabaseSettings(context);
|
|
182
208
|
manifest.components.database_settings = databaseSettingsResult;
|
|
183
209
|
|
|
184
210
|
// 4. Backup Auth Settings
|
|
185
211
|
if (flags?.includeAuth) {
|
|
186
|
-
console.log(chalk.blue('\n🔐 4/
|
|
212
|
+
console.log(chalk.blue('\n🔐 4/11 - Backup das Auth Settings via API...'));
|
|
187
213
|
const authResult = await step04AuthSettings(context);
|
|
188
214
|
manifest.components.auth_settings = authResult;
|
|
189
215
|
}
|
|
190
216
|
|
|
191
217
|
// 5. Backup Realtime Settings
|
|
192
218
|
if (flags?.includeRealtime) {
|
|
193
|
-
console.log(chalk.blue('\n🔄 5/
|
|
219
|
+
console.log(chalk.blue('\n🔄 5/11 - Backup das Realtime Settings via Captura Interativa...'));
|
|
194
220
|
const realtimeResult = await step05RealtimeSettings(context);
|
|
195
221
|
manifest.components.realtime = realtimeResult;
|
|
196
222
|
}
|
|
197
223
|
|
|
198
224
|
// 6. Backup Storage
|
|
199
225
|
if (flags?.includeStorage) {
|
|
200
|
-
console.log(chalk.blue('\n📦 6/
|
|
226
|
+
console.log(chalk.blue('\n📦 6/11 - Backup do Storage via API...'));
|
|
201
227
|
const storageResult = await step06Storage(context);
|
|
202
228
|
manifest.components.storage = storageResult;
|
|
203
229
|
}
|
|
204
230
|
|
|
205
231
|
// 7. Backup Custom Roles
|
|
206
|
-
console.log(chalk.blue('\n👥 7/
|
|
232
|
+
console.log(chalk.blue('\n👥 7/11 - Backup dos Custom Roles via SQL...'));
|
|
207
233
|
const rolesResult = await step07CustomRoles(context);
|
|
208
234
|
manifest.components.custom_roles = rolesResult;
|
|
209
235
|
|
|
210
236
|
// 8. Backup Edge Functions
|
|
211
237
|
if (flags?.includeFunctions) {
|
|
212
|
-
console.log(chalk.blue('\n⚡ 8/
|
|
238
|
+
console.log(chalk.blue('\n⚡ 8/11 - Backup das Edge Functions via Docker...'));
|
|
213
239
|
const functionsResult = await step08EdgeFunctions(context);
|
|
214
240
|
manifest.components.edge_functions = functionsResult;
|
|
215
241
|
}
|
|
216
242
|
|
|
217
243
|
// 9. Backup Supabase .temp
|
|
218
|
-
console.log(chalk.blue('\n📁 9/
|
|
244
|
+
console.log(chalk.blue('\n📁 9/11 - Backup do Supabase .temp...'));
|
|
219
245
|
const supabaseTempResult = await step09SupabaseTemp(context);
|
|
220
246
|
manifest.components.supabase_temp = supabaseTempResult;
|
|
221
247
|
|
|
222
248
|
// 10. Backup Migrations
|
|
223
|
-
console.log(chalk.blue('\n📋 10/
|
|
249
|
+
console.log(chalk.blue('\n📋 10/11 - Backup das Migrations...'));
|
|
224
250
|
const migrationsResult = await step10Migrations(context);
|
|
225
251
|
manifest.components.migrations = migrationsResult;
|
|
226
252
|
|
|
@@ -7,7 +7,7 @@ const { showDockerMessagesAndExit } = require('../utils');
|
|
|
7
7
|
* Deve ocorrer antes de tudo
|
|
8
8
|
*/
|
|
9
9
|
module.exports = async () => {
|
|
10
|
-
console.log(chalk.blue('\n🐳
|
|
10
|
+
console.log(chalk.blue('\n🐳 Validação Docker...'));
|
|
11
11
|
console.log(chalk.gray('🔍 Verificando dependências Docker...'));
|
|
12
12
|
|
|
13
13
|
const backupCapability = await canPerformCompleteBackup();
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs').promises;
|
|
4
|
-
const inquirer = require('inquirer');
|
|
5
4
|
const { ensureDir, writeJson } = require('../../../utils/fsx');
|
|
6
5
|
const { extractPasswordFromDbUrl, ensureCleanLink } = require('../../../utils/supabaseLink');
|
|
7
6
|
const { cleanDir } = require('../../../utils/fsExtra');
|
|
@@ -9,7 +8,8 @@ const { cleanDir } = require('../../../utils/fsExtra');
|
|
|
9
8
|
/**
|
|
10
9
|
* Etapa 8: Backup Edge Functions via Docker (reset link + limpeza opcional)
|
|
11
10
|
*/
|
|
12
|
-
module.exports = async (
|
|
11
|
+
module.exports = async (context) => {
|
|
12
|
+
const { projectId, accessToken, databaseUrl, backupDir } = context;
|
|
13
13
|
try {
|
|
14
14
|
const functionsDir = path.join(backupDir, 'edge-functions');
|
|
15
15
|
await ensureDir(functionsDir);
|
|
@@ -94,7 +94,7 @@ module.exports = async ({ projectId, accessToken, databaseUrl, backupDir }) => {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
|
-
} catch
|
|
97
|
+
} catch {
|
|
98
98
|
// Arquivos não foram baixados, continuar
|
|
99
99
|
console.log(chalk.yellow(` ⚠️ Nenhum arquivo encontrado em ${tempDownloadDir}`));
|
|
100
100
|
}
|
|
@@ -102,7 +102,7 @@ module.exports = async ({ projectId, accessToken, databaseUrl, backupDir }) => {
|
|
|
102
102
|
// LIMPAR supabase/functions após copiar
|
|
103
103
|
try {
|
|
104
104
|
await fs.rm(tempDownloadDir, { recursive: true, force: true });
|
|
105
|
-
} catch
|
|
105
|
+
} catch {
|
|
106
106
|
// Ignorar erro de limpeza
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -126,14 +126,8 @@ module.exports = async ({ projectId, accessToken, databaseUrl, backupDir }) => {
|
|
|
126
126
|
console.log(chalk.green(` ✅ Sucessos: ${successCount}`));
|
|
127
127
|
console.log(chalk.green(` ❌ Erros: ${errorCount}`));
|
|
128
128
|
|
|
129
|
-
//
|
|
130
|
-
const
|
|
131
|
-
type: 'confirm',
|
|
132
|
-
name: 'shouldClean',
|
|
133
|
-
message: 'Deseja limpar supabase/functions após o backup? (S/n):',
|
|
134
|
-
default: true,
|
|
135
|
-
prefix: ''
|
|
136
|
-
}]);
|
|
129
|
+
// Usar flag de limpeza do contexto (já foi perguntado no início)
|
|
130
|
+
const shouldClean = context?.cleanupFlags?.cleanFunctions || false;
|
|
137
131
|
|
|
138
132
|
if (shouldClean) {
|
|
139
133
|
await cleanDir(supabaseFunctionsDir);
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const inquirer = require('inquirer');
|
|
4
3
|
const { copyDirSafe } = require('../../../utils/fsExtra');
|
|
5
4
|
const { cleanDir } = require('../../../utils/fsExtra');
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Etapa 9: Backup Supabase .temp (NOVA ETAPA INDEPENDENTE)
|
|
9
8
|
*/
|
|
10
|
-
module.exports = async (
|
|
9
|
+
module.exports = async (context) => {
|
|
10
|
+
const { backupDir } = context;
|
|
11
11
|
try {
|
|
12
12
|
const tempDir = path.join(process.cwd(), 'supabase', '.temp');
|
|
13
13
|
const backupTempDir = path.join(backupDir, 'supabase-temp');
|
|
@@ -22,14 +22,8 @@ module.exports = async ({ backupDir }) => {
|
|
|
22
22
|
console.log(chalk.green(` ✅ ${fileCount} arquivo(s) copiado(s)`));
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
//
|
|
26
|
-
const
|
|
27
|
-
type: 'confirm',
|
|
28
|
-
name: 'shouldClean',
|
|
29
|
-
message: 'Deseja apagar supabase/.temp após o backup? (S/n):',
|
|
30
|
-
default: false,
|
|
31
|
-
prefix: ''
|
|
32
|
-
}]);
|
|
25
|
+
// Usar flag de limpeza do contexto (já foi perguntado no início)
|
|
26
|
+
const shouldClean = context?.cleanupFlags?.cleanTemp || false;
|
|
33
27
|
|
|
34
28
|
if (shouldClean) {
|
|
35
29
|
await cleanDir(tempDir);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const inquirer = require('inquirer');
|
|
4
3
|
const { execSync } = require('child_process');
|
|
5
4
|
const { extractPasswordFromDbUrl, ensureCleanLink } = require('../../../utils/supabaseLink');
|
|
6
5
|
const { cleanDir, countFiles, copyDirSafe } = require('../../../utils/fsExtra');
|
|
@@ -8,7 +7,8 @@ const { cleanDir, countFiles, copyDirSafe } = require('../../../utils/fsExtra');
|
|
|
8
7
|
/**
|
|
9
8
|
* Etapa 10: Backup Migrations (NOVA ETAPA INDEPENDENTE)
|
|
10
9
|
*/
|
|
11
|
-
module.exports = async (
|
|
10
|
+
module.exports = async (context) => {
|
|
11
|
+
const { projectId, accessToken, databaseUrl, backupDir } = context;
|
|
12
12
|
try {
|
|
13
13
|
// Reset de link ao projeto de ORIGEM
|
|
14
14
|
const dbPassword = extractPasswordFromDbUrl(databaseUrl);
|
|
@@ -54,14 +54,8 @@ module.exports = async ({ projectId, accessToken, databaseUrl, backupDir }) => {
|
|
|
54
54
|
console.log(chalk.green(` ✅ ${copiedCount} migration(s) copiada(s)`));
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
//
|
|
58
|
-
const
|
|
59
|
-
type: 'confirm',
|
|
60
|
-
name: 'shouldClean',
|
|
61
|
-
message: 'Deseja apagar supabase/migrations após o backup? (S/n):',
|
|
62
|
-
default: false,
|
|
63
|
-
prefix: ''
|
|
64
|
-
}]);
|
|
57
|
+
// Usar flag de limpeza do contexto (já foi perguntado no início)
|
|
58
|
+
const shouldClean = context?.cleanupFlags?.cleanMigrations || false;
|
|
65
59
|
|
|
66
60
|
if (shouldClean) {
|
|
67
61
|
await cleanDir(migrationsDir);
|
package/src/commands/check.js
CHANGED
package/src/commands/config.js
CHANGED
|
@@ -4,7 +4,7 @@ const { readConfig, validateFor } = require('../utils/config');
|
|
|
4
4
|
const { showBetaBanner } = require('../utils/banner');
|
|
5
5
|
|
|
6
6
|
// Exportar FUNÇÃO em vez de objeto Command
|
|
7
|
-
module.exports = async (
|
|
7
|
+
module.exports = async (_options) => {
|
|
8
8
|
showBetaBanner();
|
|
9
9
|
|
|
10
10
|
try {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const inquirer = require('inquirer');
|
|
5
4
|
const { readEnvFile, writeEnvFile, backupEnvFile } = require('../../utils/env');
|
|
6
5
|
const { saveEnvMap } = require('../../utils/envMap');
|
|
7
6
|
const { mapEnvVariablesInteractively } = require('../../interactive/envMapper');
|
|
8
7
|
const { showBetaBanner } = require('../../utils/banner');
|
|
9
8
|
const { listValidBackups, showRestoreSummary } = require('./utils');
|
|
9
|
+
const { confirm } = require('../../utils/prompt');
|
|
10
|
+
const step00DockerValidation = require('../backup/steps/00-docker-validation');
|
|
10
11
|
|
|
11
12
|
// Importar todas as etapas
|
|
12
13
|
const step00BackupSelection = require('./steps/00-backup-selection');
|
|
13
14
|
const step01ComponentsSelection = require('./steps/01-components-selection');
|
|
14
|
-
const step02Confirmation = require('./steps/02-confirmation');
|
|
15
15
|
const step03Database = require('./steps/03-database');
|
|
16
16
|
const step04EdgeFunctions = require('./steps/04-edge-functions');
|
|
17
17
|
const step05AuthSettings = require('./steps/05-auth-settings');
|
|
@@ -23,11 +23,16 @@ module.exports = async (_options) => {
|
|
|
23
23
|
showBetaBanner();
|
|
24
24
|
|
|
25
25
|
try {
|
|
26
|
+
// Executar validação Docker ANTES de tudo
|
|
27
|
+
await step00DockerValidation();
|
|
28
|
+
|
|
26
29
|
// Consentimento para leitura e escrita do .env.local
|
|
27
|
-
console.log(chalk.yellow('⚠️ O smoonb irá ler e escrever o arquivo .env.local localmente.'));
|
|
30
|
+
console.log(chalk.yellow('\n⚠️ O smoonb irá ler e escrever o arquivo .env.local localmente.'));
|
|
28
31
|
console.log(chalk.yellow(' Um backup automático do .env.local será criado antes de qualquer alteração.'));
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
console.log(chalk.yellow(' Vamos mapear suas variáveis de ambiente para garantir que todas as chaves necessárias'));
|
|
33
|
+
console.log(chalk.yellow(' estejam presentes e com os valores corretos do projeto de destino.'));
|
|
34
|
+
const consentOk = await confirm('Você consente em prosseguir', true);
|
|
35
|
+
if (!consentOk) {
|
|
31
36
|
console.log(chalk.red('🚫 Operação cancelada pelo usuário.'));
|
|
32
37
|
process.exit(1);
|
|
33
38
|
}
|
|
@@ -100,13 +105,24 @@ module.exports = async (_options) => {
|
|
|
100
105
|
process.exit(1);
|
|
101
106
|
}
|
|
102
107
|
|
|
103
|
-
// 4. Mostrar resumo
|
|
108
|
+
// 4. Mostrar resumo detalhado
|
|
109
|
+
console.log(chalk.cyan('\n📋 RESUMO DA RESTAURAÇÃO:\n'));
|
|
110
|
+
console.log(chalk.gray(` 📁 Backup selecionado: ${path.basename(selectedBackup.path)}`));
|
|
111
|
+
console.log(chalk.gray(` 🎯 Projeto destino: ${targetProject.targetProjectId || '(não configurado)'}`));
|
|
112
|
+
console.log(chalk.gray(` 📊 Database: ${components.database ? 'Sim' : 'Não'}`));
|
|
113
|
+
console.log(chalk.gray(` ⚡ Edge Functions: ${components.edgeFunctions ? 'Sim' : 'Não'}`));
|
|
114
|
+
console.log(chalk.gray(` 🔐 Auth Settings: ${components.authSettings ? 'Sim' : 'Não'}`));
|
|
115
|
+
console.log(chalk.gray(` 📦 Storage: ${components.storage ? 'Sim' : 'Não'}`));
|
|
116
|
+
console.log(chalk.gray(` 🔧 Database Settings: ${components.databaseSettings ? 'Sim' : 'Não'}`));
|
|
117
|
+
console.log(chalk.gray(` 🔄 Realtime Settings: ${components.realtimeSettings ? 'Sim' : 'Não'}\n`));
|
|
118
|
+
|
|
119
|
+
// Mostrar resumo técnico adicional
|
|
104
120
|
showRestoreSummary(selectedBackup, components, targetProject);
|
|
105
121
|
|
|
106
122
|
// 5. Confirmar execução
|
|
107
|
-
const
|
|
108
|
-
if (!
|
|
109
|
-
console.log(chalk.yellow('Restauração cancelada.'));
|
|
123
|
+
const finalOk = await confirm('Deseja iniciar a restauração com estas configurações?', true);
|
|
124
|
+
if (!finalOk) {
|
|
125
|
+
console.log(chalk.yellow('🚫 Restauração cancelada.'));
|
|
110
126
|
process.exit(0);
|
|
111
127
|
}
|
|
112
128
|
|
|
@@ -1,84 +1,71 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const fs = require('fs');
|
|
3
|
-
const
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const { confirm } = require('../../utils/prompt');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Etapa 1: Perguntar quais componentes restaurar
|
|
7
8
|
*/
|
|
8
9
|
module.exports = async (backupPath) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// Database
|
|
12
|
-
questions.push({
|
|
13
|
-
type: 'confirm',
|
|
14
|
-
name: 'restoreDatabase',
|
|
15
|
-
message: 'Deseja restaurar Database (S/n):',
|
|
16
|
-
default: true
|
|
17
|
-
});
|
|
10
|
+
// Database (sempre disponível)
|
|
11
|
+
const restoreDatabase = await confirm('Deseja restaurar Database', true);
|
|
18
12
|
|
|
19
13
|
// Edge Functions
|
|
20
14
|
const edgeFunctionsDir = path.join(backupPath, 'edge-functions');
|
|
15
|
+
let restoreEdgeFunctions = false;
|
|
21
16
|
if (fs.existsSync(edgeFunctionsDir) && fs.readdirSync(edgeFunctionsDir).length > 0) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
default: true
|
|
27
|
-
});
|
|
17
|
+
console.log(chalk.cyan('\n⚡ Edge Functions:'));
|
|
18
|
+
console.log(chalk.gray(' As Edge Functions serão copiadas para supabase/functions e implantadas no projeto destino.'));
|
|
19
|
+
console.log(chalk.gray(' A pasta supabase/functions será limpa antes do processo.\n'));
|
|
20
|
+
restoreEdgeFunctions = await confirm('Deseja restaurar Edge Functions', true);
|
|
28
21
|
}
|
|
29
22
|
|
|
30
23
|
// Auth Settings
|
|
24
|
+
let restoreAuthSettings = false;
|
|
31
25
|
if (fs.existsSync(path.join(backupPath, 'auth-settings.json'))) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
default: false
|
|
37
|
-
});
|
|
26
|
+
console.log(chalk.cyan('\n🔐 Auth Settings:'));
|
|
27
|
+
console.log(chalk.gray(' As configurações de Auth serão exibidas para configuração manual no Dashboard.'));
|
|
28
|
+
console.log(chalk.gray(' Algumas configurações não podem ser aplicadas automaticamente por questões de segurança.\n'));
|
|
29
|
+
restoreAuthSettings = await confirm('Deseja ver as configurações de Auth Settings', true);
|
|
38
30
|
}
|
|
39
31
|
|
|
40
32
|
// Storage Buckets
|
|
41
33
|
const storageDir = path.join(backupPath, 'storage');
|
|
34
|
+
let restoreStorage = false;
|
|
42
35
|
if (fs.existsSync(storageDir) && fs.readdirSync(storageDir).length > 0) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
default: false
|
|
48
|
-
});
|
|
36
|
+
console.log(chalk.cyan('\n📦 Storage:'));
|
|
37
|
+
console.log(chalk.gray(' As informações dos buckets de Storage serão exibidas para migração manual.'));
|
|
38
|
+
console.log(chalk.gray(' Os arquivos precisam ser migrados manualmente usando as ferramentas do Supabase.\n'));
|
|
39
|
+
restoreStorage = await confirm('Deseja ver informações de Storage Buckets', true);
|
|
49
40
|
}
|
|
50
41
|
|
|
51
42
|
// Database Extensions and Settings
|
|
52
43
|
const dbSettingsFiles = fs.readdirSync(backupPath)
|
|
53
44
|
.filter(file => file.startsWith('database-settings-') && file.endsWith('.json'));
|
|
45
|
+
let restoreDatabaseSettings = false;
|
|
54
46
|
if (dbSettingsFiles.length > 0) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
default: false
|
|
60
|
-
});
|
|
47
|
+
console.log(chalk.cyan('\n🔧 Database Extensions and Settings:'));
|
|
48
|
+
console.log(chalk.gray(' As extensões e configurações do banco de dados serão restauradas via SQL.'));
|
|
49
|
+
console.log(chalk.gray(' Isso inclui extensões PostgreSQL e configurações específicas do projeto.\n'));
|
|
50
|
+
restoreDatabaseSettings = await confirm('Deseja restaurar Database Extensions and Settings', true);
|
|
61
51
|
}
|
|
62
52
|
|
|
63
53
|
// Realtime Settings
|
|
54
|
+
let restoreRealtimeSettings = false;
|
|
64
55
|
if (fs.existsSync(path.join(backupPath, 'realtime-settings.json'))) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
default: false
|
|
70
|
-
});
|
|
56
|
+
console.log(chalk.cyan('\n🔄 Realtime Settings:'));
|
|
57
|
+
console.log(chalk.gray(' As configurações de Realtime serão exibidas para configuração manual no Dashboard.'));
|
|
58
|
+
console.log(chalk.gray(' Algumas configurações precisam ser aplicadas manualmente.\n'));
|
|
59
|
+
restoreRealtimeSettings = await confirm('Deseja ver as configurações de Realtime Settings', true);
|
|
71
60
|
}
|
|
72
61
|
|
|
73
|
-
const answers = await inquirer.prompt(questions);
|
|
74
|
-
|
|
75
62
|
return {
|
|
76
|
-
database:
|
|
77
|
-
edgeFunctions:
|
|
78
|
-
storage:
|
|
79
|
-
authSettings:
|
|
80
|
-
databaseSettings:
|
|
81
|
-
realtimeSettings:
|
|
63
|
+
database: restoreDatabase,
|
|
64
|
+
edgeFunctions: restoreEdgeFunctions,
|
|
65
|
+
storage: restoreStorage,
|
|
66
|
+
authSettings: restoreAuthSettings,
|
|
67
|
+
databaseSettings: restoreDatabaseSettings,
|
|
68
|
+
realtimeSettings: restoreRealtimeSettings
|
|
82
69
|
};
|
|
83
70
|
};
|
|
84
71
|
|
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
// Este arquivo não é mais usado diretamente
|
|
2
|
+
// A confirmação agora é feita no index.js com resumo detalhado
|
|
3
|
+
// Mantido para compatibilidade, mas pode ser removido no futuro
|
|
4
|
+
|
|
5
|
+
const { confirm } = require('../../utils/prompt');
|
|
2
6
|
|
|
3
7
|
/**
|
|
4
|
-
* Etapa 2: Confirmar execução
|
|
8
|
+
* Etapa 2: Confirmar execução (LEGACY - não usado mais)
|
|
9
|
+
* A confirmação agora é feita no index.js após mostrar resumo detalhado
|
|
5
10
|
*/
|
|
6
11
|
module.exports = async () => {
|
|
7
|
-
|
|
8
|
-
input: process.stdin,
|
|
9
|
-
output: process.stdout
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
const question = (query) => new Promise(resolve => rl.question(query, resolve));
|
|
13
|
-
|
|
14
|
-
const confirm = await question('Deseja continuar com a restauração? (s/N): ');
|
|
15
|
-
rl.close();
|
|
16
|
-
|
|
17
|
-
return confirm.toLowerCase() === 's';
|
|
12
|
+
return await confirm('Deseja continuar com a restauração?', true);
|
|
18
13
|
};
|
|
19
14
|
|
|
@@ -47,7 +47,7 @@ module.exports = async ({ backupPath, targetProject }) => {
|
|
|
47
47
|
try {
|
|
48
48
|
await fs.rm(supabaseFunctionsDir, { recursive: true, force: true });
|
|
49
49
|
await fs.mkdir(supabaseFunctionsDir, { recursive: true });
|
|
50
|
-
} catch
|
|
50
|
+
} catch {
|
|
51
51
|
// Ignorar erro de limpeza se não existir
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -72,7 +72,7 @@ module.exports = async ({ backupPath, targetProject }) => {
|
|
|
72
72
|
timeout: 10000,
|
|
73
73
|
env: { ...process.env, SUPABASE_ACCESS_TOKEN: targetProject.targetAccessToken || '' }
|
|
74
74
|
});
|
|
75
|
-
} catch
|
|
75
|
+
} catch {
|
|
76
76
|
console.log(chalk.yellow(' ⚠️ Link pode já existir, continuando...'));
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -99,7 +99,7 @@ module.exports = async ({ backupPath, targetProject }) => {
|
|
|
99
99
|
console.log(chalk.gray(' - Limpando supabase/functions após deploy...'));
|
|
100
100
|
try {
|
|
101
101
|
await fs.rm(supabaseFunctionsDir, { recursive: true, force: true });
|
|
102
|
-
} catch
|
|
102
|
+
} catch {
|
|
103
103
|
// Ignorar erro de limpeza
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -50,7 +50,7 @@ module.exports = async ({ backupPath, targetProject }) => {
|
|
|
50
50
|
|
|
51
51
|
try {
|
|
52
52
|
execSync(dockerCmd, { stdio: 'pipe', encoding: 'utf8' });
|
|
53
|
-
} catch
|
|
53
|
+
} catch {
|
|
54
54
|
console.log(chalk.yellow(` ⚠️ ${extName} - extension já existe ou não pode ser habilitada`));
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -25,7 +25,7 @@ module.exports = async ({ backupPath, targetProject }) => {
|
|
|
25
25
|
console.log(chalk.yellow('\n 📋 Configure manualmente as seguintes opções:'));
|
|
26
26
|
|
|
27
27
|
if (realtimeSettings.realtime_settings?.settings) {
|
|
28
|
-
Object.
|
|
28
|
+
Object.values(realtimeSettings.realtime_settings.settings).forEach((setting) => {
|
|
29
29
|
console.log(chalk.gray(` - ${setting.label}: ${setting.value}`));
|
|
30
30
|
if (setting.description) {
|
|
31
31
|
console.log(chalk.gray(` ${setting.description}`));
|
package/src/index.js
CHANGED
|
@@ -125,7 +125,7 @@ function checkPrerequisites() {
|
|
|
125
125
|
const { execSync } = require('child_process');
|
|
126
126
|
const npmVersion = execSync('npm --version', { encoding: 'utf8' }).trim();
|
|
127
127
|
prerequisites.npm = { installed: true, version: npmVersion };
|
|
128
|
-
} catch
|
|
128
|
+
} catch {
|
|
129
129
|
prerequisites.npm = { installed: false, version: null };
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -134,7 +134,7 @@ function checkPrerequisites() {
|
|
|
134
134
|
const { execSync } = require('child_process');
|
|
135
135
|
const supabaseVersion = execSync('supabase --version', { encoding: 'utf8' }).trim();
|
|
136
136
|
prerequisites.supabase_cli = { installed: true, version: supabaseVersion };
|
|
137
|
-
} catch
|
|
137
|
+
} catch {
|
|
138
138
|
prerequisites.supabase_cli = { installed: false, version: null };
|
|
139
139
|
}
|
|
140
140
|
|
|
@@ -143,7 +143,7 @@ function checkPrerequisites() {
|
|
|
143
143
|
const { execSync } = require('child_process');
|
|
144
144
|
const pgDumpVersion = execSync('pg_dump --version', { encoding: 'utf8' }).trim();
|
|
145
145
|
prerequisites.pg_dump = { installed: true, version: pgDumpVersion };
|
|
146
|
-
} catch
|
|
146
|
+
} catch {
|
|
147
147
|
prerequisites.pg_dump = { installed: false, version: null };
|
|
148
148
|
}
|
|
149
149
|
|