smoonb 0.0.62 → 0.0.63
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 +60 -16
- package/bin/smoonb.js +24 -2
- package/package.json +1 -1
- package/src/commands/restore/index.js +111 -12
package/README.md
CHANGED
|
@@ -210,38 +210,57 @@ backups/backup-2025-10-31-09-37-54/
|
|
|
210
210
|
|
|
211
211
|
### Restauração Interativa
|
|
212
212
|
|
|
213
|
+
**Restaurar backup existente:**
|
|
213
214
|
```bash
|
|
214
215
|
npx smoonb restore
|
|
215
216
|
```
|
|
216
217
|
|
|
218
|
+
**Importar e restaurar diretamente do Dashboard:**
|
|
219
|
+
```bash
|
|
220
|
+
# Apenas database
|
|
221
|
+
npx smoonb restore --file "C:\Downloads\db_cluster-04-03-2024@14-16-59.backup.gz"
|
|
222
|
+
|
|
223
|
+
# Database e storage juntos
|
|
224
|
+
npx smoonb restore --file "backup.backup.gz" --storage "meu-projeto.storage.zip"
|
|
225
|
+
```
|
|
226
|
+
|
|
217
227
|
**Fluxo interativo do restore:**
|
|
218
228
|
|
|
219
229
|
1. **Validação Docker** - Verifica se o Docker está rodando
|
|
220
|
-
2. **
|
|
221
|
-
3. **
|
|
222
|
-
4. **
|
|
223
|
-
5. **
|
|
224
|
-
6. **Seleção de
|
|
230
|
+
2. **Termo de Uso** - Exibe e solicita aceitação dos termos
|
|
231
|
+
3. **Consentimento** - Pede permissão para ler/escrever `.env.local`
|
|
232
|
+
4. **Mapeamento de Variáveis** - Mapeia variáveis para o projeto de destino
|
|
233
|
+
5. **Backup do .env.local** - Cria backup automático
|
|
234
|
+
6. **Seleção de Backup** - Lista e permite escolher qual backup restaurar (pula se `--file` fornecido)
|
|
235
|
+
- Se `--file` for fornecido: importa automaticamente e auto-seleciona o backup
|
|
236
|
+
- Se `--storage` for fornecido junto com `--file`: importa também o arquivo de storage
|
|
237
|
+
7. **Seleção de Componentes** - Pergunta quais componentes restaurar:
|
|
225
238
|
- 📊 Database (sempre disponível)
|
|
226
239
|
- ⚡ Edge Functions (se disponível no backup)
|
|
227
240
|
- 🔐 Auth Settings (se disponível no backup)
|
|
228
241
|
- 📦 Storage (se disponível no backup)
|
|
229
242
|
- 🔧 Database Extensions and Settings (se disponível no backup)
|
|
230
243
|
- 🔄 Realtime Settings (se disponível no backup)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
244
|
+
8. **Resumo Detalhado** - Mostra backup selecionado, projeto destino e componentes
|
|
245
|
+
9. **Confirmação Final** - Confirma antes de iniciar
|
|
246
|
+
10. **Execução da Restauração:**
|
|
247
|
+
- 📊 Database - Restaura via `psql` (suporta `.backup.gz` e `.backup`)
|
|
248
|
+
- ⚡ Edge Functions - Copia e faz deploy no projeto destino
|
|
249
|
+
- 🔐 Auth Settings - Exibe configurações para aplicação manual
|
|
250
|
+
- 📦 Storage - Exibe informações para migração manual
|
|
251
|
+
- 🔧 Database Settings - Restaura extensões e configurações via SQL
|
|
252
|
+
- 🔄 Realtime Settings - Exibe configurações para aplicação manual
|
|
240
253
|
|
|
241
254
|
**Formato de arquivos suportados:**
|
|
242
255
|
- ✅ `.backup.gz` (compactado) - Descompacta automaticamente antes de restaurar
|
|
243
256
|
- ✅ `.backup` (descompactado) - Restaura diretamente
|
|
244
257
|
|
|
258
|
+
**Quando usar `--file`:**
|
|
259
|
+
- Importa automaticamente o arquivo de backup antes de restaurar
|
|
260
|
+
- Elimina a etapa de seleção de backup
|
|
261
|
+
- Se `--storage` fornecido, importa também o arquivo de storage
|
|
262
|
+
- Útil para restaurar backups baixados diretamente do Dashboard do Supabase
|
|
263
|
+
|
|
245
264
|
### Importar Backup do Dashboard do Supabase
|
|
246
265
|
|
|
247
266
|
Se você baixou um backup diretamente do Dashboard do Supabase (formato `.backup.gz`), você pode importá-lo para o formato esperado pelo smoonb. O comando também suporta importar arquivos de storage (`.storage.zip`) opcionalmente.
|
|
@@ -265,7 +284,7 @@ npx smoonb import --file "backup.backup.gz" --storage "meu-projeto.storage.zip"
|
|
|
265
284
|
6. Se fornecido, copia o arquivo de storage para a mesma pasta
|
|
266
285
|
7. Deixa o backup pronto para ser encontrado pelo comando `restore`
|
|
267
286
|
|
|
268
|
-
**Exemplo completo - Apenas database:**
|
|
287
|
+
**Exemplo completo - Apenas database (usando import + restore):**
|
|
269
288
|
```bash
|
|
270
289
|
# 1. Baixar backup do Dashboard do Supabase
|
|
271
290
|
# Arquivo: db_cluster-04-03-2024@14-16-59.backup.gz
|
|
@@ -278,7 +297,16 @@ npx smoonb restore
|
|
|
278
297
|
# O backup importado aparecerá na lista de backups disponíveis
|
|
279
298
|
```
|
|
280
299
|
|
|
281
|
-
**Exemplo completo -
|
|
300
|
+
**Exemplo completo - Apenas database (usando restore diretamente):**
|
|
301
|
+
```bash
|
|
302
|
+
# 1. Baixar backup do Dashboard do Supabase
|
|
303
|
+
# Arquivo: db_cluster-04-03-2024@14-16-59.backup.gz
|
|
304
|
+
|
|
305
|
+
# 2. Importar e restaurar diretamente (pula seleção de backup)
|
|
306
|
+
npx smoonb restore --file "C:\Downloads\db_cluster-04-03-2024@14-16-59.backup.gz"
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
**Exemplo completo - Database e Storage (usando import + restore):**
|
|
282
310
|
```bash
|
|
283
311
|
# 1. Baixar backup e storage do Dashboard do Supabase
|
|
284
312
|
# Arquivos:
|
|
@@ -293,6 +321,17 @@ npx smoonb restore
|
|
|
293
321
|
# O backup importado aparecerá na lista de backups disponíveis
|
|
294
322
|
```
|
|
295
323
|
|
|
324
|
+
**Exemplo completo - Database e Storage (usando restore diretamente):**
|
|
325
|
+
```bash
|
|
326
|
+
# 1. Baixar backup e storage do Dashboard do Supabase
|
|
327
|
+
# Arquivos:
|
|
328
|
+
# - db_cluster-04-03-2024@14-16-59.backup.gz
|
|
329
|
+
# - meu-projeto.storage.zip
|
|
330
|
+
|
|
331
|
+
# 2. Importar e restaurar diretamente (pula seleção de backup)
|
|
332
|
+
npx smoonb restore --file "C:\Downloads\db_cluster-04-03-2024@14-16-59.backup.gz" --storage "C:\Downloads\meu-projeto.storage.zip"
|
|
333
|
+
```
|
|
334
|
+
|
|
296
335
|
**Importante:**
|
|
297
336
|
- O arquivo de backup é **obrigatório** e deve estar no formato do Dashboard: `db_cluster-DD-MM-YYYY@HH-MM-SS.backup.gz`
|
|
298
337
|
- O arquivo de storage é **opcional** e deve estar no formato: `*.storage.zip`
|
|
@@ -301,6 +340,10 @@ npx smoonb restore
|
|
|
301
340
|
- O caminho pode ser absoluto ou relativo
|
|
302
341
|
- O comando criará a estrutura de pastas necessária automaticamente
|
|
303
342
|
|
|
343
|
+
**Diferença entre `import` e `restore --file`:**
|
|
344
|
+
- `import`: Apenas importa o arquivo e cria a estrutura de backup. Você precisa executar `restore` depois.
|
|
345
|
+
- `restore --file`: Importa o arquivo automaticamente e já inicia o processo de restauração, pulando a etapa de seleção de backup.
|
|
346
|
+
|
|
304
347
|
### Verificação Pós-Restore
|
|
305
348
|
|
|
306
349
|
```bash
|
|
@@ -322,6 +365,7 @@ npx smoonb check
|
|
|
322
365
|
|---------|-----------|
|
|
323
366
|
| `npx smoonb backup` | Backup completo interativo usando Docker |
|
|
324
367
|
| `npx smoonb restore` | Restauração interativa usando psql (Docker) |
|
|
368
|
+
| `npx smoonb restore --file <path> [--storage <path>]` | Importar e restaurar diretamente arquivo .backup.gz e opcionalmente .storage.zip do Dashboard |
|
|
325
369
|
| `npx smoonb import --file <path> [--storage <path>]` | Importar arquivo .backup.gz e opcionalmente .storage.zip do Dashboard do Supabase |
|
|
326
370
|
| `npx smoonb check` | Verificação de integridade pós-restore |
|
|
327
371
|
|
package/bin/smoonb.js
CHANGED
|
@@ -53,6 +53,12 @@ ${chalk.yellow.bold('1. BACKUP - Fazer backup completo do projeto:')}
|
|
|
53
53
|
${chalk.yellow.bold('2. RESTORE - Restaurar backup em um projeto:')}
|
|
54
54
|
${chalk.white('npx smoonb restore')}
|
|
55
55
|
${chalk.gray('# Processo interativo que lista backups disponíveis e permite escolher')}
|
|
56
|
+
|
|
57
|
+
${chalk.white('npx smoonb restore --file "C:\\Downloads\\db_cluster-04-03-2024@14-16-59.backup.gz"')}
|
|
58
|
+
${chalk.gray('# Importa e restaura diretamente o arquivo de backup (pula seleção)')}
|
|
59
|
+
|
|
60
|
+
${chalk.white('npx smoonb restore --file "backup.backup.gz" --storage "meu-projeto.storage.zip"')}
|
|
61
|
+
${chalk.gray('# Importa e restaura backup e storage juntos')}
|
|
56
62
|
|
|
57
63
|
${chalk.yellow.bold('3. IMPORT - Importar backup do Dashboard do Supabase:')}
|
|
58
64
|
${chalk.white('npx smoonb import --file "C:\\Downloads\\db_cluster-04-03-2024@14-16-59.backup.gz"')}
|
|
@@ -103,25 +109,41 @@ ${chalk.yellow.bold('O que é capturado:')}
|
|
|
103
109
|
program
|
|
104
110
|
.command('restore')
|
|
105
111
|
.description('Restaurar backup completo usando psql (modo interativo)')
|
|
112
|
+
.option('--file <path>', 'Caminho completo do arquivo .backup.gz a importar e restaurar (opcional)')
|
|
113
|
+
.option('--storage <path>', 'Caminho completo do arquivo .storage.zip a importar junto com o backup (opcional)')
|
|
106
114
|
.addHelpText('after', `
|
|
107
115
|
${chalk.yellow.bold('Exemplos:')}
|
|
108
116
|
${chalk.white('npx smoonb restore')}
|
|
109
117
|
${chalk.gray('# Processo interativo que lista backups disponíveis')}
|
|
118
|
+
|
|
119
|
+
${chalk.white('npx smoonb restore --file "C:\\Downloads\\db_cluster-04-03-2024@14-16-59.backup.gz"')}
|
|
120
|
+
${chalk.gray('# Importa e restaura diretamente o arquivo de backup')}
|
|
121
|
+
|
|
122
|
+
${chalk.white('npx smoonb restore --file "backup.backup.gz" --storage "meu-projeto.storage.zip"')}
|
|
123
|
+
${chalk.gray('# Importa e restaura backup e storage juntos')}
|
|
110
124
|
|
|
111
125
|
${chalk.yellow.bold('Fluxo do restore:')}
|
|
112
126
|
1. Validação Docker
|
|
113
127
|
2. Consentimento para ler/escrever .env.local
|
|
114
128
|
3. Mapeamento de variáveis de ambiente
|
|
115
|
-
4. Seleção de backup disponível
|
|
129
|
+
4. Seleção de backup disponível (pula se --file fornecido)
|
|
116
130
|
5. Seleção de componentes para restaurar
|
|
117
131
|
6. Resumo detalhado e confirmação
|
|
118
132
|
7. Execução da restauração
|
|
119
133
|
|
|
134
|
+
${chalk.yellow.bold('Quando usar --file:')}
|
|
135
|
+
• Importa automaticamente o arquivo de backup antes de restaurar
|
|
136
|
+
• Elimina a etapa de seleção de backup
|
|
137
|
+
• Se --storage fornecido, importa também o arquivo de storage
|
|
138
|
+
• Útil para restaurar backups baixados diretamente do Dashboard
|
|
139
|
+
|
|
120
140
|
${chalk.yellow.bold('Formatos suportados:')}
|
|
121
141
|
• .backup.gz (compactado) - Descompacta automaticamente
|
|
122
142
|
• .backup (descompactado) - Restaura diretamente
|
|
123
143
|
`)
|
|
124
|
-
.action(
|
|
144
|
+
.action(async (options) => {
|
|
145
|
+
await commands.restore({ file: options.file, storage: options.storage });
|
|
146
|
+
});
|
|
125
147
|
|
|
126
148
|
program
|
|
127
149
|
.command('check')
|
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs');
|
|
4
|
+
const fsPromises = require('fs').promises;
|
|
4
5
|
const { readEnvFile, writeEnvFile, backupEnvFile } = require('../../utils/env');
|
|
5
6
|
const { saveEnvMap } = require('../../utils/envMap');
|
|
6
7
|
const { mapEnvVariablesInteractively } = require('../../interactive/envMapper');
|
|
7
8
|
const { showBetaBanner } = require('../../utils/banner');
|
|
8
9
|
const { listValidBackups, showRestoreSummary } = require('./utils');
|
|
9
10
|
const { confirm } = require('../../utils/prompt');
|
|
11
|
+
const { ensureDir } = require('../../utils/fsx');
|
|
10
12
|
const step00DockerValidation = require('../backup/steps/00-docker-validation');
|
|
11
13
|
|
|
12
14
|
// Importar todas as etapas
|
|
@@ -19,7 +21,81 @@ const step06Storage = require('./steps/06-storage');
|
|
|
19
21
|
const step07DatabaseSettings = require('./steps/07-database-settings');
|
|
20
22
|
const step08RealtimeSettings = require('./steps/08-realtime-settings');
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Função auxiliar para importar arquivo de backup e storage (reutiliza lógica do comando import)
|
|
26
|
+
*/
|
|
27
|
+
async function importBackupFile(sourceFile, sourceStorageFile, outputDir) {
|
|
28
|
+
// Validar arquivo de backup
|
|
29
|
+
try {
|
|
30
|
+
await fsPromises.access(sourceFile);
|
|
31
|
+
} catch {
|
|
32
|
+
throw new Error(`Arquivo de backup não encontrado: ${sourceFile}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Verificar se é um arquivo .backup.gz ou .backup
|
|
36
|
+
if (!sourceFile.endsWith('.backup.gz') && !sourceFile.endsWith('.backup')) {
|
|
37
|
+
throw new Error('Arquivo de backup deve ser .backup.gz ou .backup');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Validar arquivo de storage se fornecido
|
|
41
|
+
if (sourceStorageFile) {
|
|
42
|
+
try {
|
|
43
|
+
await fsPromises.access(sourceStorageFile);
|
|
44
|
+
} catch {
|
|
45
|
+
throw new Error(`Arquivo de storage não encontrado: ${sourceStorageFile}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Verificar se é um arquivo .storage.zip
|
|
49
|
+
if (!sourceStorageFile.endsWith('.storage.zip')) {
|
|
50
|
+
throw new Error('Arquivo de storage deve ser .storage.zip');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Extrair informações do nome do arquivo de backup
|
|
55
|
+
// Formato esperado: db_cluster-DD-MM-YYYY@HH-MM-SS.backup.gz
|
|
56
|
+
const fileName = path.basename(sourceFile);
|
|
57
|
+
const match = fileName.match(/db_cluster-(\d{2})-(\d{2})-(\d{4})@(\d{2})-(\d{2})-(\d{2})\.backup(\.gz)?/);
|
|
58
|
+
|
|
59
|
+
if (!match) {
|
|
60
|
+
throw new Error('Nome do arquivo de backup não está no formato esperado do Dashboard. Formato esperado: db_cluster-DD-MM-YYYY@HH-MM-SS.backup.gz');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const [, day, month, year, hour, minute, second] = match;
|
|
64
|
+
|
|
65
|
+
// Criar nome da pasta no formato backup-YYYY-MM-DD-HH-MM-SS
|
|
66
|
+
const backupDirName = `backup-${year}-${month}-${day}-${hour}-${minute}-${second}`;
|
|
67
|
+
const backupDir = path.join(outputDir, backupDirName);
|
|
68
|
+
|
|
69
|
+
// Criar diretório de backup
|
|
70
|
+
await ensureDir(backupDir);
|
|
71
|
+
console.log(chalk.blue(`📁 Importando backup para: ${backupDirName}`));
|
|
72
|
+
|
|
73
|
+
// Copiar arquivo de backup para o diretório de backup
|
|
74
|
+
const destFile = path.join(backupDir, fileName);
|
|
75
|
+
await fsPromises.copyFile(sourceFile, destFile);
|
|
76
|
+
|
|
77
|
+
// Obter tamanho do arquivo de backup
|
|
78
|
+
const stats = await fsPromises.stat(destFile);
|
|
79
|
+
const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
|
|
80
|
+
|
|
81
|
+
console.log(chalk.green(`✅ Arquivo de backup importado: ${fileName} (${sizeMB} MB)`));
|
|
82
|
+
|
|
83
|
+
// Copiar arquivo de storage se fornecido
|
|
84
|
+
if (sourceStorageFile) {
|
|
85
|
+
const storageFileName = path.basename(sourceStorageFile);
|
|
86
|
+
const destStorageFile = path.join(backupDir, storageFileName);
|
|
87
|
+
await fsPromises.copyFile(sourceStorageFile, destStorageFile);
|
|
88
|
+
|
|
89
|
+
const storageStats = await fsPromises.stat(destStorageFile);
|
|
90
|
+
const storageSizeMB = (storageStats.size / (1024 * 1024)).toFixed(2);
|
|
91
|
+
|
|
92
|
+
console.log(chalk.green(`✅ Arquivo de storage importado: ${storageFileName} (${storageSizeMB} MB)`));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return backupDir;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = async (options) => {
|
|
23
99
|
showBetaBanner();
|
|
24
100
|
|
|
25
101
|
try {
|
|
@@ -94,20 +170,43 @@ module.exports = async (_options) => {
|
|
|
94
170
|
targetAccessToken: getValue('SUPABASE_ACCESS_TOKEN')
|
|
95
171
|
};
|
|
96
172
|
|
|
97
|
-
|
|
173
|
+
const outputDir = getValue('SMOONB_OUTPUT_DIR') || './backups';
|
|
174
|
+
let selectedBackup = null;
|
|
98
175
|
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
console.log(chalk.
|
|
105
|
-
|
|
176
|
+
// Se --file foi fornecido, importar o arquivo e auto-selecionar
|
|
177
|
+
if (options.file) {
|
|
178
|
+
const sourceFile = path.resolve(options.file);
|
|
179
|
+
const sourceStorageFile = options.storage ? path.resolve(options.storage) : null;
|
|
180
|
+
|
|
181
|
+
console.log(chalk.blue(`📁 Importando arquivo de backup...`));
|
|
182
|
+
const importedBackupDir = await importBackupFile(sourceFile, sourceStorageFile, outputDir);
|
|
183
|
+
|
|
184
|
+
// Listar backups válidos para encontrar o backup importado
|
|
185
|
+
const validBackups = await listValidBackups(outputDir);
|
|
186
|
+
selectedBackup = validBackups.find(b => b.path === importedBackupDir);
|
|
187
|
+
|
|
188
|
+
if (!selectedBackup) {
|
|
189
|
+
throw new Error('Não foi possível encontrar o backup importado');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
console.log(chalk.green(`✅ Backup importado e selecionado automaticamente: ${path.basename(selectedBackup.path)}`));
|
|
193
|
+
} else {
|
|
194
|
+
// Fluxo normal: listar e selecionar backup interativamente
|
|
195
|
+
console.log(chalk.blue(`📁 Buscando backups em: ${outputDir}`));
|
|
196
|
+
|
|
197
|
+
// 1. Listar backups válidos (.backup.gz)
|
|
198
|
+
const validBackups = await listValidBackups(outputDir);
|
|
199
|
+
|
|
200
|
+
if (validBackups.length === 0) {
|
|
201
|
+
console.error(chalk.red('❌ Nenhum backup válido encontrado'));
|
|
202
|
+
console.log(chalk.yellow('💡 Execute primeiro: npx smoonb backup'));
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// 2. Selecionar backup interativamente
|
|
207
|
+
selectedBackup = await step00BackupSelection(validBackups);
|
|
106
208
|
}
|
|
107
209
|
|
|
108
|
-
// 2. Selecionar backup interativamente
|
|
109
|
-
const selectedBackup = await step00BackupSelection(validBackups);
|
|
110
|
-
|
|
111
210
|
// 3. Perguntar quais componentes restaurar
|
|
112
211
|
const components = await step01ComponentsSelection(selectedBackup.path);
|
|
113
212
|
|