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 +1 -1
- package/src/commands/backup.js +34 -42
- package/src/utils/realtime-settings.js +1 -1
package/package.json
CHANGED
package/src/commands/backup.js
CHANGED
|
@@ -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
|
|
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: ${
|
|
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
|
-
|
|
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
|
|
226
|
+
async function backupDatabase(projectId, backupDir) {
|
|
224
227
|
try {
|
|
225
|
-
console.log(chalk.gray('
|
|
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
|
|
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
|
|
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
|
-
|
|
254
|
+
// CORREÇÃO: Usar caminho absoluto igual às Edge Functions
|
|
255
|
+
const backupDirAbs = path.resolve(backupDir);
|
|
249
256
|
|
|
250
|
-
// Comando pg_dumpall via Docker (
|
|
257
|
+
// Comando pg_dumpall via Docker (mesma abordagem das Edge Functions)
|
|
251
258
|
const dockerCmd = [
|
|
252
259
|
'docker run --rm --network host',
|
|
253
|
-
`-v "${
|
|
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(
|
|
263
|
-
|
|
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 "${
|
|
270
|
-
|
|
275
|
+
`-v "${backupDirAbs}:/host"`,
|
|
276
|
+
`postgres:17 gzip /host/${fileName}`
|
|
271
277
|
].join(' ');
|
|
272
278
|
|
|
273
|
-
|
|
279
|
+
execSync(gzipCmd, { stdio: 'pipe' });
|
|
274
280
|
|
|
275
281
|
const finalFileName = `${fileName}.gz`;
|
|
276
|
-
const
|
|
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.
|
|
298
|
-
return { success: false
|
|
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('📋
|
|
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
|
}
|