smoonb 0.0.9 → 0.0.10
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/package.json +1 -1
- package/src/commands/backup.js +59 -64
- package/src/commands/check.js +38 -43
- package/src/commands/config.js +107 -56
- package/src/commands/functions.js +109 -125
- package/src/commands/restore.js +55 -60
package/package.json
CHANGED
package/src/commands/backup.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const { Command } = require('commander');
|
|
2
1
|
const chalk = require('chalk');
|
|
3
2
|
const path = require('path');
|
|
4
3
|
const { ensureBin, runCommand } = require('../utils/cli');
|
|
@@ -8,68 +7,66 @@ const { readConfig, validateFor } = require('../utils/config');
|
|
|
8
7
|
const { IntrospectionService } = require('../services/introspect');
|
|
9
8
|
const { showBetaBanner } = require('../index');
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
console.error(chalk.red('❌ databaseUrl não configurada'));
|
|
35
|
-
console.log(chalk.yellow('💡 Configure databaseUrl no .smoonbrc'));
|
|
36
|
-
process.exit(1);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Resolver diretório de saída
|
|
40
|
-
const outputDir = options.output || config.backup.outputDir;
|
|
41
|
-
|
|
42
|
-
// Criar diretório de backup com timestamp
|
|
43
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
44
|
-
const backupDir = path.join(outputDir, `backup-${timestamp}`);
|
|
45
|
-
await ensureDir(backupDir);
|
|
46
|
-
|
|
47
|
-
console.log(chalk.blue(`🚀 Iniciando backup do projeto: ${config.supabase.projectId}`));
|
|
48
|
-
console.log(chalk.blue(`📁 Diretório: ${backupDir}`));
|
|
49
|
-
|
|
50
|
-
// 1. Backup da Database usando Supabase CLI
|
|
51
|
-
console.log(chalk.blue('\n📊 1/3 - Backup da Database PostgreSQL...'));
|
|
52
|
-
await backupDatabaseWithSupabaseCLI(databaseUrl, backupDir);
|
|
53
|
-
|
|
54
|
-
// 2. Gerar inventário real
|
|
55
|
-
console.log(chalk.blue('\n🔍 2/3 - Gerando inventário completo...'));
|
|
56
|
-
await generateInventory(config, backupDir);
|
|
57
|
-
|
|
58
|
-
// 3. Backup das Edge Functions locais
|
|
59
|
-
console.log(chalk.blue('\n⚡ 3/3 - Backup das Edge Functions locais...'));
|
|
60
|
-
await backupLocalFunctions(backupDir);
|
|
61
|
-
|
|
62
|
-
// Gerar manifesto do backup
|
|
63
|
-
await generateBackupManifest(config, backupDir);
|
|
64
|
-
|
|
65
|
-
console.log(chalk.green('\n🎉 Backup completo finalizado!'));
|
|
66
|
-
console.log(chalk.blue(`📁 Localização: ${backupDir}`));
|
|
67
|
-
|
|
68
|
-
} catch (error) {
|
|
69
|
-
console.error(chalk.red(`❌ Erro no backup: ${error.message}`));
|
|
10
|
+
// Exportar FUNÇÃO em vez de objeto Command
|
|
11
|
+
module.exports = async (options) => {
|
|
12
|
+
showBetaBanner();
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
// Verificar se Supabase CLI está disponível
|
|
16
|
+
const supabasePath = await ensureBin('supabase');
|
|
17
|
+
if (!supabasePath) {
|
|
18
|
+
console.error(chalk.red('❌ Supabase CLI não encontrado'));
|
|
19
|
+
console.log(chalk.yellow('💡 Instale o Supabase CLI:'));
|
|
20
|
+
console.log(chalk.yellow(' npm install -g supabase'));
|
|
21
|
+
console.log(chalk.yellow(' ou visite: https://supabase.com/docs/guides/cli'));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Carregar e validar configuração
|
|
26
|
+
const config = await readConfig();
|
|
27
|
+
validateFor(config, 'backup');
|
|
28
|
+
|
|
29
|
+
const databaseUrl = config.supabase.databaseUrl;
|
|
30
|
+
if (!databaseUrl) {
|
|
31
|
+
console.error(chalk.red('❌ databaseUrl não configurada'));
|
|
32
|
+
console.log(chalk.yellow('💡 Configure databaseUrl no .smoonbrc'));
|
|
70
33
|
process.exit(1);
|
|
71
34
|
}
|
|
72
|
-
|
|
35
|
+
|
|
36
|
+
// Resolver diretório de saída
|
|
37
|
+
const outputDir = options.output || config.backup.outputDir;
|
|
38
|
+
|
|
39
|
+
// Criar diretório de backup com timestamp
|
|
40
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
41
|
+
const backupDir = path.join(outputDir, `backup-${timestamp}`);
|
|
42
|
+
await ensureDir(backupDir);
|
|
43
|
+
|
|
44
|
+
console.log(chalk.blue(`🚀 Iniciando backup do projeto: ${config.supabase.projectId}`));
|
|
45
|
+
console.log(chalk.blue(`📁 Diretório: ${backupDir}`));
|
|
46
|
+
|
|
47
|
+
// 1. Backup da Database usando Supabase CLI
|
|
48
|
+
console.log(chalk.blue('\n📊 1/3 - Backup da Database PostgreSQL...'));
|
|
49
|
+
await backupDatabaseWithSupabaseCLI(databaseUrl, backupDir);
|
|
50
|
+
|
|
51
|
+
// 2. Gerar inventário real
|
|
52
|
+
console.log(chalk.blue('\n🔍 2/3 - Gerando inventário completo...'));
|
|
53
|
+
await generateInventory(config, backupDir);
|
|
54
|
+
|
|
55
|
+
// 3. Backup das Edge Functions locais
|
|
56
|
+
console.log(chalk.blue('\n⚡ 3/3 - Backup das Edge Functions locais...'));
|
|
57
|
+
await backupLocalFunctions(backupDir);
|
|
58
|
+
|
|
59
|
+
// Gerar manifesto do backup
|
|
60
|
+
await generateBackupManifest(config, backupDir);
|
|
61
|
+
|
|
62
|
+
console.log(chalk.green('\n🎉 Backup completo finalizado!'));
|
|
63
|
+
console.log(chalk.blue(`📁 Localização: ${backupDir}`));
|
|
64
|
+
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(chalk.red(`❌ Erro no backup: ${error.message}`));
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
73
70
|
|
|
74
71
|
// Backup da database usando Supabase CLI
|
|
75
72
|
async function backupDatabaseWithSupabaseCLI(databaseUrl, backupDir) {
|
|
@@ -172,6 +169,4 @@ async function generateBackupManifest(config, backupDir) {
|
|
|
172
169
|
|
|
173
170
|
const manifestPath = path.join(backupDir, 'backup-manifest.json');
|
|
174
171
|
await writeJson(manifestPath, manifest);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
module.exports = backupCommand;
|
|
172
|
+
}
|
package/src/commands/check.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const { Command } = require('commander');
|
|
2
1
|
const chalk = require('chalk');
|
|
3
2
|
const path = require('path');
|
|
4
3
|
const fs = require('fs');
|
|
@@ -8,53 +7,51 @@ const { writeJson } = require('../utils/fsx');
|
|
|
8
7
|
const { IntrospectionService } = require('../services/introspect');
|
|
9
8
|
const { showBetaBanner } = require('../index');
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
process.exit(1);
|
|
25
|
-
}
|
|
10
|
+
// Exportar FUNÇÃO em vez de objeto Command
|
|
11
|
+
module.exports = async (options) => {
|
|
12
|
+
showBetaBanner();
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
// Verificar se psql está disponível
|
|
16
|
+
const psqlPath = await ensureBin('psql');
|
|
17
|
+
if (!psqlPath) {
|
|
18
|
+
console.error(chalk.red('❌ psql não encontrado'));
|
|
19
|
+
console.log(chalk.yellow('💡 Instale PostgreSQL:'));
|
|
20
|
+
console.log(chalk.yellow(' https://www.postgresql.org/download/'));
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
// Carregar configuração
|
|
25
|
+
const config = await readConfig();
|
|
26
|
+
validateFor(config, 'backup'); // Usar mesma validação do backup
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
const databaseUrl = config.supabase.databaseUrl;
|
|
29
|
+
if (!databaseUrl) {
|
|
30
|
+
console.error(chalk.red('❌ databaseUrl não configurada'));
|
|
31
|
+
console.log(chalk.yellow('💡 Configure databaseUrl no .smoonbrc'));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
37
34
|
|
|
38
|
-
|
|
35
|
+
console.log(chalk.blue(`🔍 Verificando integridade do projeto: ${config.supabase.projectId}`));
|
|
39
36
|
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
// Executar verificações
|
|
38
|
+
const report = await performChecks(config, databaseUrl);
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
// Salvar relatório
|
|
41
|
+
const reportPath = path.resolve(options.output || 'check-report.json');
|
|
42
|
+
await writeJson(reportPath, report);
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
// Mostrar resumo
|
|
45
|
+
showCheckSummary(report);
|
|
49
46
|
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
console.log(chalk.green('\n🎉 Verificação concluída!'));
|
|
48
|
+
console.log(chalk.blue(`📋 Relatório salvo em: ${reportPath}`));
|
|
52
49
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error(chalk.red(`❌ Erro na verificação: ${error.message}`));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
58
55
|
|
|
59
56
|
// Executar todas as verificações
|
|
60
57
|
async function performChecks(config, databaseUrl) {
|
|
@@ -268,6 +265,4 @@ function showCheckSummary(report) {
|
|
|
268
265
|
} else {
|
|
269
266
|
console.log(chalk.yellow('⚠️ Algumas verificações falharam. Verifique o relatório completo.'));
|
|
270
267
|
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
module.exports = checkCommand;
|
|
268
|
+
}
|
package/src/commands/config.js
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Comando de configuração do smoonb
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
1
|
const chalk = require('chalk');
|
|
6
2
|
const fs = require('fs').promises;
|
|
7
3
|
const path = require('path');
|
|
8
4
|
const os = require('os');
|
|
5
|
+
const { showBetaBanner } = require('../index');
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
console.log(chalk.red.bold('🚨 USE POR SUA CONTA E RISCO - Pode causar perda de dados!'));
|
|
14
|
-
console.log(chalk.red.bold('❌ NÃO NOS RESPONSABILIZAMOS por qualquer perda de dados!\n'));
|
|
7
|
+
// Exportar FUNÇÃO em vez de objeto Command
|
|
8
|
+
module.exports = async (options) => {
|
|
9
|
+
showBetaBanner();
|
|
15
10
|
|
|
16
11
|
console.log(chalk.cyan.bold('⚙️ Configuração do smoonb...\n'));
|
|
17
12
|
|
|
@@ -19,60 +14,116 @@ async function configCommand(options) {
|
|
|
19
14
|
const configPath = path.join(process.cwd(), '.smoonbrc');
|
|
20
15
|
|
|
21
16
|
if (options.init) {
|
|
22
|
-
|
|
23
|
-
const defaultConfig = {
|
|
24
|
-
supabase: {
|
|
25
|
-
projectId: '',
|
|
26
|
-
url: '',
|
|
27
|
-
serviceKey: '',
|
|
28
|
-
anonKey: '',
|
|
29
|
-
databaseUrl: ''
|
|
30
|
-
},
|
|
31
|
-
backup: {
|
|
32
|
-
includeFunctions: true,
|
|
33
|
-
includeStorage: true,
|
|
34
|
-
includeAuth: true,
|
|
35
|
-
includeRealtime: true,
|
|
36
|
-
outputDir: './backups',
|
|
37
|
-
pgDumpPath: 'C:\\Program Files\\PostgreSQL\\17\\bin\\pg_dump.exe'
|
|
38
|
-
},
|
|
39
|
-
restore: {
|
|
40
|
-
cleanRestore: false,
|
|
41
|
-
verifyAfterRestore: true
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
await fs.writeFile(configPath, JSON.stringify(defaultConfig, null, 2));
|
|
46
|
-
console.log(chalk.green('✅ Arquivo de configuração criado:'), configPath);
|
|
47
|
-
console.log(chalk.yellow('💡 Edite o arquivo para configurar suas credenciais Supabase'));
|
|
48
|
-
|
|
17
|
+
await initializeConfig(configPath);
|
|
49
18
|
} else if (options.show) {
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
const configContent = await fs.readFile(configPath, 'utf8');
|
|
53
|
-
const config = JSON.parse(configContent);
|
|
54
|
-
|
|
55
|
-
console.log(chalk.green('📋 Configuração atual:'));
|
|
56
|
-
console.log(chalk.blue('📁 Arquivo:'), configPath);
|
|
57
|
-
console.log(chalk.gray(JSON.stringify(config, null, 2)));
|
|
58
|
-
|
|
59
|
-
} catch (error) {
|
|
60
|
-
console.log(chalk.yellow('⚠️ Arquivo de configuração não encontrado'));
|
|
61
|
-
console.log(chalk.yellow('💡 Use'), chalk.cyan('smoonb config --init'), chalk.yellow('para criar a configuração'));
|
|
62
|
-
}
|
|
63
|
-
|
|
19
|
+
await showConfig(configPath);
|
|
64
20
|
} else {
|
|
65
|
-
// Mostrar ajuda
|
|
66
21
|
console.log(chalk.yellow('💡 Opções disponíveis:'));
|
|
67
|
-
console.log(chalk.
|
|
68
|
-
console.log(chalk.
|
|
69
|
-
console.log(chalk.blue('\n📁 Arquivo de configuração:'), configPath);
|
|
22
|
+
console.log(chalk.gray(' --init Inicializar configuração'));
|
|
23
|
+
console.log(chalk.gray(' --show Mostrar configuração atual'));
|
|
70
24
|
}
|
|
71
25
|
|
|
72
26
|
} catch (error) {
|
|
73
|
-
console.error(chalk.red
|
|
27
|
+
console.error(chalk.red('❌ Erro na configuração:'), error.message);
|
|
74
28
|
process.exit(1);
|
|
75
29
|
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Inicializar configuração
|
|
33
|
+
async function initializeConfig(configPath) {
|
|
34
|
+
console.log(chalk.blue('🔧 Inicializando configuração...'));
|
|
35
|
+
|
|
36
|
+
const defaultConfig = {
|
|
37
|
+
supabase: {
|
|
38
|
+
projectId: 'your-project-id-here',
|
|
39
|
+
url: 'https://your-project-id.supabase.co',
|
|
40
|
+
serviceKey: 'your-service-key-here',
|
|
41
|
+
anonKey: 'your-anon-key-here',
|
|
42
|
+
databaseUrl: 'postgresql://postgres:[password]@db.your-project-id.supabase.co:5432/postgres'
|
|
43
|
+
},
|
|
44
|
+
backup: {
|
|
45
|
+
includeFunctions: true,
|
|
46
|
+
includeStorage: true,
|
|
47
|
+
includeAuth: true,
|
|
48
|
+
includeRealtime: true,
|
|
49
|
+
outputDir: './backups'
|
|
50
|
+
},
|
|
51
|
+
restore: {
|
|
52
|
+
cleanRestore: true,
|
|
53
|
+
verifyAfterRestore: true
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
await fs.writeFile(configPath, JSON.stringify(defaultConfig, null, 2));
|
|
59
|
+
console.log(chalk.green('✅ Arquivo de configuração criado: .smoonbrc'));
|
|
60
|
+
console.log(chalk.yellow('\n📝 Próximos passos:'));
|
|
61
|
+
console.log(chalk.gray(' 1. Edite .smoonbrc com suas credenciais Supabase'));
|
|
62
|
+
console.log(chalk.gray(' 2. Substitua os valores placeholder pelos reais'));
|
|
63
|
+
console.log(chalk.gray(' 3. Execute: npx smoonb backup'));
|
|
64
|
+
} catch (error) {
|
|
65
|
+
throw new Error(`Falha ao criar arquivo de configuração: ${error.message}`);
|
|
66
|
+
}
|
|
76
67
|
}
|
|
77
68
|
|
|
78
|
-
|
|
69
|
+
// Mostrar configuração atual
|
|
70
|
+
async function showConfig(configPath) {
|
|
71
|
+
console.log(chalk.blue('📋 Configuração atual:'));
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const configContent = await fs.readFile(configPath, 'utf8');
|
|
75
|
+
const config = JSON.parse(configContent);
|
|
76
|
+
|
|
77
|
+
console.log(chalk.green('✅ Arquivo de configuração encontrado'));
|
|
78
|
+
console.log(chalk.gray(` - Localização: ${configPath}`));
|
|
79
|
+
|
|
80
|
+
if (config.supabase?.projectId && config.supabase.projectId !== 'your-project-id-here') {
|
|
81
|
+
console.log(chalk.gray(` - Project ID: ${config.supabase.projectId}`));
|
|
82
|
+
} else {
|
|
83
|
+
console.log(chalk.yellow(' - Project ID: Não configurado'));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (config.supabase?.url && config.supabase.url !== 'https://your-project-id.supabase.co') {
|
|
87
|
+
console.log(chalk.gray(` - Supabase URL: ${config.supabase.url}`));
|
|
88
|
+
} else {
|
|
89
|
+
console.log(chalk.yellow(' - Supabase URL: Não configurado'));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (config.supabase?.serviceKey && config.supabase.serviceKey !== 'your-service-key-here') {
|
|
93
|
+
console.log(chalk.gray(' - Service Key: Configurada'));
|
|
94
|
+
} else {
|
|
95
|
+
console.log(chalk.yellow(' - Service Key: Não configurada'));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (config.supabase?.anonKey && config.supabase.anonKey !== 'your-anon-key-here') {
|
|
99
|
+
console.log(chalk.gray(' - Anon Key: Configurada'));
|
|
100
|
+
} else {
|
|
101
|
+
console.log(chalk.yellow(' - Anon Key: Não configurada'));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (config.supabase?.databaseUrl && !config.supabase.databaseUrl.includes('[password]')) {
|
|
105
|
+
console.log(chalk.gray(' - Database URL: Configurada'));
|
|
106
|
+
} else {
|
|
107
|
+
console.log(chalk.yellow(' - Database URL: Não configurada'));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log(chalk.blue('\n📊 Configurações de backup:'));
|
|
111
|
+
console.log(chalk.gray(` - Output Dir: ${config.backup?.outputDir || './backups'}`));
|
|
112
|
+
console.log(chalk.gray(` - Include Functions: ${config.backup?.includeFunctions || true}`));
|
|
113
|
+
console.log(chalk.gray(` - Include Storage: ${config.backup?.includeStorage || true}`));
|
|
114
|
+
console.log(chalk.gray(` - Include Auth: ${config.backup?.includeAuth || true}`));
|
|
115
|
+
console.log(chalk.gray(` - Include Realtime: ${config.backup?.includeRealtime || true}`));
|
|
116
|
+
|
|
117
|
+
console.log(chalk.blue('\n🔄 Configurações de restore:'));
|
|
118
|
+
console.log(chalk.gray(` - Clean Restore: ${config.restore?.cleanRestore || true}`));
|
|
119
|
+
console.log(chalk.gray(` - Verify After Restore: ${config.restore?.verifyAfterRestore || true}`));
|
|
120
|
+
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (error.code === 'ENOENT') {
|
|
123
|
+
console.log(chalk.yellow('⚠️ Arquivo de configuração não encontrado'));
|
|
124
|
+
console.log(chalk.gray(' - Use: npx smoonb config --init'));
|
|
125
|
+
} else {
|
|
126
|
+
throw new Error(`Falha ao ler arquivo de configuração: ${error.message}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -1,149 +1,133 @@
|
|
|
1
|
-
const { Command } = require('commander');
|
|
2
1
|
const chalk = require('chalk');
|
|
3
2
|
const { ensureBin, runCommand } = require('../utils/cli');
|
|
4
3
|
const { readConfig, validateFor } = require('../utils/config');
|
|
5
4
|
const { showBetaBanner } = require('../index');
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
console.log(chalk.yellow(' ou visite: https://supabase.com/docs/guides/cli'));
|
|
20
|
-
process.exit(1);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
console.log(chalk.blue('⚡ Comandos disponíveis para Edge Functions:'));
|
|
24
|
-
console.log(chalk.yellow('\n📋 Listar functions:'));
|
|
25
|
-
console.log(chalk.gray(' npx smoonb functions list'));
|
|
26
|
-
console.log(chalk.yellow('\n🚀 Deploy functions:'));
|
|
27
|
-
console.log(chalk.gray(' npx smoonb functions push'));
|
|
28
|
-
console.log(chalk.yellow('\n📥 Pull functions (se disponível):'));
|
|
29
|
-
console.log(chalk.gray(' npx smoonb functions pull'));
|
|
30
|
-
console.log(chalk.yellow('\n💡 Para mais opções, use o Supabase CLI diretamente:'));
|
|
31
|
-
console.log(chalk.gray(' supabase functions --help'));
|
|
32
|
-
|
|
33
|
-
} catch (error) {
|
|
34
|
-
console.error(chalk.red(`❌ Erro: ${error.message}`));
|
|
6
|
+
// Exportar FUNÇÃO em vez de objeto Command
|
|
7
|
+
module.exports = async (options) => {
|
|
8
|
+
showBetaBanner();
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
// Verificar se Supabase CLI está disponível
|
|
12
|
+
const supabasePath = await ensureBin('supabase');
|
|
13
|
+
if (!supabasePath) {
|
|
14
|
+
console.error(chalk.red('❌ Supabase CLI não encontrado'));
|
|
15
|
+
console.log(chalk.yellow('💡 Instale o Supabase CLI:'));
|
|
16
|
+
console.log(chalk.yellow(' npm install -g supabase'));
|
|
17
|
+
console.log(chalk.yellow(' ou visite: https://supabase.com/docs/guides/cli'));
|
|
35
18
|
process.exit(1);
|
|
36
19
|
}
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// Subcomando para listar functions
|
|
40
|
-
functionsCommand
|
|
41
|
-
.command('list')
|
|
42
|
-
.description('Listar Edge Functions do projeto')
|
|
43
|
-
.action(async () => {
|
|
44
|
-
showBetaBanner();
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
const config = await readConfig();
|
|
48
|
-
validateFor(config, 'inventory');
|
|
49
|
-
|
|
50
|
-
console.log(chalk.blue('📋 Listando Edge Functions...'));
|
|
51
|
-
|
|
52
|
-
const { stdout, stderr } = await runCommand(
|
|
53
|
-
'supabase functions list',
|
|
54
|
-
{
|
|
55
|
-
env: {
|
|
56
|
-
...process.env,
|
|
57
|
-
SUPABASE_ACCESS_TOKEN: config.supabase.serviceKey
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
);
|
|
61
20
|
|
|
62
|
-
|
|
63
|
-
|
|
21
|
+
console.log(chalk.blue('⚡ Comandos disponíveis para Edge Functions:'));
|
|
22
|
+
console.log(chalk.yellow('\n📋 Listar functions:'));
|
|
23
|
+
console.log(chalk.gray(' npx smoonb functions list'));
|
|
24
|
+
console.log(chalk.yellow('\n🚀 Deploy functions:'));
|
|
25
|
+
console.log(chalk.gray(' npx smoonb functions push'));
|
|
26
|
+
console.log(chalk.yellow('\n📥 Pull functions (se disponível):'));
|
|
27
|
+
console.log(chalk.gray(' npx smoonb functions pull'));
|
|
28
|
+
console.log(chalk.yellow('\n💡 Para mais opções, use o Supabase CLI diretamente:'));
|
|
29
|
+
console.log(chalk.gray(' supabase functions --help'));
|
|
30
|
+
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error(chalk.red(`❌ Erro: ${error.message}`));
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Função para listar functions
|
|
38
|
+
async function listFunctions() {
|
|
39
|
+
try {
|
|
40
|
+
const config = await readConfig();
|
|
41
|
+
validateFor(config, 'inventory');
|
|
42
|
+
|
|
43
|
+
console.log(chalk.blue('📋 Listando Edge Functions...'));
|
|
44
|
+
|
|
45
|
+
const { stdout, stderr } = await runCommand(
|
|
46
|
+
'supabase functions list',
|
|
47
|
+
{
|
|
48
|
+
env: {
|
|
49
|
+
...process.env,
|
|
50
|
+
SUPABASE_ACCESS_TOKEN: config.supabase.serviceKey
|
|
51
|
+
}
|
|
64
52
|
}
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
if (stderr && !stderr.includes('WARN')) {
|
|
56
|
+
console.log(chalk.yellow(`⚠️ Avisos: ${stderr}`));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log(chalk.green('✅ Edge Functions listadas:'));
|
|
60
|
+
console.log(stdout);
|
|
61
|
+
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(chalk.red(`❌ Erro ao listar functions: ${error.message}`));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
// Função para deploy de functions
|
|
69
|
+
async function pushFunctions(projectRef) {
|
|
70
|
+
try {
|
|
71
|
+
const config = await readConfig();
|
|
72
|
+
const projectId = projectRef || config.supabase.projectId;
|
|
68
73
|
|
|
69
|
-
|
|
70
|
-
console.error(chalk.red(
|
|
74
|
+
if (!projectId) {
|
|
75
|
+
console.error(chalk.red('❌ Project ID não encontrado'));
|
|
76
|
+
console.log(chalk.yellow('💡 Use: npx smoonb functions push --project-ref <id>'));
|
|
71
77
|
process.exit(1);
|
|
72
78
|
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// Subcomando para deploy de functions
|
|
76
|
-
functionsCommand
|
|
77
|
-
.command('push')
|
|
78
|
-
.description('Fazer deploy das Edge Functions')
|
|
79
|
-
.option('--project-ref <ref>', 'ID do projeto Supabase')
|
|
80
|
-
.action(async (options) => {
|
|
81
|
-
showBetaBanner();
|
|
82
|
-
|
|
83
|
-
try {
|
|
84
|
-
const config = await readConfig();
|
|
85
|
-
const projectRef = options.projectRef || config.supabase.projectId;
|
|
86
|
-
|
|
87
|
-
if (!projectRef) {
|
|
88
|
-
console.error(chalk.red('❌ Project ID não encontrado'));
|
|
89
|
-
console.log(chalk.yellow('💡 Use: npx smoonb functions push --project-ref <id>'));
|
|
90
|
-
process.exit(1);
|
|
91
|
-
}
|
|
92
79
|
|
|
93
|
-
|
|
80
|
+
console.log(chalk.blue(`🚀 Fazendo deploy das Edge Functions para: ${projectId}`));
|
|
94
81
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
82
|
+
const { stdout, stderr } = await runCommand(
|
|
83
|
+
`supabase functions deploy --project-ref ${projectId}`,
|
|
84
|
+
{
|
|
85
|
+
env: {
|
|
86
|
+
...process.env,
|
|
87
|
+
SUPABASE_ACCESS_TOKEN: config.supabase.serviceKey
|
|
102
88
|
}
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
if (stderr && !stderr.includes('WARN')) {
|
|
106
|
-
console.log(chalk.yellow(`⚠️ Avisos: ${stderr}`));
|
|
107
89
|
}
|
|
90
|
+
);
|
|
108
91
|
|
|
109
|
-
|
|
110
|
-
console.log(
|
|
111
|
-
|
|
112
|
-
} catch (error) {
|
|
113
|
-
console.error(chalk.red(`❌ Erro no deploy: ${error.message}`));
|
|
114
|
-
process.exit(1);
|
|
92
|
+
if (stderr && !stderr.includes('WARN')) {
|
|
93
|
+
console.log(chalk.yellow(`⚠️ Avisos: ${stderr}`));
|
|
115
94
|
}
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// Subcomando para pull de functions
|
|
119
|
-
functionsCommand
|
|
120
|
-
.command('pull')
|
|
121
|
-
.description('Baixar Edge Functions do projeto remoto')
|
|
122
|
-
.option('--project-ref <ref>', 'ID do projeto Supabase')
|
|
123
|
-
.action(async (options) => {
|
|
124
|
-
showBetaBanner();
|
|
125
|
-
|
|
126
|
-
try {
|
|
127
|
-
const config = await readConfig();
|
|
128
|
-
const projectRef = options.projectRef || config.supabase.projectId;
|
|
129
|
-
|
|
130
|
-
if (!projectRef) {
|
|
131
|
-
console.error(chalk.red('❌ Project ID não encontrado'));
|
|
132
|
-
console.log(chalk.yellow('💡 Use: npx smoonb functions pull --project-ref <id>'));
|
|
133
|
-
process.exit(1);
|
|
134
|
-
}
|
|
135
95
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
96
|
+
console.log(chalk.green('✅ Deploy concluído:'));
|
|
97
|
+
console.log(stdout);
|
|
98
|
+
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error(chalk.red(`❌ Erro no deploy: ${error.message}`));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Função para pull de functions
|
|
106
|
+
async function pullFunctions(projectRef) {
|
|
107
|
+
try {
|
|
108
|
+
const config = await readConfig();
|
|
109
|
+
const projectId = projectRef || config.supabase.projectId;
|
|
142
110
|
|
|
143
|
-
|
|
144
|
-
console.error(chalk.red(
|
|
111
|
+
if (!projectId) {
|
|
112
|
+
console.error(chalk.red('❌ Project ID não encontrado'));
|
|
113
|
+
console.log(chalk.yellow('💡 Use: npx smoonb functions pull --project-ref <id>'));
|
|
145
114
|
process.exit(1);
|
|
146
115
|
}
|
|
147
|
-
});
|
|
148
116
|
|
|
149
|
-
|
|
117
|
+
console.log(chalk.yellow('⚠️ Pull de Edge Functions não é oficialmente suportado pelo Supabase CLI'));
|
|
118
|
+
console.log(chalk.yellow('💡 Para baixar código das functions remotas:'));
|
|
119
|
+
console.log(chalk.gray(' 1. Use o Dashboard do Supabase'));
|
|
120
|
+
console.log(chalk.gray(' 2. Ou clone o código do seu repositório Git'));
|
|
121
|
+
console.log(chalk.gray(' 3. Ou use a API do Supabase diretamente'));
|
|
122
|
+
console.log(chalk.blue('\n📚 Documentação: https://supabase.com/docs/guides/functions'));
|
|
123
|
+
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error(chalk.red(`❌ Erro: ${error.message}`));
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Exportar funções auxiliares para uso futuro
|
|
131
|
+
module.exports.list = listFunctions;
|
|
132
|
+
module.exports.push = pushFunctions;
|
|
133
|
+
module.exports.pull = pullFunctions;
|
package/src/commands/restore.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const { Command } = require('commander');
|
|
2
1
|
const chalk = require('chalk');
|
|
3
2
|
const path = require('path');
|
|
4
3
|
const fs = require('fs');
|
|
@@ -7,72 +6,70 @@ const { ensureBin, runCommand } = require('../utils/cli');
|
|
|
7
6
|
const { readConfig, validateFor } = require('../utils/config');
|
|
8
7
|
const { showBetaBanner } = require('../index');
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
9
|
+
// Exportar FUNÇÃO em vez de objeto Command
|
|
10
|
+
module.exports = async (options) => {
|
|
11
|
+
showBetaBanner();
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
// Verificar se psql está disponível
|
|
15
|
+
const psqlPath = await ensureBin('psql');
|
|
16
|
+
if (!psqlPath) {
|
|
17
|
+
console.error(chalk.red('❌ psql não encontrado'));
|
|
18
|
+
console.log(chalk.yellow('💡 Instale PostgreSQL:'));
|
|
19
|
+
console.log(chalk.yellow(' https://www.postgresql.org/download/'));
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
// Carregar configuração
|
|
24
|
+
const config = await readConfig();
|
|
25
|
+
validateFor(config, 'restore');
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
// Resolver URL da database
|
|
28
|
+
const databaseUrl = options.dbUrl || config.supabase.databaseUrl;
|
|
29
|
+
if (!databaseUrl) {
|
|
30
|
+
console.error(chalk.red('❌ databaseUrl não configurada'));
|
|
31
|
+
console.log(chalk.yellow('💡 Configure databaseUrl no .smoonbrc ou use --db-url'));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
37
34
|
|
|
38
|
-
|
|
35
|
+
console.log(chalk.blue(`🔍 Procurando backups em: ${config.backup.outputDir || './backups'}`));
|
|
39
36
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
// Listar backups disponíveis
|
|
38
|
+
const backups = await listAvailableBackups(config.backup.outputDir || './backups');
|
|
39
|
+
|
|
40
|
+
if (backups.length === 0) {
|
|
41
|
+
console.error(chalk.red('❌ Nenhum backup encontrado'));
|
|
42
|
+
console.log(chalk.yellow('💡 Execute primeiro: npx smoonb backup'));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
48
45
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
// Seleção interativa do backup
|
|
47
|
+
const selectedBackup = await selectBackup(backups);
|
|
48
|
+
|
|
49
|
+
console.log(chalk.blue(`🚀 Iniciando restauração do backup: ${selectedBackup.name}`));
|
|
50
|
+
console.log(chalk.blue(`🎯 Database destino: ${databaseUrl.replace(/:[^:]*@/, ':***@')}`));
|
|
54
51
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
// Verificar se é clean restore
|
|
53
|
+
if (config.restore.cleanRestore) {
|
|
54
|
+
await checkCleanRestore(databaseUrl);
|
|
55
|
+
}
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
// Executar restauração
|
|
58
|
+
await performRestore(selectedBackup.path, databaseUrl);
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
// Verificação pós-restore
|
|
61
|
+
if (config.restore.verifyAfterRestore) {
|
|
62
|
+
console.log(chalk.blue('\n🔍 Executando verificação pós-restore...'));
|
|
63
|
+
console.log(chalk.yellow('💡 Execute manualmente: npx smoonb check'));
|
|
64
|
+
}
|
|
68
65
|
|
|
69
|
-
|
|
66
|
+
console.log(chalk.green('\n🎉 Restauração concluída com sucesso!'));
|
|
70
67
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error(chalk.red(`❌ Erro na restauração: ${error.message}`));
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
76
73
|
|
|
77
74
|
// Listar backups disponíveis
|
|
78
75
|
async function listAvailableBackups(backupsDir) {
|
|
@@ -252,6 +249,4 @@ async function performRestore(backupDir, databaseUrl) {
|
|
|
252
249
|
throw new Error(`Falha ao executar ${sqlFile}: ${error.message}`);
|
|
253
250
|
}
|
|
254
251
|
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
module.exports = restoreCommand;
|
|
252
|
+
}
|