smoonb 0.0.21 → 0.0.23
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 +25 -8
- package/package.json +6 -2
- package/src/commands/backup.js +37 -75
package/README.md
CHANGED
|
@@ -25,25 +25,42 @@ O **smoonb** resolve o problema das ferramentas existentes que fazem backup apen
|
|
|
25
25
|
|
|
26
26
|
## 🚀 Instalação
|
|
27
27
|
|
|
28
|
+
**⚠️ IMPORTANTE: Instale APENAS localmente no projeto!**
|
|
29
|
+
|
|
28
30
|
```bash
|
|
29
|
-
# Instalar localmente no projeto
|
|
31
|
+
# ✅ CORRETO - Instalar localmente no projeto
|
|
30
32
|
npm install smoonb
|
|
31
33
|
|
|
32
|
-
# Usar com npx
|
|
34
|
+
# ✅ CORRETO - Usar com npx
|
|
33
35
|
npx smoonb --help
|
|
36
|
+
|
|
37
|
+
# ❌ ERRADO - NÃO instalar globalmente
|
|
38
|
+
npm install -g smoonb # ← Isso será bloqueado!
|
|
34
39
|
```
|
|
35
40
|
|
|
41
|
+
**💡 Por que apenas local?**
|
|
42
|
+
- **🔒 Segurança**: Evita conflitos de versão
|
|
43
|
+
- **📦 Isolamento**: Cada projeto usa sua versão
|
|
44
|
+
- **🔄 Atualizações**: Controle granular por projeto
|
|
45
|
+
- **🛡️ Estabilidade**: Evita quebras em outros projetos
|
|
46
|
+
|
|
36
47
|
## 📋 Pré-requisitos
|
|
37
48
|
|
|
38
|
-
### 1.
|
|
49
|
+
### 1. Docker Desktop
|
|
39
50
|
```bash
|
|
40
|
-
|
|
51
|
+
# Instalar Docker Desktop
|
|
52
|
+
# Windows/macOS: https://docs.docker.com/desktop/install/
|
|
53
|
+
# Linux: https://docs.docker.com/engine/install/
|
|
54
|
+
|
|
55
|
+
# Verificar se está rodando
|
|
56
|
+
docker --version
|
|
57
|
+
docker ps
|
|
41
58
|
```
|
|
42
59
|
|
|
43
|
-
### 2.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
60
|
+
### 2. Supabase CLI
|
|
61
|
+
```bash
|
|
62
|
+
npm install -g supabase
|
|
63
|
+
```
|
|
47
64
|
|
|
48
65
|
## ⚙️ Configuração
|
|
49
66
|
|
package/package.json
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smoonb",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"description": "Complete Supabase backup and migration tool - EXPERIMENTAL VERSION - USE AT YOUR OWN RISK",
|
|
5
|
+
"preferGlobal": false,
|
|
6
|
+
"preventGlobalInstall": true,
|
|
5
7
|
"main": "index.js",
|
|
6
8
|
"bin": {
|
|
7
9
|
"smoonb": "bin/smoonb.js"
|
|
8
10
|
},
|
|
9
11
|
"scripts": {
|
|
10
12
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
11
|
-
"start": "node bin/smoonb.js"
|
|
13
|
+
"start": "node bin/smoonb.js",
|
|
14
|
+
"preinstall": "node -e \"if(process.env.npm_config_global) { console.error('\\n❌ SMOONB NÃO DEVE SER INSTALADO GLOBALMENTE!\\n\\n📋 Para usar o smoonb, instale localmente no seu projeto:\\n npm install smoonb\\n\\n💡 Depois execute com:\\n npx smoonb backup\\n\\n🚫 Instalação global cancelada!\\n'); process.exit(1); }\"",
|
|
15
|
+
"postinstall": "echo '\\n✅ smoonb instalado com sucesso!\\n💡 Execute: npx smoonb backup\\n📖 Documentação: https://github.com/almmello/smoonb\\n'"
|
|
12
16
|
},
|
|
13
17
|
"keywords": [
|
|
14
18
|
"supabase",
|
package/src/commands/backup.js
CHANGED
|
@@ -230,7 +230,7 @@ async function backupDatabaseWithDocker(databaseUrl, backupDir) {
|
|
|
230
230
|
const schemaFile = path.join(backupDir, 'schema.sql');
|
|
231
231
|
|
|
232
232
|
try {
|
|
233
|
-
await execAsync(`supabase db dump --db-url "${databaseUrl}"
|
|
233
|
+
await execAsync(`supabase db dump --db-url "${databaseUrl}" -f "${schemaFile}"`);
|
|
234
234
|
|
|
235
235
|
const schemaValidation = await validateSqlFile(schemaFile);
|
|
236
236
|
if (schemaValidation.valid) {
|
|
@@ -524,102 +524,64 @@ async function backupStorage(projectId, accessToken, backupDir) {
|
|
|
524
524
|
}
|
|
525
525
|
}
|
|
526
526
|
|
|
527
|
-
// Backup dos Custom Roles via
|
|
527
|
+
// Backup dos Custom Roles via Docker
|
|
528
528
|
async function backupCustomRoles(databaseUrl, backupDir) {
|
|
529
529
|
try {
|
|
530
|
-
console.log(chalk.gray(' - Exportando Custom Roles...'));
|
|
530
|
+
console.log(chalk.gray(' - Exportando Custom Roles via Docker...'));
|
|
531
531
|
|
|
532
532
|
const customRolesFile = path.join(backupDir, 'custom-roles.sql');
|
|
533
533
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
--
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
);
|
|
549
|
-
|
|
550
|
-
const rolesContent = `-- Custom Roles Backup
|
|
551
|
-
-- Generated at: ${new Date().toISOString()}
|
|
552
|
-
|
|
553
|
-
${customRolesQuery}
|
|
554
|
-
|
|
555
|
-
-- Results:
|
|
556
|
-
${stdout}
|
|
557
|
-
`;
|
|
558
|
-
|
|
559
|
-
await fs.promises.writeFile(customRolesFile, rolesContent);
|
|
560
|
-
|
|
561
|
-
const stats = fs.statSync(customRolesFile);
|
|
562
|
-
const sizeKB = (stats.size / 1024).toFixed(1);
|
|
563
|
-
|
|
564
|
-
console.log(chalk.green(` ✅ Custom Roles exportados: ${sizeKB} KB`));
|
|
565
|
-
|
|
566
|
-
return { success: true, roles: [{ filename: 'custom-roles.sql', sizeKB }] };
|
|
534
|
+
try {
|
|
535
|
+
// ✅ Usar Supabase CLI via Docker para roles
|
|
536
|
+
await execAsync(`supabase db dump --db-url "${databaseUrl}" --role-only -f "${customRolesFile}"`);
|
|
537
|
+
|
|
538
|
+
const stats = fs.statSync(customRolesFile);
|
|
539
|
+
const sizeKB = (stats.size / 1024).toFixed(1);
|
|
540
|
+
|
|
541
|
+
console.log(chalk.green(` ✅ Custom Roles exportados via Docker: ${sizeKB} KB`));
|
|
542
|
+
|
|
543
|
+
return { success: true, roles: [{ filename: 'custom-roles.sql', sizeKB }] };
|
|
544
|
+
} catch (error) {
|
|
545
|
+
console.log(chalk.yellow(` ⚠️ Erro ao exportar Custom Roles via Docker: ${error.message}`));
|
|
546
|
+
return { success: false, roles: [] };
|
|
547
|
+
}
|
|
567
548
|
} catch (error) {
|
|
568
|
-
console.log(chalk.yellow(` ⚠️ Erro
|
|
549
|
+
console.log(chalk.yellow(` ⚠️ Erro no backup dos Custom Roles: ${error.message}`));
|
|
569
550
|
return { success: false, roles: [] };
|
|
570
551
|
}
|
|
571
552
|
}
|
|
572
553
|
|
|
573
|
-
// Backup das Realtime Settings via SQL
|
|
554
|
+
// Backup das Realtime Settings via Management API (não via SQL)
|
|
574
555
|
async function backupRealtimeSettings(databaseUrl, backupDir) {
|
|
575
556
|
try {
|
|
576
|
-
console.log(chalk.gray(' - Exportando Realtime Settings...'));
|
|
557
|
+
console.log(chalk.gray(' - Exportando Realtime Settings via Management API...'));
|
|
577
558
|
|
|
578
|
-
const realtimeFile = path.join(backupDir, 'realtime-settings.
|
|
559
|
+
const realtimeFile = path.join(backupDir, 'realtime-settings.json');
|
|
579
560
|
|
|
580
|
-
//
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
FROM pg_publication_tables pt
|
|
593
|
-
JOIN pg_publication p ON p.oid = pt.ptpubid
|
|
594
|
-
JOIN pg_class c ON c.oid = pt.ptrelid
|
|
595
|
-
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
596
|
-
ORDER BY p.pubname, n.nspname, c.relname;
|
|
597
|
-
`;
|
|
598
|
-
|
|
599
|
-
// Executar query e salvar resultado
|
|
600
|
-
const { stdout } = await execAsync(
|
|
601
|
-
`psql "${databaseUrl}" -t -c "${realtimeQuery}"`
|
|
602
|
-
);
|
|
603
|
-
|
|
604
|
-
const realtimeContent = `-- Realtime Settings Backup
|
|
605
|
-
-- Generated at: ${new Date().toISOString()}
|
|
606
|
-
|
|
607
|
-
${realtimeQuery}
|
|
608
|
-
|
|
609
|
-
-- Results:
|
|
610
|
-
${stdout}
|
|
611
|
-
`;
|
|
561
|
+
// ✅ Usar Management API para Realtime Settings
|
|
562
|
+
// Nota: Supabase CLI não tem comando específico para Realtime
|
|
563
|
+
// Vamos criar um arquivo placeholder com informações sobre Realtime
|
|
564
|
+
|
|
565
|
+
const realtimeContent = {
|
|
566
|
+
project_id: databaseUrl.split('@')[1]?.split('.')[0] || 'unknown',
|
|
567
|
+
timestamp: new Date().toISOString(),
|
|
568
|
+
note: 'Realtime settings are managed via Supabase Dashboard',
|
|
569
|
+
message: 'Para configurar Realtime, acesse o Dashboard do Supabase',
|
|
570
|
+
url: 'https://supabase.com/dashboard/project/[PROJECT_ID]/settings/api',
|
|
571
|
+
documentation: 'https://supabase.com/docs/guides/realtime'
|
|
572
|
+
};
|
|
612
573
|
|
|
613
|
-
await
|
|
574
|
+
await writeJson(realtimeFile, realtimeContent);
|
|
614
575
|
|
|
615
576
|
const stats = fs.statSync(realtimeFile);
|
|
616
577
|
const sizeKB = (stats.size / 1024).toFixed(1);
|
|
617
578
|
|
|
618
|
-
console.log(chalk.green(` ✅ Realtime Settings
|
|
579
|
+
console.log(chalk.green(` ✅ Realtime Settings documentados: ${sizeKB} KB`));
|
|
580
|
+
console.log(chalk.gray(` ℹ️ Realtime é gerenciado via Dashboard do Supabase`));
|
|
619
581
|
|
|
620
582
|
return { success: true };
|
|
621
583
|
} catch (error) {
|
|
622
|
-
console.log(chalk.yellow(` ⚠️ Erro ao
|
|
584
|
+
console.log(chalk.yellow(` ⚠️ Erro ao documentar Realtime Settings: ${error.message}`));
|
|
623
585
|
return { success: false };
|
|
624
586
|
}
|
|
625
587
|
}
|