smoonb 0.0.14 → 0.0.16

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.14",
3
+ "version": "0.0.16",
4
4
  "description": "Complete Supabase backup and migration tool - EXPERIMENTAL VERSION - USE AT YOUR OWN RISK",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -256,66 +256,104 @@ async function backupDatabaseWithPgDump(databaseUrl, backupDir, pgDumpPath) {
256
256
  // Backup das Edge Functions via Supabase API
257
257
  async function backupEdgeFunctions(config, backupDir) {
258
258
  try {
259
- const supabase = createClient(config.supabase.url, config.supabase.serviceKey);
260
259
  const functionsDir = path.join(backupDir, 'edge-functions');
261
260
  await ensureDir(functionsDir);
262
261
 
263
- console.log(chalk.gray(' - Listando Edge Functions...'));
262
+ console.log(chalk.gray(' - Listando Edge Functions via Management API...'));
264
263
 
265
- // Listar Edge Functions via API
266
- const { data: functions, error } = await supabase.functions.list();
264
+ // Usar fetch direto para Management API
265
+ const functionsResponse = await fetch(`https://api.supabase.com/v1/projects/${config.supabase.projectId}/functions`, {
266
+ headers: {
267
+ 'Authorization': `Bearer ${config.supabase.serviceKey}`,
268
+ 'apikey': config.supabase.serviceKey,
269
+ 'Content-Type': 'application/json'
270
+ }
271
+ });
267
272
 
268
- if (error) {
269
- console.log(chalk.yellow(` ⚠️ Erro ao listar Edge Functions: ${error.message}`));
273
+ if (!functionsResponse.ok) {
274
+ console.log(chalk.yellow(` ⚠️ Erro ao listar Edge Functions: ${functionsResponse.status} ${functionsResponse.statusText}`));
270
275
  return { success: false, functions: [] };
271
276
  }
272
277
 
278
+ const functions = await functionsResponse.json();
279
+
280
+ if (!functions || functions.length === 0) {
281
+ console.log(chalk.gray(' - Nenhuma Edge Function encontrada'));
282
+ await writeJson(path.join(functionsDir, 'README.md'), {
283
+ message: 'Nenhuma Edge Function encontrada neste projeto'
284
+ });
285
+ return { success: true, functions: [] };
286
+ }
287
+
288
+ console.log(chalk.gray(` - Encontradas ${functions.length} Edge Functions`));
289
+
273
290
  const downloadedFunctions = [];
274
291
 
275
- for (const func of functions || []) {
292
+ // Baixar todas as functions encontradas
293
+ for (const func of functions) {
276
294
  try {
277
- console.log(chalk.gray(` - Baixando function: ${func.name}`));
295
+ console.log(chalk.gray(` - Baixando: ${func.name}`));
278
296
 
279
- // Criar diretório para a function
280
- const funcDir = path.join(functionsDir, func.name);
281
- await ensureDir(funcDir);
282
-
283
- // Baixar código da function via API
284
- const { data: functionCode, error: codeError } = await supabase.functions.getEdgeFunction(func.name);
297
+ // Baixar código da function via Management API
298
+ const functionResponse = await fetch(`https://api.supabase.com/v1/projects/${config.supabase.projectId}/functions/${func.name}`, {
299
+ headers: {
300
+ 'Authorization': `Bearer ${config.supabase.serviceKey}`,
301
+ 'apikey': config.supabase.serviceKey,
302
+ 'Content-Type': 'application/json'
303
+ }
304
+ });
285
305
 
286
- if (codeError) {
287
- console.log(chalk.yellow(` ⚠️ Erro ao baixar ${func.name}: ${codeError.message}`));
306
+ if (!functionResponse.ok) {
307
+ console.log(chalk.yellow(` ⚠️ Erro ao baixar ${func.name}: ${functionResponse.status} ${functionResponse.statusText}`));
288
308
  continue;
289
309
  }
290
310
 
291
- // Salvar arquivos da function
292
- if (functionCode) {
293
- // Salvar index.ts
294
- const indexPath = path.join(funcDir, 'index.ts');
295
- await fs.promises.writeFile(indexPath, functionCode.code || '// Function code not available');
311
+ const functionData = await functionResponse.json();
312
+
313
+ // Salvar arquivos dinamicamente
314
+ const funcDir = path.join(functionsDir, func.name);
315
+ await ensureDir(funcDir);
296
316
 
297
- // Salvar deno.json se disponível
298
- if (functionCode.deno_config) {
317
+ // Salvar cada arquivo da function
318
+ if (functionData && functionData.files) {
319
+ for (const file of functionData.files) {
320
+ const fileName = path.basename(file.name);
321
+ const filePath = path.join(funcDir, fileName);
322
+ await fs.promises.writeFile(filePath, file.content);
323
+ }
324
+ } else if (functionData && functionData.code) {
325
+ // Fallback para estrutura simples
326
+ const indexPath = path.join(funcDir, 'index.ts');
327
+ await fs.promises.writeFile(indexPath, functionData.code);
328
+
329
+ if (functionData.deno_config) {
299
330
  const denoPath = path.join(funcDir, 'deno.json');
300
- await writeJson(denoPath, functionCode.deno_config);
331
+ await writeJson(denoPath, functionData.deno_config);
301
332
  }
333
+ } else {
334
+ // Criar arquivo placeholder se não houver código
335
+ const indexPath = path.join(funcDir, 'index.ts');
336
+ await fs.promises.writeFile(indexPath, `// Edge Function: ${func.name}\n// Code not available via API\n`);
337
+ }
302
338
 
303
- downloadedFunctions.push({
304
- name: func.name,
305
- version: func.version,
306
- files: ['index.ts', 'deno.json'].filter(file => fs.existsSync(path.join(funcDir, file)))
307
- });
339
+ downloadedFunctions.push({
340
+ name: func.name,
341
+ slug: func.name,
342
+ version: func.version || 'unknown',
343
+ files: fs.existsSync(funcDir) ? fs.readdirSync(funcDir) : []
344
+ });
308
345
 
309
- console.log(chalk.green(` ✅ ${func.name} baixada`));
310
- }
346
+ console.log(chalk.green(` ✅ ${func.name} baixada`));
311
347
  } catch (error) {
312
- console.log(chalk.yellow(` ⚠️ Erro ao processar ${func.name}: ${error.message}`));
348
+ console.log(chalk.yellow(` ⚠️ Erro ao baixar ${func.name}: ${error.message}`));
313
349
  }
314
350
  }
315
351
 
352
+ console.log(chalk.green(`✅ Edge Functions backupadas: ${downloadedFunctions.length} functions`));
316
353
  return { success: true, functions: downloadedFunctions };
354
+
317
355
  } catch (error) {
318
- console.log(chalk.yellow(`⚠️ Erro no backup das Edge Functions: ${error.message}`));
356
+ console.log(chalk.yellow(` ⚠️ Erro no backup das Edge Functions: ${error.message}`));
319
357
  return { success: false, functions: [] };
320
358
  }
321
359
  }
@@ -323,31 +361,37 @@ async function backupEdgeFunctions(config, backupDir) {
323
361
  // Backup das Auth Settings via Management API
324
362
  async function backupAuthSettings(config, backupDir) {
325
363
  try {
326
- console.log(chalk.gray(' - Exportando configurações de Auth...'));
364
+ console.log(chalk.gray(' - Exportando configurações de Auth via Management API...'));
327
365
 
328
- // Usar Management API para obter configurações de Auth
329
- const authSettingsPath = path.join(backupDir, 'auth-settings.json');
366
+ // Usar fetch direto para Management API
367
+ const authResponse = await fetch(`https://api.supabase.com/v1/projects/${config.supabase.projectId}/auth/settings`, {
368
+ headers: {
369
+ 'Authorization': `Bearer ${config.supabase.serviceKey}`,
370
+ 'apikey': config.supabase.serviceKey,
371
+ 'Content-Type': 'application/json'
372
+ }
373
+ });
330
374
 
331
- const authSettings = {
375
+ if (!authResponse.ok) {
376
+ console.log(chalk.yellow(` ⚠️ Erro ao obter Auth Settings: ${authResponse.status} ${authResponse.statusText}`));
377
+ return { success: false };
378
+ }
379
+
380
+ const authSettings = await authResponse.json();
381
+
382
+ // Salvar configurações de Auth
383
+ const authSettingsPath = path.join(backupDir, 'auth-settings.json');
384
+ await writeJson(authSettingsPath, {
332
385
  project_id: config.supabase.projectId,
333
386
  timestamp: new Date().toISOString(),
334
- settings: {
335
- // Configurações básicas que podemos obter
336
- site_url: config.supabase.url,
337
- jwt_secret: 'REDACTED', // Não expor secret
338
- smtp_settings: null,
339
- rate_limits: null,
340
- email_templates: null
341
- },
342
- note: 'Configurações completas requerem acesso ao Management API'
343
- };
387
+ settings: authSettings
388
+ });
344
389
 
345
- await writeJson(authSettingsPath, authSettings);
346
- console.log(chalk.green(' ✅ Auth Settings exportadas'));
347
-
390
+ console.log(chalk.green(`✅ Auth Settings exportadas: ${path.basename(authSettingsPath)}`));
348
391
  return { success: true };
392
+
349
393
  } catch (error) {
350
- console.log(chalk.yellow(` ⚠️ Erro ao exportar Auth Settings: ${error.message}`));
394
+ console.log(chalk.yellow(` ⚠️ Erro no backup das Auth Settings: ${error.message}`));
351
395
  return { success: false };
352
396
  }
353
397
  }
@@ -355,30 +399,54 @@ async function backupAuthSettings(config, backupDir) {
355
399
  // Backup do Storage via Supabase API
356
400
  async function backupStorage(config, backupDir) {
357
401
  try {
358
- const supabase = createClient(config.supabase.url, config.supabase.serviceKey);
359
402
  const storageDir = path.join(backupDir, 'storage');
360
403
  await ensureDir(storageDir);
361
404
 
362
- console.log(chalk.gray(' - Listando buckets de Storage...'));
405
+ console.log(chalk.gray(' - Listando buckets de Storage via Management API...'));
363
406
 
364
- // Listar buckets
365
- const { data: buckets, error } = await supabase.storage.listBuckets();
407
+ // Usar fetch direto para Management API
408
+ const storageResponse = await fetch(`https://api.supabase.com/v1/projects/${config.supabase.projectId}/storage/buckets`, {
409
+ headers: {
410
+ 'Authorization': `Bearer ${config.supabase.serviceKey}`,
411
+ 'apikey': config.supabase.serviceKey,
412
+ 'Content-Type': 'application/json'
413
+ }
414
+ });
366
415
 
367
- if (error) {
368
- console.log(chalk.yellow(` ⚠️ Erro ao listar buckets: ${error.message}`));
416
+ if (!storageResponse.ok) {
417
+ console.log(chalk.yellow(` ⚠️ Erro ao listar buckets: ${storageResponse.status} ${storageResponse.statusText}`));
369
418
  return { success: false, buckets: [] };
370
419
  }
371
420
 
372
- const processedBuckets = [];
421
+ const buckets = await storageResponse.json();
422
+
423
+ if (!buckets || buckets.length === 0) {
424
+ console.log(chalk.gray(' - Nenhum bucket encontrado'));
425
+ await writeJson(path.join(storageDir, 'README.md'), {
426
+ message: 'Nenhum bucket de Storage encontrado neste projeto'
427
+ });
428
+ return { success: true, buckets: [] };
429
+ }
430
+
431
+ console.log(chalk.gray(` - Encontrados ${buckets.length} buckets`));
373
432
 
374
433
  for (const bucket of buckets || []) {
375
434
  try {
376
435
  console.log(chalk.gray(` - Processando bucket: ${bucket.name}`));
377
436
 
378
- // Listar objetos do bucket
379
- const { data: objects, error: objectsError } = await supabase.storage
380
- .from(bucket.name)
381
- .list('', { limit: 1000 });
437
+ // Listar objetos do bucket via Management API
438
+ const objectsResponse = await fetch(`https://api.supabase.com/v1/projects/${config.supabase.projectId}/storage/buckets/${bucket.name}/objects`, {
439
+ headers: {
440
+ 'Authorization': `Bearer ${config.supabase.serviceKey}`,
441
+ 'apikey': config.supabase.serviceKey,
442
+ 'Content-Type': 'application/json'
443
+ }
444
+ });
445
+
446
+ let objects = [];
447
+ if (objectsResponse.ok) {
448
+ objects = await objectsResponse.json();
449
+ }
382
450
 
383
451
  const bucketInfo = {
384
452
  id: bucket.id,
@@ -404,7 +472,7 @@ async function backupStorage(config, backupDir) {
404
472
  }
405
473
  }
406
474
 
407
- return { success: true, buckets: processedBuckets };
475
+ console.log(chalk.green(`✅ Storage backupado: ${processedBuckets.length} buckets`));
408
476
  } catch (error) {
409
477
  console.log(chalk.yellow(`⚠️ Erro no backup do Storage: ${error.message}`));
410
478
  return { success: false, buckets: [] };