smoonb 1.0.11 → 1.0.13
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/CHANGELOG.md +167 -150
- package/README.md +695 -687
- package/README.pt-BR.md +697 -687
- package/npm-shrinkwrap.json +2030 -0
- package/package.json +71 -68
- package/src/commands/backup/index.js +39 -21
- package/src/commands/backup/outcome.js +16 -0
- package/src/commands/backup/steps/00-license.js +427 -427
- package/src/commands/backup/steps/02-database.js +6 -6
- package/src/commands/backup/steps/03-database-separated.js +129 -161
- package/src/commands/backup/steps/04-database-settings.js +24 -40
- package/src/commands/backup/steps/07-storage.js +11 -10
- package/src/commands/backup/steps/08-custom-roles.js +5 -55
- package/src/commands/backup/steps/10-supabase-temp.js +0 -9
- package/src/commands/backup/steps/11-migrations.js +30 -74
- package/src/i18n/locales/en.json +825 -824
- package/src/i18n/locales/pt-BR.json +824 -823
- package/src/interactive/envMapper.js +6 -12
- package/src/utils/docker.js +6 -53
- package/src/utils/pg-dump-diagnostics.js +68 -64
- package/src/utils/supabaseCli.js +26 -32
|
@@ -1,79 +1,35 @@
|
|
|
1
|
-
const chalk = require('chalk');
|
|
2
1
|
const path = require('path');
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const {
|
|
6
|
-
const {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*/
|
|
12
|
-
module.exports = async (context) => {
|
|
13
|
-
const { projectId, accessToken, databaseUrl, backupDir } = context;
|
|
2
|
+
const fs = require('fs').promises;
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const { runSupabase } = require('../../../utils/supabaseCli');
|
|
5
|
+
const { runSql } = require('../../restore/pg');
|
|
6
|
+
const { copyDirectoryRecursive } = require('../../restore/utils');
|
|
7
|
+
module.exports = async ({ databaseUrl, accessToken, backupDir, postgresMajor = 17 }, { query = runSql, run = runSupabase } = {}) => {
|
|
8
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'smoonb-migrations-'));
|
|
9
|
+
let phase = 'migration_history_check_failed';
|
|
14
10
|
try {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
await cleanDir(migrationsDir);
|
|
23
|
-
console.log(chalk.white(` - ${getT('backup.steps.migrations.cleaning')}`));
|
|
24
|
-
|
|
25
|
-
// Baixar todas as migrations do servidor usando migration fetch
|
|
26
|
-
console.log(chalk.white(` - ${getT('backup.steps.migrations.downloading')}`));
|
|
27
|
-
|
|
28
|
-
const env = {
|
|
29
|
-
...process.env,
|
|
30
|
-
SUPABASE_ACCESS_TOKEN: accessToken
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
execSync('supabase migration fetch', {
|
|
35
|
-
cwd: process.cwd(),
|
|
36
|
-
stdio: 'pipe',
|
|
37
|
-
encoding: 'utf8',
|
|
38
|
-
timeout: 120000,
|
|
39
|
-
env
|
|
40
|
-
});
|
|
41
|
-
} catch (error) {
|
|
42
|
-
console.log(chalk.yellow(` ⚠️ ${getT('backup.steps.migrations.fetchError', { message: error.message })}`));
|
|
43
|
-
console.log(chalk.yellow(` 💡 ${getT('backup.steps.migrations.fetchTip')}`));
|
|
44
|
-
return { success: false };
|
|
11
|
+
const history = await query(databaseUrl, "BEGIN READ ONLY; SET LOCAL statement_timeout = '20s'; SELECT to_regclass('supabase_migrations.schema_migrations') IS NOT NULL; COMMIT;", { postgresMajor });
|
|
12
|
+
if (!['t', 'f'].includes(history.trim())) throw new Error('Unexpected history response');
|
|
13
|
+
let count = 0;
|
|
14
|
+
if (history.trim() === 't') {
|
|
15
|
+
const value = await query(databaseUrl, "BEGIN READ ONLY; SET LOCAL statement_timeout = '20s'; SELECT count(*) FROM supabase_migrations.schema_migrations; COMMIT;", { postgresMajor });
|
|
16
|
+
if (!/^\d+$/.test(value.trim())) throw new Error('Unexpected migration count');
|
|
17
|
+
count = Number(value.trim());
|
|
45
18
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Copiar migrations para o backup
|
|
52
|
-
const backupMigrationsDir = path.join(backupDir, 'migrations');
|
|
53
|
-
const copiedCount = await copyDirSafe(migrationsDir, backupMigrationsDir);
|
|
54
|
-
const relativePath = path.relative(process.cwd(), backupMigrationsDir);
|
|
55
|
-
console.log(chalk.white(` - ${getT('backup.steps.migrations.copying', { path: relativePath, count: copiedCount })}`));
|
|
56
|
-
|
|
57
|
-
if (copiedCount > 0) {
|
|
58
|
-
console.log(chalk.green(` ✅ ${getT('backup.steps.migrations.copied', { count: copiedCount })}`));
|
|
19
|
+
if (count === 0) {
|
|
20
|
+
await fs.mkdir(path.join(backupDir, 'migrations'), { recursive: true });
|
|
21
|
+
console.log('Migrations: nenhum histórico registrado no banco; nada a exportar.');
|
|
22
|
+
return { success: true, file_count: 0, reason: history.trim() === 'f' ? 'history_absent' : 'history_empty' };
|
|
59
23
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
file_count: copiedCount
|
|
72
|
-
};
|
|
73
|
-
} catch (error) {
|
|
74
|
-
const getT = global.smoonbI18n?.t || t;
|
|
75
|
-
console.log(chalk.yellow(` ⚠️ ${getT('backup.steps.migrations.error', { message: error.message })}`));
|
|
76
|
-
return { success: false };
|
|
77
|
-
}
|
|
24
|
+
phase = 'migration_export_failed';
|
|
25
|
+
await fs.mkdir(path.join(root, 'supabase', 'migrations'), { recursive: true });
|
|
26
|
+
await fs.writeFile(path.join(root, 'supabase', 'config.toml'), 'project_id = "smoonb-backup"\n');
|
|
27
|
+
run('supabase', ['migration', 'fetch', '--db-url', databaseUrl, '--workdir', root, '--yes'], { cwd: root, env: { ...process.env, SUPABASE_ACCESS_TOKEN: accessToken }, stdio: 'pipe' });
|
|
28
|
+
const source = path.join(root, 'supabase', 'migrations');
|
|
29
|
+
await copyDirectoryRecursive(source, path.join(backupDir, 'migrations'));
|
|
30
|
+
const fileCount = (await fs.readdir(source)).filter(name => name.endsWith('.sql')).length;
|
|
31
|
+
if (fileCount !== count) throw new Error('Migration export count mismatch');
|
|
32
|
+
return { success: true, file_count: fileCount };
|
|
33
|
+
} catch { return { success: false, reason: phase, action: 'Check database connectivity and access to supabase_migrations.schema_migrations; retry the backup.' }; }
|
|
34
|
+
finally { await fs.rm(root, { recursive: true, force: true }); }
|
|
78
35
|
};
|
|
79
|
-
|