smoonb 0.0.9 → 0.0.11

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smoonb",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "Complete Supabase backup and migration tool - EXPERIMENTAL VERSION - USE AT YOUR OWN RISK",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -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');
@@ -6,70 +5,68 @@ const { ensureDir, writeJson, copyDir } = require('../utils/fsx');
6
5
  const { sha256 } = require('../utils/hash');
7
6
  const { readConfig, validateFor } = require('../utils/config');
8
7
  const { IntrospectionService } = require('../services/introspect');
9
- const { showBetaBanner } = require('../index');
8
+ const { showBetaBanner } = require('../utils/banner');
10
9
 
11
- const backupCommand = new Command('backup')
12
- .description('Backup completo do projeto Supabase usando Supabase CLI')
13
- .option('-o, --output <dir>', 'Diretório de saída')
14
- .action(async (options) => {
15
- showBetaBanner();
16
-
17
- try {
18
- // Verificar se Supabase CLI está disponível
19
- const supabasePath = await ensureBin('supabase');
20
- if (!supabasePath) {
21
- console.error(chalk.red(' Supabase CLI não encontrado'));
22
- console.log(chalk.yellow('💡 Instale o Supabase CLI:'));
23
- console.log(chalk.yellow(' npm install -g supabase'));
24
- console.log(chalk.yellow(' ou visite: https://supabase.com/docs/guides/cli'));
25
- process.exit(1);
26
- }
27
-
28
- // Carregar e validar configuração
29
- const config = await readConfig();
30
- validateFor(config, 'backup');
31
-
32
- const databaseUrl = config.supabase.databaseUrl;
33
- if (!databaseUrl) {
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
+ }
@@ -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');
@@ -6,55 +5,53 @@ const { ensureBin, runCommand } = require('../utils/cli');
6
5
  const { readConfig, validateFor } = require('../utils/config');
7
6
  const { writeJson } = require('../utils/fsx');
8
7
  const { IntrospectionService } = require('../services/introspect');
9
- const { showBetaBanner } = require('../index');
8
+ const { showBetaBanner } = require('../utils/banner');
10
9
 
11
- const checkCommand = new Command('check')
12
- .description('Verificar integridade do projeto Supabase após restauração')
13
- .option('-o, --output <file>', 'Arquivo de saída do relatório', 'check-report.json')
14
- .action(async (options) => {
15
- showBetaBanner();
16
-
17
- try {
18
- // Verificar se psql está disponível
19
- const psqlPath = await ensureBin('psql');
20
- if (!psqlPath) {
21
- console.error(chalk.red('❌ psql não encontrado'));
22
- console.log(chalk.yellow('💡 Instale PostgreSQL:'));
23
- console.log(chalk.yellow(' https://www.postgresql.org/download/'));
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
- // Carregar configuração
28
- const config = await readConfig();
29
- validateFor(config, 'backup'); // Usar mesma validação do backup
24
+ // Carregar configuração
25
+ const config = await readConfig();
26
+ validateFor(config, 'backup'); // Usar mesma validação do backup
30
27
 
31
- const databaseUrl = config.supabase.databaseUrl;
32
- if (!databaseUrl) {
33
- console.error(chalk.red('❌ databaseUrl não configurada'));
34
- console.log(chalk.yellow('💡 Configure databaseUrl no .smoonbrc'));
35
- process.exit(1);
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
- console.log(chalk.blue(`🔍 Verificando integridade do projeto: ${config.supabase.projectId}`));
35
+ console.log(chalk.blue(`🔍 Verificando integridade do projeto: ${config.supabase.projectId}`));
39
36
 
40
- // Executar verificações
41
- const report = await performChecks(config, databaseUrl);
37
+ // Executar verificações
38
+ const report = await performChecks(config, databaseUrl);
42
39
 
43
- // Salvar relatório
44
- const reportPath = path.resolve(options.output);
45
- await writeJson(reportPath, report);
40
+ // Salvar relatório
41
+ const reportPath = path.resolve(options.output || 'check-report.json');
42
+ await writeJson(reportPath, report);
46
43
 
47
- // Mostrar resumo
48
- showCheckSummary(report);
44
+ // Mostrar resumo
45
+ showCheckSummary(report);
49
46
 
50
- console.log(chalk.green('\n🎉 Verificação concluída!'));
51
- console.log(chalk.blue(`📋 Relatório salvo em: ${reportPath}`));
47
+ console.log(chalk.green('\n🎉 Verificação concluída!'));
48
+ console.log(chalk.blue(`📋 Relatório salvo em: ${reportPath}`));
52
49
 
53
- } catch (error) {
54
- console.error(chalk.red(`❌ Erro na verificação: ${error.message}`));
55
- process.exit(1);
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
+ }
@@ -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('../utils/banner');
9
6
 
10
- async function configCommand(options) {
11
- console.log(chalk.red.bold('🚀 smoonb - EXPERIMENTAL VERSION'));
12
- console.log(chalk.red.bold('⚠️ VERSÃO EXPERIMENTAL - NUNCA TESTADA EM PRODUÇÃO!'));
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
- // Inicializar configuração
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
- // Mostrar configuração atual
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.cyan(' --init'), chalk.gray(' Inicializar arquivo de configuração'));
68
- console.log(chalk.cyan(' --show'), chalk.gray(' Mostrar configuração atual'));
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.bold('❌ Erro durante a configuração:'), error.message);
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
- module.exports = configCommand;
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
- const { showBetaBanner } = require('../index');
6
-
7
- const functionsCommand = new Command('functions')
8
- .description('Gerenciar Edge Functions do Supabase')
9
- .action(async () => {
10
- showBetaBanner();
11
-
12
- try {
13
- // Verificar se Supabase CLI está disponível
14
- const supabasePath = await ensureBin('supabase');
15
- if (!supabasePath) {
16
- console.error(chalk.red(' Supabase CLI não encontrado'));
17
- console.log(chalk.yellow('💡 Instale o Supabase CLI:'));
18
- console.log(chalk.yellow(' npm install -g supabase'));
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}`));
4
+ const { showBetaBanner } = require('../utils/banner');
5
+
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
- if (stderr && !stderr.includes('WARN')) {
63
- console.log(chalk.yellow(`⚠️ Avisos: ${stderr}`));
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
- console.log(chalk.green('✅ Edge Functions listadas:'));
67
- console.log(stdout);
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
- } catch (error) {
70
- console.error(chalk.red(`❌ Erro ao listar functions: ${error.message}`));
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
- console.log(chalk.blue(`🚀 Fazendo deploy das Edge Functions para: ${projectRef}`));
80
+ console.log(chalk.blue(`🚀 Fazendo deploy das Edge Functions para: ${projectId}`));
94
81
 
95
- const { stdout, stderr } = await runCommand(
96
- `supabase functions deploy --project-ref ${projectRef}`,
97
- {
98
- env: {
99
- ...process.env,
100
- SUPABASE_ACCESS_TOKEN: config.supabase.serviceKey
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
- console.log(chalk.green('✅ Deploy concluído:'));
110
- console.log(stdout);
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
- console.log(chalk.yellow('⚠️ Pull de Edge Functions não é oficialmente suportado pelo Supabase CLI'));
137
- console.log(chalk.yellow('💡 Para baixar código das functions remotas:'));
138
- console.log(chalk.gray(' 1. Use o Dashboard do Supabase'));
139
- console.log(chalk.gray(' 2. Ou clone o código do seu repositório Git'));
140
- console.log(chalk.gray(' 3. Ou use a API do Supabase diretamente'));
141
- console.log(chalk.blue('\n📚 Documentação: https://supabase.com/docs/guides/functions'));
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
- } catch (error) {
144
- console.error(chalk.red(`❌ Erro: ${error.message}`));
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
- module.exports = functionsCommand;
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;
@@ -1,78 +1,75 @@
1
- const { Command } = require('commander');
2
1
  const chalk = require('chalk');
3
2
  const path = require('path');
4
3
  const fs = require('fs');
5
4
  const inquirer = require('inquirer');
6
5
  const { ensureBin, runCommand } = require('../utils/cli');
7
6
  const { readConfig, validateFor } = require('../utils/config');
8
- const { showBetaBanner } = require('../index');
7
+ const { showBetaBanner } = require('../utils/banner');
9
8
 
10
- const restoreCommand = new Command('restore')
11
- .description('Restaurar backup do projeto Supabase usando psql (modo interativo)')
12
- .option('--db-url <url>', 'URL da database de destino (override)')
13
- .action(async (options) => {
14
- showBetaBanner();
15
-
16
- try {
17
- // Verificar se psql está disponível
18
- const psqlPath = await ensureBin('psql');
19
- if (!psqlPath) {
20
- console.error(chalk.red('❌ psql não encontrado'));
21
- console.log(chalk.yellow('💡 Instale PostgreSQL:'));
22
- console.log(chalk.yellow(' https://www.postgresql.org/download/'));
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
- // Carregar configuração
27
- const config = await readConfig();
28
- validateFor(config, 'restore');
23
+ // Carregar configuração
24
+ const config = await readConfig();
25
+ validateFor(config, 'restore');
29
26
 
30
- // Resolver URL da database
31
- const databaseUrl = options.dbUrl || config.supabase.databaseUrl;
32
- if (!databaseUrl) {
33
- console.error(chalk.red('❌ databaseUrl não configurada'));
34
- console.log(chalk.yellow('💡 Configure databaseUrl no .smoonbrc ou use --db-url'));
35
- process.exit(1);
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
- console.log(chalk.blue(`🔍 Procurando backups em: ${config.backup.outputDir || './backups'}`));
35
+ console.log(chalk.blue(`🔍 Procurando backups em: ${config.backup.outputDir || './backups'}`));
39
36
 
40
- // Listar backups disponíveis
41
- const backups = await listAvailableBackups(config.backup.outputDir || './backups');
42
-
43
- if (backups.length === 0) {
44
- console.error(chalk.red('❌ Nenhum backup encontrado'));
45
- console.log(chalk.yellow('💡 Execute primeiro: npx smoonb backup'));
46
- process.exit(1);
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
- // Seleção interativa do backup
50
- const selectedBackup = await selectBackup(backups);
51
-
52
- console.log(chalk.blue(`🚀 Iniciando restauração do backup: ${selectedBackup.name}`));
53
- console.log(chalk.blue(`🎯 Database destino: ${databaseUrl.replace(/:[^:]*@/, ':***@')}`));
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
- // Verificar se é clean restore
56
- if (config.restore.cleanRestore) {
57
- await checkCleanRestore(databaseUrl);
58
- }
52
+ // Verificar se é clean restore
53
+ if (config.restore.cleanRestore) {
54
+ await checkCleanRestore(databaseUrl);
55
+ }
59
56
 
60
- // Executar restauração
61
- await performRestore(selectedBackup.path, databaseUrl);
57
+ // Executar restauração
58
+ await performRestore(selectedBackup.path, databaseUrl);
62
59
 
63
- // Verificação pós-restore
64
- if (config.restore.verifyAfterRestore) {
65
- console.log(chalk.blue('\n🔍 Executando verificação pós-restore...'));
66
- console.log(chalk.yellow('💡 Execute manualmente: npx smoonb check'));
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
- console.log(chalk.green('\n🎉 Restauração concluída com sucesso!'));
66
+ console.log(chalk.green('\n🎉 Restauração concluída com sucesso!'));
70
67
 
71
- } catch (error) {
72
- console.error(chalk.red(`❌ Erro na restauração: ${error.message}`));
73
- process.exit(1);
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
+ }
package/src/index.js CHANGED
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  const chalk = require('chalk');
9
+ const { showBetaBanner } = require('./utils/banner');
9
10
 
10
11
  // Exportar comandos
11
12
  const backupCommand = require('./commands/backup');
@@ -28,35 +29,6 @@ const packageInfo = {
28
29
  license: 'SEE LICENSE IN LICENSE.md'
29
30
  };
30
31
 
31
- /**
32
- * Banner da versão experimental
33
- */
34
- function showBetaBanner() {
35
- console.log(chalk.red.bold(`
36
- ╔══════════════════════════════════════════════════════════════╗
37
- ║ 🚀 smoonb ║
38
- ║ ║
39
- ║ ⚠️ EXPERIMENTAL VERSION - NÃO TESTADA! ║
40
- ║ ║
41
- ║ 🚨 AVISO: Este software NUNCA foi testado em produção! ║
42
- ║ ⚠️ USE POR SUA CONTA E RISCO - Pode causar perda de dados ║
43
- ║ ❌ NÃO NOS RESPONSABILIZAMOS por qualquer perda de dados ║
44
- ║ ║
45
- ║ A primeira ferramenta CLI completa para backup e migração ║
46
- ║ de projetos Supabase. Resolve o problema de backup ║
47
- ║ incompleto das ferramentas existentes. ║
48
- ║ ║
49
- ║ ✅ Database PostgreSQL + Edge Functions + Auth Settings ║
50
- ║ ✅ Storage Objects + Realtime Settings + Metadados ║
51
- ║ ║
52
- ║ 🏢 Desenvolvido por: Goalmoon Tecnologia LTDA ║
53
- ║ 🌐 Website: https://goalmoon.com ║
54
- ║ 📖 Documentação: https://github.com/almmello/smoonb ║
55
- ║ 🐛 Issues: https://github.com/almmello/smoonb/issues ║
56
- ╚══════════════════════════════════════════════════════════════╝
57
- `));
58
- }
59
-
60
32
  /**
61
33
  * Informações de licenciamento
62
34
  */
@@ -0,0 +1,32 @@
1
+ const chalk = require('chalk');
2
+
3
+ /**
4
+ * Banner da versão experimental
5
+ */
6
+ function showBetaBanner() {
7
+ console.log(chalk.red.bold(`
8
+ ╔══════════════════════════════════════════════════════════════╗
9
+ ║ 🚀 smoonb ║
10
+ ║ ║
11
+ ║ ⚠️ EXPERIMENTAL VERSION - NÃO TESTADA! ║
12
+ ║ ║
13
+ ║ 🚨 AVISO: Este software NUNCA foi testado em produção! ║
14
+ ║ ⚠️ USE POR SUA CONTA E RISCO - Pode causar perda de dados ║
15
+ ║ ❌ NÃO NOS RESPONSABILIZAMOS por qualquer perda de dados ║
16
+ ║ ║
17
+ ║ A primeira ferramenta CLI completa para backup e migração ║
18
+ ║ de projetos Supabase. Resolve o problema de backup ║
19
+ ║ incompleto das ferramentas existentes. ║
20
+ ║ ║
21
+ ║ ✅ Database PostgreSQL + Edge Functions + Auth Settings ║
22
+ ║ ✅ Storage Objects + Realtime Settings + Metadados ║
23
+ ║ ║
24
+ ║ 🏢 Desenvolvido por: Goalmoon Tecnologia LTDA ║
25
+ ║ 🌐 Website: https://goalmoon.com ║
26
+ ║ 📖 Documentação: https://github.com/almmello/smoonb ║
27
+ ║ 🐛 Issues: https://github.com/almmello/smoonb/issues ║
28
+ ╚══════════════════════════════════════════════════════════════╝
29
+ `));
30
+ }
31
+
32
+ module.exports = { showBetaBanner };