smoonb 0.0.42 → 0.0.45
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/restore.js +99 -25
package/package.json
CHANGED
package/src/commands/restore.js
CHANGED
|
@@ -89,7 +89,7 @@ module.exports = async (options) => {
|
|
|
89
89
|
}
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
-
// Listar backups válidos (
|
|
92
|
+
// Listar backups válidos (aceita .backup.gz e .backup)
|
|
93
93
|
async function listValidBackups(backupsDir) {
|
|
94
94
|
if (!fs.existsSync(backupsDir)) {
|
|
95
95
|
return [];
|
|
@@ -102,7 +102,10 @@ async function listValidBackups(backupsDir) {
|
|
|
102
102
|
if (item.isDirectory() && item.name.startsWith('backup-')) {
|
|
103
103
|
const backupPath = path.join(backupsDir, item.name);
|
|
104
104
|
const files = fs.readdirSync(backupPath);
|
|
105
|
-
|
|
105
|
+
// Aceitar tanto .backup.gz quanto .backup
|
|
106
|
+
const backupFile = files.find(file =>
|
|
107
|
+
file.endsWith('.backup.gz') || file.endsWith('.backup')
|
|
108
|
+
);
|
|
106
109
|
|
|
107
110
|
if (backupFile) {
|
|
108
111
|
const manifestPath = path.join(backupPath, 'backup-manifest.json');
|
|
@@ -184,7 +187,7 @@ async function askRestoreComponents(backupPath) {
|
|
|
184
187
|
questions.push({
|
|
185
188
|
type: 'confirm',
|
|
186
189
|
name: 'restoreDatabase',
|
|
187
|
-
message: 'Deseja restaurar Database
|
|
190
|
+
message: 'Deseja restaurar Database (S/n):',
|
|
188
191
|
default: true
|
|
189
192
|
});
|
|
190
193
|
|
|
@@ -194,7 +197,7 @@ async function askRestoreComponents(backupPath) {
|
|
|
194
197
|
questions.push({
|
|
195
198
|
type: 'confirm',
|
|
196
199
|
name: 'restoreEdgeFunctions',
|
|
197
|
-
message: 'Deseja restaurar Edge Functions
|
|
200
|
+
message: 'Deseja restaurar Edge Functions (S/n):',
|
|
198
201
|
default: true
|
|
199
202
|
});
|
|
200
203
|
}
|
|
@@ -204,8 +207,8 @@ async function askRestoreComponents(backupPath) {
|
|
|
204
207
|
questions.push({
|
|
205
208
|
type: 'confirm',
|
|
206
209
|
name: 'restoreAuthSettings',
|
|
207
|
-
message: 'Deseja restaurar Auth Settings (
|
|
208
|
-
default:
|
|
210
|
+
message: 'Deseja restaurar Auth Settings (s/N):',
|
|
211
|
+
default: false
|
|
209
212
|
});
|
|
210
213
|
}
|
|
211
214
|
|
|
@@ -215,7 +218,7 @@ async function askRestoreComponents(backupPath) {
|
|
|
215
218
|
questions.push({
|
|
216
219
|
type: 'confirm',
|
|
217
220
|
name: 'restoreStorage',
|
|
218
|
-
message: 'Deseja ver informações de Storage Buckets
|
|
221
|
+
message: 'Deseja ver informações de Storage Buckets (s/N):',
|
|
219
222
|
default: false
|
|
220
223
|
});
|
|
221
224
|
}
|
|
@@ -227,7 +230,7 @@ async function askRestoreComponents(backupPath) {
|
|
|
227
230
|
questions.push({
|
|
228
231
|
type: 'confirm',
|
|
229
232
|
name: 'restoreDatabaseSettings',
|
|
230
|
-
message: 'Deseja restaurar Database Extensions and Settings
|
|
233
|
+
message: 'Deseja restaurar Database Extensions and Settings (s/N):',
|
|
231
234
|
default: false
|
|
232
235
|
});
|
|
233
236
|
}
|
|
@@ -237,8 +240,8 @@ async function askRestoreComponents(backupPath) {
|
|
|
237
240
|
questions.push({
|
|
238
241
|
type: 'confirm',
|
|
239
242
|
name: 'restoreRealtimeSettings',
|
|
240
|
-
message: 'Deseja restaurar Realtime Settings (
|
|
241
|
-
default:
|
|
243
|
+
message: 'Deseja restaurar Realtime Settings (s/N):',
|
|
244
|
+
default: false
|
|
242
245
|
});
|
|
243
246
|
}
|
|
244
247
|
|
|
@@ -313,9 +316,9 @@ async function confirmExecution() {
|
|
|
313
316
|
}
|
|
314
317
|
|
|
315
318
|
// Restaurar Database via psql (conforme documentação oficial Supabase: https://supabase.com/docs/guides/platform/migrating-within-supabase/dashboard-restore)
|
|
319
|
+
// Aceita tanto arquivos .backup.gz quanto .backup já descompactados
|
|
316
320
|
async function restoreDatabaseGz(backupFilePath, targetDatabaseUrl) {
|
|
317
321
|
console.log(chalk.blue('📊 Restaurando Database...'));
|
|
318
|
-
console.log(chalk.gray(' - Descompactando backup (se necessário)...'));
|
|
319
322
|
|
|
320
323
|
try {
|
|
321
324
|
const { execSync } = require('child_process');
|
|
@@ -324,9 +327,11 @@ async function restoreDatabaseGz(backupFilePath, targetDatabaseUrl) {
|
|
|
324
327
|
const fileName = path.basename(backupFilePath);
|
|
325
328
|
let uncompressedFile = fileName;
|
|
326
329
|
|
|
327
|
-
//
|
|
328
|
-
if (fileName.endsWith('.gz')) {
|
|
330
|
+
// Verificar se é arquivo .backup.gz (compactado) ou .backup (descompactado)
|
|
331
|
+
if (fileName.endsWith('.backup.gz')) {
|
|
332
|
+
console.log(chalk.gray(' - Arquivo .backup.gz detectado'));
|
|
329
333
|
console.log(chalk.gray(' - Extraindo arquivo .gz...'));
|
|
334
|
+
|
|
330
335
|
const unzipCmd = [
|
|
331
336
|
'docker run --rm',
|
|
332
337
|
`-v "${backupDirAbs}:/host"`,
|
|
@@ -336,6 +341,11 @@ async function restoreDatabaseGz(backupFilePath, targetDatabaseUrl) {
|
|
|
336
341
|
execSync(unzipCmd, { stdio: 'pipe' });
|
|
337
342
|
uncompressedFile = fileName.replace('.gz', '');
|
|
338
343
|
console.log(chalk.gray(' - Arquivo descompactado: ' + uncompressedFile));
|
|
344
|
+
} else if (fileName.endsWith('.backup')) {
|
|
345
|
+
console.log(chalk.gray(' - Arquivo .backup detectado (já descompactado)'));
|
|
346
|
+
console.log(chalk.gray(' - Prosseguindo com restauração direta'));
|
|
347
|
+
} else {
|
|
348
|
+
throw new Error(`Formato de arquivo inválido. Esperado .backup.gz ou .backup, recebido: ${fileName}`);
|
|
339
349
|
}
|
|
340
350
|
|
|
341
351
|
// Extrair credenciais da URL de conexão
|
|
@@ -391,17 +401,25 @@ async function restoreEdgeFunctions(backupPath, targetProject) {
|
|
|
391
401
|
console.log(chalk.blue('\n⚡ Restaurando Edge Functions...'));
|
|
392
402
|
|
|
393
403
|
try {
|
|
404
|
+
const fs = require('fs').promises;
|
|
394
405
|
const { execSync } = require('child_process');
|
|
395
406
|
const edgeFunctionsDir = path.join(backupPath, 'edge-functions');
|
|
396
407
|
|
|
397
|
-
if (!fs.
|
|
408
|
+
if (!await fs.access(edgeFunctionsDir).then(() => true).catch(() => false)) {
|
|
398
409
|
console.log(chalk.yellow(' ⚠️ Nenhuma Edge Function encontrada no backup'));
|
|
399
410
|
return;
|
|
400
411
|
}
|
|
401
412
|
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
|
|
413
|
+
const items = await fs.readdir(edgeFunctionsDir);
|
|
414
|
+
const functions = [];
|
|
415
|
+
|
|
416
|
+
for (const item of items) {
|
|
417
|
+
const itemPath = path.join(edgeFunctionsDir, item);
|
|
418
|
+
const stats = await fs.stat(itemPath);
|
|
419
|
+
if (stats.isDirectory()) {
|
|
420
|
+
functions.push(item);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
405
423
|
|
|
406
424
|
if (functions.length === 0) {
|
|
407
425
|
console.log(chalk.yellow(' ⚠️ Nenhuma Edge Function encontrada no backup'));
|
|
@@ -410,29 +428,55 @@ async function restoreEdgeFunctions(backupPath, targetProject) {
|
|
|
410
428
|
|
|
411
429
|
console.log(chalk.gray(` - Encontradas ${functions.length} Edge Function(s)`));
|
|
412
430
|
|
|
413
|
-
//
|
|
431
|
+
// ✅ COPIAR Edge Functions de backups/backup-XXX/edge-functions para supabase/functions
|
|
432
|
+
const supabaseFunctionsDir = path.join(process.cwd(), 'supabase', 'functions');
|
|
433
|
+
|
|
434
|
+
// Criar diretório supabase/functions se não existir
|
|
435
|
+
await fs.mkdir(supabaseFunctionsDir, { recursive: true });
|
|
436
|
+
|
|
437
|
+
// Limpar supabase/functions antes de copiar
|
|
438
|
+
console.log(chalk.gray(' - Limpando supabase/functions...'));
|
|
439
|
+
try {
|
|
440
|
+
await fs.rm(supabaseFunctionsDir, { recursive: true, force: true });
|
|
441
|
+
await fs.mkdir(supabaseFunctionsDir, { recursive: true });
|
|
442
|
+
} catch (cleanError) {
|
|
443
|
+
// Ignorar erro de limpeza se não existir
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Copiar cada Edge Function para supabase/functions
|
|
447
|
+
for (const funcName of functions) {
|
|
448
|
+
const backupFuncPath = path.join(edgeFunctionsDir, funcName);
|
|
449
|
+
const targetFuncPath = path.join(supabaseFunctionsDir, funcName);
|
|
450
|
+
|
|
451
|
+
console.log(chalk.gray(` - Copiando ${funcName} para supabase/functions...`));
|
|
452
|
+
|
|
453
|
+
// Copiar recursivamente
|
|
454
|
+
await copyDirectoryRecursive(backupFuncPath, targetFuncPath);
|
|
455
|
+
}
|
|
456
|
+
|
|
414
457
|
console.log(chalk.gray(` - Linkando com projeto ${targetProject.targetProjectId}...`));
|
|
415
458
|
|
|
459
|
+
// Linkar com o projeto destino
|
|
416
460
|
try {
|
|
417
461
|
execSync(`supabase link --project-ref ${targetProject.targetProjectId}`, {
|
|
418
462
|
stdio: 'pipe',
|
|
419
|
-
encoding: 'utf8'
|
|
463
|
+
encoding: 'utf8',
|
|
464
|
+
timeout: 10000
|
|
420
465
|
});
|
|
421
466
|
} catch (linkError) {
|
|
422
|
-
console.log(chalk.yellow(
|
|
467
|
+
console.log(chalk.yellow(' ⚠️ Link pode já existir, continuando...'));
|
|
423
468
|
}
|
|
424
469
|
|
|
425
|
-
// Deploy
|
|
470
|
+
// Deploy das Edge Functions
|
|
426
471
|
for (const funcName of functions) {
|
|
427
472
|
console.log(chalk.gray(` - Deployando ${funcName}...`));
|
|
428
473
|
|
|
429
474
|
try {
|
|
430
|
-
const functionPath = path.join(edgeFunctionsDir, funcName);
|
|
431
|
-
|
|
432
475
|
execSync(`supabase functions deploy ${funcName}`, {
|
|
433
|
-
cwd:
|
|
476
|
+
cwd: process.cwd(),
|
|
434
477
|
stdio: 'pipe',
|
|
435
|
-
encoding: 'utf8'
|
|
478
|
+
encoding: 'utf8',
|
|
479
|
+
timeout: 120000
|
|
436
480
|
});
|
|
437
481
|
|
|
438
482
|
console.log(chalk.green(` ✅ ${funcName} deployada com sucesso!`));
|
|
@@ -441,11 +485,41 @@ async function restoreEdgeFunctions(backupPath, targetProject) {
|
|
|
441
485
|
}
|
|
442
486
|
}
|
|
443
487
|
|
|
488
|
+
// Limpar supabase/functions após deploy
|
|
489
|
+
console.log(chalk.gray(' - Limpando supabase/functions após deploy...'));
|
|
490
|
+
try {
|
|
491
|
+
await fs.rm(supabaseFunctionsDir, { recursive: true, force: true });
|
|
492
|
+
} catch (cleanError) {
|
|
493
|
+
// Ignorar erro de limpeza
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
console.log(chalk.green(' ✅ Edge Functions restauradas com sucesso!'));
|
|
497
|
+
|
|
444
498
|
} catch (error) {
|
|
445
499
|
console.error(chalk.red(` ❌ Erro ao restaurar Edge Functions: ${error.message}`));
|
|
446
500
|
}
|
|
447
501
|
}
|
|
448
502
|
|
|
503
|
+
// Função auxiliar para copiar diretório recursivamente
|
|
504
|
+
async function copyDirectoryRecursive(src, dest) {
|
|
505
|
+
const fs = require('fs').promises;
|
|
506
|
+
|
|
507
|
+
await fs.mkdir(dest, { recursive: true });
|
|
508
|
+
|
|
509
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
510
|
+
|
|
511
|
+
for (const entry of entries) {
|
|
512
|
+
const srcPath = path.join(src, entry.name);
|
|
513
|
+
const destPath = path.join(dest, entry.name);
|
|
514
|
+
|
|
515
|
+
if (entry.isDirectory()) {
|
|
516
|
+
await copyDirectoryRecursive(srcPath, destPath);
|
|
517
|
+
} else {
|
|
518
|
+
await fs.copyFile(srcPath, destPath);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
449
523
|
// Restaurar Storage Buckets (interativo - exibir informações)
|
|
450
524
|
async function restoreStorageBuckets(backupPath, targetProject) {
|
|
451
525
|
console.log(chalk.blue('\n📦 Restaurando Storage Buckets...'));
|