smoonb 0.0.26 → 0.0.27

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.26",
3
+ "version": "0.0.27",
4
4
  "description": "Complete Supabase backup and migration tool - EXPERIMENTAL VERSION - USE AT YOUR OWN RISK",
5
5
  "preferGlobal": false,
6
6
  "preventGlobalInstall": true,
@@ -109,14 +109,8 @@ async function performFullBackup(config, options) {
109
109
 
110
110
  // 1. Backup Database via pg_dumpall Docker (idêntico ao Dashboard)
111
111
  console.log(chalk.blue('\n📊 1/6 - Backup da Database PostgreSQL via pg_dumpall Docker...'));
112
- const dbResult = await backupDatabaseWithDocker(config.supabase.databaseUrl, backupDir);
113
- manifest.components.database = {
114
- success: dbResult.success,
115
- method: 'pg_dumpall_docker',
116
- fileName: dbResult.fileName,
117
- size_kb: dbResult.size,
118
- dashboard_compatible: true
119
- };
112
+ const databaseResult = await backupDatabase(config.supabase.projectId, backupDir);
113
+ manifest.components.database = databaseResult;
120
114
 
121
115
  // 2. Backup Edge Functions via Docker
122
116
  console.log(chalk.blue('\n⚡ 2/6 - Backup das Edge Functions via Docker...'));
@@ -148,12 +142,21 @@ async function performFullBackup(config, options) {
148
142
 
149
143
  console.log(chalk.green('\n🎉 BACKUP COMPLETO FINALIZADO VIA DOCKER!'));
150
144
  console.log(chalk.blue(`📁 Localização: ${backupDir}`));
151
- console.log(chalk.green(`📊 Database: ${dbResult.fileName} (${dbResult.size} KB) - Idêntico ao Dashboard`));
145
+ console.log(chalk.green(`📊 Database: ${databaseResult.fileName} (${databaseResult.size} KB) - Idêntico ao Dashboard`));
152
146
  console.log(chalk.green(`⚡ Edge Functions: ${functionsResult.success_count || 0}/${functionsResult.functions_count || 0} functions baixadas via Docker`));
153
147
  console.log(chalk.green(`🔐 Auth Settings: ${authResult.success ? 'Exportadas via API' : 'Falharam'}`));
154
148
  console.log(chalk.green(`📦 Storage: ${storageResult.buckets?.length || 0} buckets verificados via API`));
155
149
  console.log(chalk.green(`👥 Custom Roles: ${rolesResult.roles?.length || 0} roles exportados via SQL`));
156
- console.log(chalk.green(`🔄 Realtime: ${realtimeResult.success ? 'Configurações capturadas interativamente' : 'Falharam'}`));
150
+ // Determinar mensagem correta baseada no método usado
151
+ let realtimeMessage = 'Falharam';
152
+ if (realtimeResult.success) {
153
+ if (options.skipRealtime) {
154
+ realtimeMessage = 'Configurações copiadas do backup anterior';
155
+ } else {
156
+ realtimeMessage = 'Configurações capturadas interativamente';
157
+ }
158
+ }
159
+ console.log(chalk.green(`🔄 Realtime: ${realtimeMessage}`));
157
160
 
158
161
  return { success: true, backupDir, manifest };
159
162
  }
@@ -220,12 +223,16 @@ function showDockerMessagesAndExit(reason) {
220
223
  }
221
224
 
222
225
  // Backup da database usando pg_dumpall via Docker (idêntico ao Supabase Dashboard)
223
- async function backupDatabaseWithDocker(databaseUrl, backupDir) {
226
+ async function backupDatabase(projectId, backupDir) {
224
227
  try {
225
- console.log(chalk.gray('🐳 Criando backup completo via pg_dumpall Docker...'));
228
+ console.log(chalk.gray(' - Criando backup completo via pg_dumpall...'));
229
+
230
+ const { execSync } = require('child_process');
231
+ const config = await readConfig();
226
232
 
227
233
  // Extrair credenciais da databaseUrl
228
- const urlMatch = databaseUrl.match(/postgresql:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/(.+)/);
234
+ const dbUrl = config.supabase.databaseUrl;
235
+ const urlMatch = dbUrl.match(/postgresql:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/(.+)/);
229
236
 
230
237
  if (!urlMatch) {
231
238
  throw new Error('Database URL inválida');
@@ -233,7 +240,7 @@ async function backupDatabaseWithDocker(databaseUrl, backupDir) {
233
240
 
234
241
  const [, username, password, host, port, database] = urlMatch;
235
242
 
236
- // Gerar nome do arquivo igual ao dashboard Supabase
243
+ // Gerar nome do arquivo igual ao dashboard
237
244
  const now = new Date();
238
245
  const day = String(now.getDate()).padStart(2, '0');
239
246
  const month = String(now.getMonth() + 1).padStart(2, '0');
@@ -243,14 +250,14 @@ async function backupDatabaseWithDocker(databaseUrl, backupDir) {
243
250
  const seconds = String(now.getSeconds()).padStart(2, '0');
244
251
 
245
252
  const fileName = `db_cluster-${day}-${month}-${year}@${hours}-${minutes}-${seconds}.backup`;
246
- const filePath = path.join(backupDir, fileName);
247
253
 
248
- console.log(chalk.gray(` - Arquivo: ${fileName}`));
254
+ // CORREÇÃO: Usar caminho absoluto igual às Edge Functions
255
+ const backupDirAbs = path.resolve(backupDir);
249
256
 
250
- // Comando pg_dumpall via Docker (idêntico ao dashboard)
257
+ // Comando pg_dumpall via Docker (mesma abordagem das Edge Functions)
251
258
  const dockerCmd = [
252
259
  'docker run --rm --network host',
253
- `-v "${backupDir}:/host"`,
260
+ `-v "${backupDirAbs}:/host"`,
254
261
  `-e PGPASSWORD="${password}"`,
255
262
  'postgres:17 pg_dumpall',
256
263
  `-h ${host}`,
@@ -259,43 +266,28 @@ async function backupDatabaseWithDocker(databaseUrl, backupDir) {
259
266
  `-f /host/${fileName}`
260
267
  ].join(' ');
261
268
 
262
- console.log(chalk.gray(' - Executando pg_dumpall via Docker...'));
263
- await execAsync(dockerCmd, { stdio: 'pipe' });
269
+ console.log(chalk.gray(` - Executando pg_dumpall via Docker...`));
270
+ execSync(dockerCmd, { stdio: 'pipe' });
264
271
 
265
272
  // Compactar igual ao Supabase Dashboard
266
- console.log(chalk.gray(' - Compactando arquivo...'));
267
273
  const gzipCmd = [
268
274
  'docker run --rm',
269
- `-v "${backupDir}:/host"`,
270
- 'postgres:17 gzip /host/' + fileName
275
+ `-v "${backupDirAbs}:/host"`,
276
+ `postgres:17 gzip /host/${fileName}`
271
277
  ].join(' ');
272
278
 
273
- await execAsync(gzipCmd, { stdio: 'pipe' });
279
+ execSync(gzipCmd, { stdio: 'pipe' });
274
280
 
275
281
  const finalFileName = `${fileName}.gz`;
276
- const finalFilePath = path.join(backupDir, finalFileName);
277
-
278
- // Validar arquivo gerado
279
- if (!fs.existsSync(finalFilePath)) {
280
- throw new Error('Arquivo de backup não foi criado');
281
- }
282
-
283
- const stats = fs.statSync(finalFilePath);
282
+ const stats = fs.statSync(path.join(backupDir, finalFileName));
284
283
  const sizeKB = (stats.size / 1024).toFixed(1);
285
284
 
286
285
  console.log(chalk.green(` ✅ Database backup: ${finalFileName} (${sizeKB} KB)`));
287
286
 
288
- return {
289
- success: true,
290
- fileName: finalFileName,
291
- size: sizeKB,
292
- method: 'pg_dumpall_docker',
293
- dashboard_compatible: true
294
- };
295
-
287
+ return { success: true, size: sizeKB, fileName: finalFileName };
296
288
  } catch (error) {
297
- console.log(chalk.red(` Erro no backup do database: ${error.message}`));
298
- return { success: false, error: error.message };
289
+ console.log(chalk.yellow(` ⚠️ Erro no backup do database: ${error.message}`));
290
+ return { success: false };
299
291
  }
300
292
  }
301
293
 
@@ -17,7 +17,7 @@ async function captureRealtimeSettings(projectId, backupDir, skipInteractive = f
17
17
  const previousSettings = await getPreviousRealtimeSettings(backupDir);
18
18
 
19
19
  if (skipInteractive && previousSettings) {
20
- console.log('📋 Usando configurações de Realtime Settings do backup anterior...');
20
+ console.log('📋 Copiando Realtime Settings do backup anterior...');
21
21
  await fs.writeFile(settingsFile, JSON.stringify(previousSettings, null, 2));
22
22
  return previousSettings;
23
23
  }