smoonb 0.0.1
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/.smoonbrc.example +18 -0
- package/LICENSE.md +64 -0
- package/README.md +227 -0
- package/bin/smoonb.js +113 -0
- package/package.json +43 -0
- package/src/commands/backup.js +245 -0
- package/src/commands/check.js +405 -0
- package/src/commands/config.js +75 -0
- package/src/commands/functions.js +375 -0
- package/src/commands/restore.js +326 -0
- package/src/commands/secrets.js +361 -0
- package/src/index.js +269 -0
- package/src/utils/supabase.js +364 -0
- package/src/utils/validation.js +351 -0
package/src/index.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* smoonb - Complete Supabase backup and migration tool
|
|
3
|
+
* Entry point principal e exports dos módulos
|
|
4
|
+
*
|
|
5
|
+
* Versão: 0.1.0-beta (FREE BETA PERIOD)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
|
|
10
|
+
// Exportar comandos
|
|
11
|
+
const backupCommand = require('./commands/backup');
|
|
12
|
+
const restoreCommand = require('./commands/restore');
|
|
13
|
+
const secretsCommand = require('./commands/secrets');
|
|
14
|
+
const functionsCommand = require('./commands/functions');
|
|
15
|
+
const checkCommand = require('./commands/check');
|
|
16
|
+
const configCommand = require('./commands/config');
|
|
17
|
+
|
|
18
|
+
// Exportar utilitários
|
|
19
|
+
const supabaseUtils = require('./utils/supabase');
|
|
20
|
+
const validationUtils = require('./utils/validation');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Informações do pacote
|
|
24
|
+
*/
|
|
25
|
+
const packageInfo = {
|
|
26
|
+
name: 'smoonb',
|
|
27
|
+
version: '0.0.1',
|
|
28
|
+
description: 'Complete Supabase backup and migration tool - EXPERIMENTAL VERSION - USE AT YOUR OWN RISK',
|
|
29
|
+
author: 'Goalmoon Tecnologia LTDA <https://goalmoon.com>',
|
|
30
|
+
license: 'SEE LICENSE IN LICENSE.md'
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Banner da versão experimental
|
|
35
|
+
*/
|
|
36
|
+
function showBetaBanner() {
|
|
37
|
+
console.log(chalk.red.bold(`
|
|
38
|
+
╔══════════════════════════════════════════════════════════════╗
|
|
39
|
+
║ 🚀 smoonb v0.0.1 ║
|
|
40
|
+
║ ║
|
|
41
|
+
║ ⚠️ EXPERIMENTAL VERSION - NÃO TESTADA! ║
|
|
42
|
+
║ ║
|
|
43
|
+
║ 🚨 AVISO: Este software NUNCA foi testado em produção! ║
|
|
44
|
+
║ ⚠️ USE POR SUA CONTA E RISCO - Pode causar perda de dados ║
|
|
45
|
+
║ ❌ NÃO NOS RESPONSABILIZAMOS por qualquer perda de dados ║
|
|
46
|
+
║ ║
|
|
47
|
+
║ A primeira ferramenta CLI completa para backup e migração ║
|
|
48
|
+
║ de projetos Supabase. Resolve o problema de backup ║
|
|
49
|
+
║ incompleto das ferramentas existentes. ║
|
|
50
|
+
║ ║
|
|
51
|
+
║ ✅ Database PostgreSQL + Edge Functions + Auth Settings ║
|
|
52
|
+
║ ✅ Storage Objects + Realtime Settings + Metadados ║
|
|
53
|
+
║ ║
|
|
54
|
+
║ 🏢 Desenvolvido por: Goalmoon Tecnologia LTDA ║
|
|
55
|
+
║ 🌐 Website: https://goalmoon.com ║
|
|
56
|
+
║ 📖 Documentação: https://github.com/almmello/smoonb ║
|
|
57
|
+
║ 🐛 Issues: https://github.com/almmello/smoonb/issues ║
|
|
58
|
+
╚══════════════════════════════════════════════════════════════╝
|
|
59
|
+
`));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Informações de licenciamento
|
|
64
|
+
*/
|
|
65
|
+
function showLicenseInfo() {
|
|
66
|
+
console.log(chalk.yellow.bold(`
|
|
67
|
+
📋 INFORMAÇÕES DE LICENCIAMENTO:
|
|
68
|
+
|
|
69
|
+
🆓 VERSÃO EXPERIMENTAL GRATUITA (Versões 0.x.x):
|
|
70
|
+
✅ Uso gratuito para projetos pessoais e comerciais
|
|
71
|
+
✅ Sem restrições de funcionalidades
|
|
72
|
+
❌ SEM SUPORTE - apenas aceitamos contribuições
|
|
73
|
+
⚠️ USE POR SUA CONTA E RISCO - software não testado
|
|
74
|
+
|
|
75
|
+
💼 LICENÇA COMERCIAL (Versões 1.0.0+):
|
|
76
|
+
⚠️ A partir da versão 1.0.0, o smoonb será licenciado comercialmente
|
|
77
|
+
📧 Aviso prévio: Mudanças serão anunciadas 90 dias antes
|
|
78
|
+
💰 Desconto especial: Usuários experimentais terão condições preferenciais
|
|
79
|
+
|
|
80
|
+
🏢 DESENVOLVIDO POR: Goalmoon Tecnologia LTDA
|
|
81
|
+
🌐 Website: https://goalmoon.com
|
|
82
|
+
|
|
83
|
+
📖 Leia a licença completa em: LICENSE.md
|
|
84
|
+
`));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Informações de ajuda rápida
|
|
89
|
+
*/
|
|
90
|
+
function showQuickHelp() {
|
|
91
|
+
console.log(chalk.cyan.bold(`
|
|
92
|
+
🚀 COMANDOS PRINCIPAIS:
|
|
93
|
+
|
|
94
|
+
📊 Backup completo:
|
|
95
|
+
smoonb backup --project-id <project-id>
|
|
96
|
+
|
|
97
|
+
🔄 Restauração completa:
|
|
98
|
+
smoonb restore --project-id <project-id> --backup-dir <backup-dir>
|
|
99
|
+
|
|
100
|
+
🔐 Gerenciamento de secrets:
|
|
101
|
+
smoonb secrets export
|
|
102
|
+
smoonb secrets import
|
|
103
|
+
|
|
104
|
+
⚡ Edge Functions:
|
|
105
|
+
smoonb functions push
|
|
106
|
+
smoonb functions list
|
|
107
|
+
|
|
108
|
+
🔍 Verificação pós-restore:
|
|
109
|
+
smoonb check --project-id <project-id>
|
|
110
|
+
|
|
111
|
+
⚙️ Configuração:
|
|
112
|
+
smoonb config --init
|
|
113
|
+
`));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Verificar pré-requisitos
|
|
118
|
+
*/
|
|
119
|
+
function checkPrerequisites() {
|
|
120
|
+
const prerequisites = {
|
|
121
|
+
node: { installed: true, version: process.version },
|
|
122
|
+
npm: { installed: false, version: null },
|
|
123
|
+
supabase_cli: { installed: false, version: null },
|
|
124
|
+
pg_dump: { installed: false, version: null }
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// Verificar npm
|
|
128
|
+
try {
|
|
129
|
+
const { execSync } = require('child_process');
|
|
130
|
+
const npmVersion = execSync('npm --version', { encoding: 'utf8' }).trim();
|
|
131
|
+
prerequisites.npm = { installed: true, version: npmVersion };
|
|
132
|
+
} catch (error) {
|
|
133
|
+
prerequisites.npm = { installed: false, version: null };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Verificar Supabase CLI
|
|
137
|
+
try {
|
|
138
|
+
const { execSync } = require('child_process');
|
|
139
|
+
const supabaseVersion = execSync('supabase --version', { encoding: 'utf8' }).trim();
|
|
140
|
+
prerequisites.supabase_cli = { installed: true, version: supabaseVersion };
|
|
141
|
+
} catch (error) {
|
|
142
|
+
prerequisites.supabase_cli = { installed: false, version: null };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Verificar pg_dump
|
|
146
|
+
try {
|
|
147
|
+
const { execSync } = require('child_process');
|
|
148
|
+
const pgDumpVersion = execSync('pg_dump --version', { encoding: 'utf8' }).trim();
|
|
149
|
+
prerequisites.pg_dump = { installed: true, version: pgDumpVersion };
|
|
150
|
+
} catch (error) {
|
|
151
|
+
prerequisites.pg_dump = { installed: false, version: null };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return prerequisites;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Mostrar status dos pré-requisitos
|
|
159
|
+
*/
|
|
160
|
+
function showPrerequisitesStatus() {
|
|
161
|
+
const prerequisites = checkPrerequisites();
|
|
162
|
+
|
|
163
|
+
console.log(chalk.blue.bold('\n📋 Status dos Pré-requisitos:\n'));
|
|
164
|
+
|
|
165
|
+
Object.entries(prerequisites).forEach(([name, info]) => {
|
|
166
|
+
const icon = info.installed ? '✅' : '❌';
|
|
167
|
+
const status = info.installed ? chalk.green('Instalado') : chalk.red('Não instalado');
|
|
168
|
+
const version = info.version ? chalk.gray(`(${info.version})`) : '';
|
|
169
|
+
|
|
170
|
+
console.log(` ${icon} ${chalk.cyan(name)}: ${status} ${version}`);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Mostrar instruções para instalar dependências faltantes
|
|
174
|
+
const missing = Object.entries(prerequisites)
|
|
175
|
+
.filter(([_, info]) => !info.installed)
|
|
176
|
+
.map(([name, _]) => name);
|
|
177
|
+
|
|
178
|
+
if (missing.length > 0) {
|
|
179
|
+
console.log(chalk.yellow.bold('\n💡 Instruções de instalação:'));
|
|
180
|
+
|
|
181
|
+
if (missing.includes('supabase_cli')) {
|
|
182
|
+
console.log(chalk.gray(' - Supabase CLI: npm install -g supabase'));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (missing.includes('pg_dump')) {
|
|
186
|
+
console.log(chalk.gray(' - PostgreSQL: https://www.postgresql.org/download/'));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Verificar configuração atual
|
|
193
|
+
*/
|
|
194
|
+
function checkCurrentConfig() {
|
|
195
|
+
const config = supabaseUtils.loadConfig();
|
|
196
|
+
const hasCredentials = supabaseUtils.hasCredentials();
|
|
197
|
+
|
|
198
|
+
console.log(chalk.blue.bold('\n⚙️ Configuração Atual:\n'));
|
|
199
|
+
|
|
200
|
+
if (config) {
|
|
201
|
+
console.log(chalk.green('✅ Arquivo de configuração encontrado'));
|
|
202
|
+
console.log(chalk.gray(` - Localização: ${require('os').homedir()}/.smoonbrc`));
|
|
203
|
+
|
|
204
|
+
if (config.supabase?.url) {
|
|
205
|
+
console.log(chalk.gray(` - Supabase URL: ${config.supabase.url}`));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (config.supabase?.serviceKey) {
|
|
209
|
+
console.log(chalk.gray(' - Service Key: Configurada'));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (config.supabase?.anonKey) {
|
|
213
|
+
console.log(chalk.gray(' - Anon Key: Configurada'));
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
console.log(chalk.yellow('⚠️ Arquivo de configuração não encontrado'));
|
|
217
|
+
console.log(chalk.gray(' - Use: smoonb config --init'));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (hasCredentials) {
|
|
221
|
+
console.log(chalk.green('✅ Credenciais configuradas'));
|
|
222
|
+
} else {
|
|
223
|
+
console.log(chalk.yellow('⚠️ Credenciais não configuradas'));
|
|
224
|
+
console.log(chalk.gray(' - Configure SUPABASE_URL e SUPABASE_ANON_KEY'));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Informações de diagnóstico completo
|
|
230
|
+
*/
|
|
231
|
+
function showDiagnostics() {
|
|
232
|
+
showBetaBanner();
|
|
233
|
+
showPrerequisitesStatus();
|
|
234
|
+
checkCurrentConfig();
|
|
235
|
+
showLicenseInfo();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Exportar todos os módulos
|
|
240
|
+
*/
|
|
241
|
+
module.exports = {
|
|
242
|
+
// Informações do pacote
|
|
243
|
+
packageInfo,
|
|
244
|
+
|
|
245
|
+
// Comandos
|
|
246
|
+
commands: {
|
|
247
|
+
backup: backupCommand,
|
|
248
|
+
restore: restoreCommand,
|
|
249
|
+
secrets: secretsCommand,
|
|
250
|
+
functions: functionsCommand,
|
|
251
|
+
check: checkCommand,
|
|
252
|
+
config: configCommand
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
// Utilitários
|
|
256
|
+
utils: {
|
|
257
|
+
supabase: supabaseUtils,
|
|
258
|
+
validation: validationUtils
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
// Funções de utilidade
|
|
262
|
+
showBetaBanner,
|
|
263
|
+
showLicenseInfo,
|
|
264
|
+
showQuickHelp,
|
|
265
|
+
checkPrerequisites,
|
|
266
|
+
showPrerequisitesStatus,
|
|
267
|
+
checkCurrentConfig,
|
|
268
|
+
showDiagnostics
|
|
269
|
+
};
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilitários para conexão e operações com Supabase
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { createClient } = require('@supabase/supabase-js');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const os = require('os');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Cliente Supabase configurado
|
|
12
|
+
*/
|
|
13
|
+
let supabaseClient = null;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Inicializar cliente Supabase
|
|
17
|
+
*/
|
|
18
|
+
function initSupabaseClient() {
|
|
19
|
+
try {
|
|
20
|
+
const supabaseUrl = process.env.SUPABASE_URL;
|
|
21
|
+
const supabaseKey = process.env.SUPABASE_ANON_KEY || process.env.SUPABASE_SERVICE_ROLE_KEY;
|
|
22
|
+
|
|
23
|
+
if (!supabaseUrl || !supabaseKey) {
|
|
24
|
+
throw new Error('SUPABASE_URL e SUPABASE_ANON_KEY são obrigatórios');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
supabaseClient = createClient(supabaseUrl, supabaseKey);
|
|
28
|
+
return supabaseClient;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
throw new Error(`Erro ao inicializar cliente Supabase: ${error.message}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Obter cliente Supabase (inicializa se necessário)
|
|
36
|
+
*/
|
|
37
|
+
function getSupabaseClient() {
|
|
38
|
+
if (!supabaseClient) {
|
|
39
|
+
return initSupabaseClient();
|
|
40
|
+
}
|
|
41
|
+
return supabaseClient;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Carregar configuração do arquivo .smoonbrc
|
|
46
|
+
*/
|
|
47
|
+
function loadConfig() {
|
|
48
|
+
const configPath = path.join(os.homedir(), '.smoonbrc');
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
if (fs.existsSync(configPath)) {
|
|
52
|
+
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
53
|
+
return JSON.parse(configContent);
|
|
54
|
+
}
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.warn('Erro ao carregar configuração:', error.message);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Salvar configuração no arquivo .smoonbrc
|
|
64
|
+
*/
|
|
65
|
+
function saveConfig(config) {
|
|
66
|
+
const configPath = path.join(os.homedir(), '.smoonbrc');
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
70
|
+
return true;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('Erro ao salvar configuração:', error.message);
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Obter URL de conexão da database
|
|
79
|
+
*/
|
|
80
|
+
function getDatabaseUrl(projectId) {
|
|
81
|
+
// Tentar variável de ambiente primeiro
|
|
82
|
+
if (process.env.DATABASE_URL) {
|
|
83
|
+
return process.env.DATABASE_URL;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Tentar configuração
|
|
87
|
+
const config = loadConfig();
|
|
88
|
+
if (config?.supabase?.databaseUrl) {
|
|
89
|
+
return config.supabase.databaseUrl;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// URL padrão (requer configuração de senha)
|
|
93
|
+
return `postgresql://postgres:[password]@db.${projectId}.supabase.co:5432/postgres`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Obter URL do projeto Supabase
|
|
98
|
+
*/
|
|
99
|
+
function getSupabaseUrl(projectId) {
|
|
100
|
+
// Tentar variável de ambiente primeiro
|
|
101
|
+
if (process.env.SUPABASE_URL) {
|
|
102
|
+
return process.env.SUPABASE_URL;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Tentar configuração
|
|
106
|
+
const config = loadConfig();
|
|
107
|
+
if (config?.supabase?.url) {
|
|
108
|
+
return config.supabase.url;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// URL padrão
|
|
112
|
+
return `https://${projectId}.supabase.co`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Obter service key do Supabase
|
|
117
|
+
*/
|
|
118
|
+
function getServiceKey() {
|
|
119
|
+
// Tentar variável de ambiente primeiro
|
|
120
|
+
if (process.env.SUPABASE_SERVICE_ROLE_KEY) {
|
|
121
|
+
return process.env.SUPABASE_SERVICE_ROLE_KEY;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Tentar configuração
|
|
125
|
+
const config = loadConfig();
|
|
126
|
+
if (config?.supabase?.serviceKey) {
|
|
127
|
+
return config.supabase.serviceKey;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Obter anon key do Supabase
|
|
135
|
+
*/
|
|
136
|
+
function getAnonKey() {
|
|
137
|
+
// Tentar variável de ambiente primeiro
|
|
138
|
+
if (process.env.SUPABASE_ANON_KEY) {
|
|
139
|
+
return process.env.SUPABASE_ANON_KEY;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Tentar configuração
|
|
143
|
+
const config = loadConfig();
|
|
144
|
+
if (config?.supabase?.anonKey) {
|
|
145
|
+
return config.supabase.anonKey;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Verificar se credenciais estão configuradas
|
|
153
|
+
*/
|
|
154
|
+
function hasCredentials() {
|
|
155
|
+
return !!(getSupabaseUrl() && (getServiceKey() || getAnonKey()));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Testar conexão com Supabase
|
|
160
|
+
*/
|
|
161
|
+
async function testConnection() {
|
|
162
|
+
try {
|
|
163
|
+
const client = getSupabaseClient();
|
|
164
|
+
|
|
165
|
+
// Tentar uma operação simples
|
|
166
|
+
const { data, error } = await client.from('_smoonb_test').select('*').limit(1);
|
|
167
|
+
|
|
168
|
+
if (error && error.code !== 'PGRST116') { // PGRST116 = tabela não existe (esperado)
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return { success: true, message: 'Conexão estabelecida com sucesso' };
|
|
173
|
+
} catch (error) {
|
|
174
|
+
return { success: false, message: error.message };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Obter informações do projeto
|
|
180
|
+
*/
|
|
181
|
+
async function getProjectInfo(projectId) {
|
|
182
|
+
try {
|
|
183
|
+
const client = getSupabaseClient();
|
|
184
|
+
|
|
185
|
+
// TODO: Implementar busca real de informações do projeto
|
|
186
|
+
// Por enquanto, retornar informações básicas
|
|
187
|
+
return {
|
|
188
|
+
id: projectId,
|
|
189
|
+
url: getSupabaseUrl(projectId),
|
|
190
|
+
status: 'active',
|
|
191
|
+
region: 'unknown',
|
|
192
|
+
created_at: new Date().toISOString()
|
|
193
|
+
};
|
|
194
|
+
} catch (error) {
|
|
195
|
+
throw new Error(`Erro ao obter informações do projeto: ${error.message}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Listar tabelas da database
|
|
201
|
+
*/
|
|
202
|
+
async function listTables() {
|
|
203
|
+
try {
|
|
204
|
+
const client = getSupabaseClient();
|
|
205
|
+
|
|
206
|
+
// Usar RPC para listar tabelas
|
|
207
|
+
const { data, error } = await client.rpc('get_tables');
|
|
208
|
+
|
|
209
|
+
if (error) {
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return data || [];
|
|
214
|
+
} catch (error) {
|
|
215
|
+
// Fallback: tentar query direta
|
|
216
|
+
try {
|
|
217
|
+
const { data, error } = await client
|
|
218
|
+
.from('information_schema.tables')
|
|
219
|
+
.select('table_name')
|
|
220
|
+
.eq('table_schema', 'public');
|
|
221
|
+
|
|
222
|
+
if (error) {
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return data?.map(row => row.table_name) || [];
|
|
227
|
+
} catch (fallbackError) {
|
|
228
|
+
throw new Error(`Erro ao listar tabelas: ${fallbackError.message}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Listar extensões instaladas
|
|
235
|
+
*/
|
|
236
|
+
async function listExtensions() {
|
|
237
|
+
try {
|
|
238
|
+
const client = getSupabaseClient();
|
|
239
|
+
|
|
240
|
+
// Usar RPC para listar extensões
|
|
241
|
+
const { data, error } = await client.rpc('get_extensions');
|
|
242
|
+
|
|
243
|
+
if (error) {
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return data || [];
|
|
248
|
+
} catch (error) {
|
|
249
|
+
// Fallback: tentar query direta
|
|
250
|
+
try {
|
|
251
|
+
const { data, error } = await client
|
|
252
|
+
.from('pg_extension')
|
|
253
|
+
.select('extname');
|
|
254
|
+
|
|
255
|
+
if (error) {
|
|
256
|
+
throw error;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return data?.map(row => row.extname) || [];
|
|
260
|
+
} catch (fallbackError) {
|
|
261
|
+
throw new Error(`Erro ao listar extensões: ${fallbackError.message}`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Obter configurações de Auth
|
|
268
|
+
*/
|
|
269
|
+
async function getAuthSettings() {
|
|
270
|
+
try {
|
|
271
|
+
const client = getSupabaseClient();
|
|
272
|
+
|
|
273
|
+
// TODO: Implementar busca real de configurações de Auth
|
|
274
|
+
// Por enquanto, retornar estrutura básica
|
|
275
|
+
return {
|
|
276
|
+
providers: [],
|
|
277
|
+
policies: [],
|
|
278
|
+
settings: {
|
|
279
|
+
enable_signup: true,
|
|
280
|
+
enable_email_confirmations: true
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
} catch (error) {
|
|
284
|
+
throw new Error(`Erro ao obter configurações de Auth: ${error.message}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Obter configurações de Storage
|
|
290
|
+
*/
|
|
291
|
+
async function getStorageSettings() {
|
|
292
|
+
try {
|
|
293
|
+
const client = getSupabaseClient();
|
|
294
|
+
|
|
295
|
+
// Listar buckets
|
|
296
|
+
const { data: buckets, error: bucketsError } = await client.storage.listBuckets();
|
|
297
|
+
|
|
298
|
+
if (bucketsError) {
|
|
299
|
+
throw bucketsError;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Para cada bucket, listar objetos
|
|
303
|
+
const bucketsWithObjects = [];
|
|
304
|
+
for (const bucket of buckets) {
|
|
305
|
+
const { data: objects, error: objectsError } = await client.storage
|
|
306
|
+
.from(bucket.name)
|
|
307
|
+
.list();
|
|
308
|
+
|
|
309
|
+
bucketsWithObjects.push({
|
|
310
|
+
...bucket,
|
|
311
|
+
objects: objects || []
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
buckets: bucketsWithObjects,
|
|
317
|
+
total_buckets: buckets.length,
|
|
318
|
+
total_objects: bucketsWithObjects.reduce((sum, bucket) => sum + bucket.objects.length, 0)
|
|
319
|
+
};
|
|
320
|
+
} catch (error) {
|
|
321
|
+
throw new Error(`Erro ao obter configurações de Storage: ${error.message}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Obter configurações de Realtime
|
|
327
|
+
*/
|
|
328
|
+
async function getRealtimeSettings() {
|
|
329
|
+
try {
|
|
330
|
+
const client = getSupabaseClient();
|
|
331
|
+
|
|
332
|
+
// TODO: Implementar busca real de configurações de Realtime
|
|
333
|
+
// Por enquanto, retornar estrutura básica
|
|
334
|
+
return {
|
|
335
|
+
enabled: true,
|
|
336
|
+
channels: [],
|
|
337
|
+
settings: {
|
|
338
|
+
max_channels_per_client: 100,
|
|
339
|
+
max_events_per_second: 100
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
} catch (error) {
|
|
343
|
+
throw new Error(`Erro ao obter configurações de Realtime: ${error.message}`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
module.exports = {
|
|
348
|
+
initSupabaseClient,
|
|
349
|
+
getSupabaseClient,
|
|
350
|
+
loadConfig,
|
|
351
|
+
saveConfig,
|
|
352
|
+
getDatabaseUrl,
|
|
353
|
+
getSupabaseUrl,
|
|
354
|
+
getServiceKey,
|
|
355
|
+
getAnonKey,
|
|
356
|
+
hasCredentials,
|
|
357
|
+
testConnection,
|
|
358
|
+
getProjectInfo,
|
|
359
|
+
listTables,
|
|
360
|
+
listExtensions,
|
|
361
|
+
getAuthSettings,
|
|
362
|
+
getStorageSettings,
|
|
363
|
+
getRealtimeSettings
|
|
364
|
+
};
|