smoonb 0.0.7 → 0.0.8

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.
@@ -1,361 +0,0 @@
1
- /**
2
- * Comando de gerenciamento de secrets do Supabase
3
- * Export/import sem commitar no git
4
- */
5
-
6
- const chalk = require('chalk');
7
- const fs = require('fs');
8
- const path = require('path');
9
-
10
- /**
11
- * Gerenciamento de secrets do Supabase
12
- * Resolve o problema: secrets sensíveis não devem ser commitados
13
- */
14
- async function secretsCommand(options) {
15
- console.log(chalk.red.bold('🚀 smoonb - EXPERIMENTAL VERSION'));
16
- console.log(chalk.red.bold('⚠️ VERSÃO EXPERIMENTAL - NUNCA TESTADA EM PRODUÇÃO!'));
17
- console.log(chalk.red.bold('🚨 USE POR SUA CONTA E RISCO - Pode causar perda de dados!'));
18
- console.log(chalk.red.bold('❌ NÃO NOS RESPONSABILIZAMOS por qualquer perda de dados!\n'));
19
-
20
- console.log(chalk.cyan.bold('🔐 Gerenciamento de secrets do Supabase...\n'));
21
-
22
- try {
23
- const args = process.argv.slice(3); // Remover 'smoonb', 'secrets'
24
-
25
- if (args.length === 0) {
26
- showSecretsHelp();
27
- return;
28
- }
29
-
30
- const action = args[0];
31
-
32
- switch (action) {
33
- case 'export':
34
- await exportSecrets(options);
35
- break;
36
- case 'import':
37
- await importSecrets(options);
38
- break;
39
- case 'list':
40
- await listSecrets(options);
41
- break;
42
- case 'validate':
43
- await validateSecrets(options);
44
- break;
45
- default:
46
- console.error(chalk.red.bold('❌ Ação não reconhecida:'), action);
47
- showSecretsHelp();
48
- process.exit(1);
49
- }
50
-
51
- } catch (error) {
52
- console.error(chalk.red.bold('❌ Erro durante o gerenciamento de secrets:'), error.message);
53
- process.exit(1);
54
- }
55
- }
56
-
57
- /**
58
- * Exportar secrets para arquivo temporário (gitignored)
59
- */
60
- async function exportSecrets(options) {
61
- console.log(chalk.blue.bold('📤 Exportando secrets...\n'));
62
-
63
- try {
64
- // Procurar arquivos de configuração com secrets
65
- const envFiles = [
66
- '.env',
67
- '.env.local',
68
- '.env.production',
69
- '.env.development'
70
- ];
71
-
72
- const secrets = {};
73
- let foundSecrets = false;
74
-
75
- for (const envFile of envFiles) {
76
- if (fs.existsSync(envFile)) {
77
- console.log(chalk.gray(` - Lendo ${envFile}...`));
78
-
79
- const envContent = await fs.promises.readFile(envFile, 'utf8');
80
- const lines = envContent.split('\n');
81
-
82
- for (const line of lines) {
83
- const trimmedLine = line.trim();
84
- if (trimmedLine && !trimmedLine.startsWith('#')) {
85
- const [key, ...valueParts] = trimmedLine.split('=');
86
- if (key && valueParts.length > 0) {
87
- const value = valueParts.join('=');
88
- secrets[key.trim()] = value.trim();
89
- foundSecrets = true;
90
- }
91
- }
92
- }
93
- }
94
- }
95
-
96
- if (!foundSecrets) {
97
- console.log(chalk.yellow('⚠️ Nenhum secret encontrado nos arquivos .env'));
98
- console.log(chalk.gray(' - Verifique se existem arquivos .env no projeto'));
99
- return;
100
- }
101
-
102
- // Criar arquivo de secrets temporário (gitignored)
103
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
104
- const secretsFile = `smoonb-secrets-${timestamp}.env`;
105
-
106
- let secretsContent = `# smoonb Secrets Export - ${new Date().toISOString()}\n`;
107
- secretsContent += `# ⚠️ NÃO COMMITE ESTE ARQUIVO! ⚠️\n`;
108
- secretsContent += `# Este arquivo contém secrets sensíveis\n\n`;
109
-
110
- for (const [key, value] of Object.entries(secrets)) {
111
- secretsContent += `${key}=${value}\n`;
112
- }
113
-
114
- await fs.promises.writeFile(secretsFile, secretsContent);
115
-
116
- console.log(chalk.green('✅ Secrets exportados com sucesso!'));
117
- console.log(chalk.blue('📁 Arquivo:'), secretsFile);
118
- console.log(chalk.blue('🔢 Secrets encontrados:'), Object.keys(secrets).length);
119
- console.log(chalk.yellow('\n⚠️ IMPORTANTE: NÃO commite este arquivo!'));
120
- console.log(chalk.yellow('💡 Use "smoonb secrets import" para importar em outro projeto'));
121
-
122
- // Adicionar ao .gitignore se não estiver lá
123
- await ensureGitignore(secretsFile);
124
-
125
- } catch (error) {
126
- console.error(chalk.red.bold('❌ Erro durante export de secrets:'), error.message);
127
- throw error;
128
- }
129
- }
130
-
131
- /**
132
- * Importar secrets de arquivo temporário
133
- */
134
- async function importSecrets(options) {
135
- console.log(chalk.blue.bold('📥 Importando secrets...\n'));
136
-
137
- try {
138
- // Procurar arquivo de secrets mais recente
139
- const secretsFiles = fs.readdirSync('.')
140
- .filter(file => file.startsWith('smoonb-secrets-') && file.endsWith('.env'))
141
- .sort()
142
- .reverse();
143
-
144
- if (secretsFiles.length === 0) {
145
- console.error(chalk.red.bold('❌ Nenhum arquivo de secrets encontrado'));
146
- console.log(chalk.yellow('💡 Use "smoonb secrets export" primeiro'));
147
- process.exit(1);
148
- }
149
-
150
- const secretsFile = secretsFiles[0];
151
- console.log(chalk.gray(` - Usando arquivo: ${secretsFile}`));
152
-
153
- // Ler arquivo de secrets
154
- const secretsContent = await fs.promises.readFile(secretsFile, 'utf8');
155
- const lines = secretsContent.split('\n');
156
-
157
- const secrets = {};
158
- for (const line of lines) {
159
- const trimmedLine = line.trim();
160
- if (trimmedLine && !trimmedLine.startsWith('#')) {
161
- const [key, ...valueParts] = trimmedLine.split('=');
162
- if (key && valueParts.length > 0) {
163
- const value = valueParts.join('=');
164
- secrets[key.trim()] = value.trim();
165
- }
166
- }
167
- }
168
-
169
- if (Object.keys(secrets).length === 0) {
170
- console.log(chalk.yellow('⚠️ Nenhum secret válido encontrado no arquivo'));
171
- return;
172
- }
173
-
174
- // Criar/atualizar .env.local
175
- const envLocalPath = '.env.local';
176
- let envLocalContent = `# smoonb Import - ${new Date().toISOString()}\n`;
177
- envLocalContent += `# Secrets importados automaticamente\n\n`;
178
-
179
- for (const [key, value] of Object.entries(secrets)) {
180
- envLocalContent += `${key}=${value}\n`;
181
- }
182
-
183
- await fs.promises.writeFile(envLocalPath, envLocalContent);
184
-
185
- console.log(chalk.green('✅ Secrets importados com sucesso!'));
186
- console.log(chalk.blue('📁 Arquivo:'), envLocalPath);
187
- console.log(chalk.blue('🔢 Secrets importados:'), Object.keys(secrets).length);
188
- console.log(chalk.yellow('\n💡 Os secrets foram salvos em .env.local (gitignored)'));
189
-
190
- } catch (error) {
191
- console.error(chalk.red.bold('❌ Erro durante import de secrets:'), error.message);
192
- throw error;
193
- }
194
- }
195
-
196
- /**
197
- * Listar secrets encontrados (sem mostrar valores)
198
- */
199
- async function listSecrets(options) {
200
- console.log(chalk.blue.bold('📋 Listando secrets encontrados...\n'));
201
-
202
- try {
203
- const envFiles = [
204
- '.env',
205
- '.env.local',
206
- '.env.production',
207
- '.env.development'
208
- ];
209
-
210
- const allSecrets = new Set();
211
- let foundFiles = 0;
212
-
213
- for (const envFile of envFiles) {
214
- if (fs.existsSync(envFile)) {
215
- foundFiles++;
216
- console.log(chalk.gray(` - ${envFile}:`));
217
-
218
- const envContent = await fs.promises.readFile(envFile, 'utf8');
219
- const lines = envContent.split('\n');
220
-
221
- for (const line of lines) {
222
- const trimmedLine = line.trim();
223
- if (trimmedLine && !trimmedLine.startsWith('#')) {
224
- const [key] = trimmedLine.split('=');
225
- if (key) {
226
- allSecrets.add(key.trim());
227
- console.log(chalk.gray(` • ${key.trim()}`));
228
- }
229
- }
230
- }
231
- console.log();
232
- }
233
- }
234
-
235
- if (foundFiles === 0) {
236
- console.log(chalk.yellow('⚠️ Nenhum arquivo .env encontrado'));
237
- return;
238
- }
239
-
240
- console.log(chalk.green('✅ Resumo:'));
241
- console.log(chalk.blue('📁 Arquivos analisados:'), foundFiles);
242
- console.log(chalk.blue('🔢 Secrets únicos encontrados:'), allSecrets.size);
243
-
244
- } catch (error) {
245
- console.error(chalk.red.bold('❌ Erro durante listagem de secrets:'), error.message);
246
- throw error;
247
- }
248
- }
249
-
250
- /**
251
- * Validar secrets (verificar se estão configurados)
252
- */
253
- async function validateSecrets(options) {
254
- console.log(chalk.blue.bold('🔍 Validando secrets...\n'));
255
-
256
- try {
257
- const requiredSecrets = [
258
- 'SUPABASE_URL',
259
- 'SUPABASE_ANON_KEY',
260
- 'SUPABASE_SERVICE_ROLE_KEY'
261
- ];
262
-
263
- const envFiles = [
264
- '.env',
265
- '.env.local',
266
- '.env.production',
267
- '.env.development'
268
- ];
269
-
270
- const foundSecrets = new Set();
271
- let foundFiles = 0;
272
-
273
- // Coletar todos os secrets
274
- for (const envFile of envFiles) {
275
- if (fs.existsSync(envFile)) {
276
- foundFiles++;
277
- const envContent = await fs.promises.readFile(envFile, 'utf8');
278
- const lines = envContent.split('\n');
279
-
280
- for (const line of lines) {
281
- const trimmedLine = line.trim();
282
- if (trimmedLine && !trimmedLine.startsWith('#')) {
283
- const [key] = trimmedLine.split('=');
284
- if (key) {
285
- foundSecrets.add(key.trim());
286
- }
287
- }
288
- }
289
- }
290
- }
291
-
292
- // Validar secrets obrigatórios
293
- console.log(chalk.gray(' - Verificando secrets obrigatórios:'));
294
- let allValid = true;
295
-
296
- for (const secret of requiredSecrets) {
297
- if (foundSecrets.has(secret)) {
298
- console.log(chalk.green(` ✅ ${secret}`));
299
- } else {
300
- console.log(chalk.red(` ❌ ${secret} - NÃO ENCONTRADO`));
301
- allValid = false;
302
- }
303
- }
304
-
305
- console.log(chalk.green('\n✅ Validação concluída!'));
306
- console.log(chalk.blue('📁 Arquivos analisados:'), foundFiles);
307
- console.log(chalk.blue('🔢 Secrets encontrados:'), foundSecrets.size);
308
-
309
- if (allValid) {
310
- console.log(chalk.green('🎉 Todos os secrets obrigatórios estão configurados!'));
311
- } else {
312
- console.log(chalk.yellow('⚠️ Alguns secrets obrigatórios estão faltando'));
313
- console.log(chalk.yellow('💡 Use "smoonb config --init" para configurar'));
314
- }
315
-
316
- } catch (error) {
317
- console.error(chalk.red.bold('❌ Erro durante validação de secrets:'), error.message);
318
- throw error;
319
- }
320
- }
321
-
322
- /**
323
- * Mostrar ajuda do comando secrets
324
- */
325
- function showSecretsHelp() {
326
- console.log(chalk.cyan.bold('🔐 Comandos de Secrets disponíveis:\n'));
327
- console.log(chalk.cyan(' export'), chalk.gray(' - Exportar secrets para arquivo temporário'));
328
- console.log(chalk.cyan(' import'), chalk.gray(' - Importar secrets de arquivo temporário'));
329
- console.log(chalk.cyan(' list'), chalk.gray(' - Listar secrets encontrados (sem valores)'));
330
- console.log(chalk.cyan(' validate'), chalk.gray(' - Validar secrets obrigatórios'));
331
- console.log(chalk.yellow('\n💡 Exemplos:'));
332
- console.log(chalk.gray(' smoonb secrets export'));
333
- console.log(chalk.gray(' smoonb secrets import'));
334
- console.log(chalk.gray(' smoonb secrets list'));
335
- console.log(chalk.gray(' smoonb secrets validate'));
336
- }
337
-
338
- /**
339
- * Garantir que arquivo está no .gitignore
340
- */
341
- async function ensureGitignore(filename) {
342
- try {
343
- const gitignorePath = '.gitignore';
344
- let gitignoreContent = '';
345
-
346
- if (fs.existsSync(gitignorePath)) {
347
- gitignoreContent = await fs.promises.readFile(gitignorePath, 'utf8');
348
- }
349
-
350
- // Verificar se já está no .gitignore
351
- if (!gitignoreContent.includes(filename)) {
352
- gitignoreContent += `\n# smoonb secrets files\n${filename}\n`;
353
- await fs.promises.writeFile(gitignorePath, gitignoreContent);
354
- console.log(chalk.gray(` - Arquivo ${filename} adicionado ao .gitignore`));
355
- }
356
- } catch (error) {
357
- console.log(chalk.yellow('⚠️ Não foi possível atualizar .gitignore:'), error.message);
358
- }
359
- }
360
-
361
- module.exports = secretsCommand;