supabase-stateful 0.1.3 → 0.1.5
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/init.js +3 -2
- package/src/commands/setup.js +71 -40
- package/src/commands/start.js +23 -2
package/package.json
CHANGED
package/src/commands/init.js
CHANGED
|
@@ -71,9 +71,10 @@ export async function init() {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
// Add state file to .gitignore
|
|
74
|
+
// Add state file and backup to .gitignore
|
|
75
75
|
await appendIfMissing('.gitignore', 'supabase/local-state.sql');
|
|
76
|
-
|
|
76
|
+
await appendIfMissing('.gitignore', 'supabase/local-state.sql.backup');
|
|
77
|
+
log.success('Added state files to .gitignore');
|
|
77
78
|
|
|
78
79
|
console.log('');
|
|
79
80
|
log.success('Initialized!');
|
package/src/commands/setup.js
CHANGED
|
@@ -421,26 +421,9 @@ async function addDevScripts(services) {
|
|
|
421
421
|
log.success('Added dev:local script');
|
|
422
422
|
}
|
|
423
423
|
|
|
424
|
-
// Add dev:all:local
|
|
424
|
+
// Add dev:all:local - point to the bash script for graceful shutdown
|
|
425
425
|
if (services.hasConcurrently && !pkg.scripts['dev:all:local']) {
|
|
426
|
-
|
|
427
|
-
let names = 'SUPABASE,NEXT';
|
|
428
|
-
let colors = 'green,cyan';
|
|
429
|
-
|
|
430
|
-
if (services.hasInngest) {
|
|
431
|
-
const inngestCmd = pkg.scripts['dev:inngest'] ? 'dev:inngest' : 'inngest';
|
|
432
|
-
cmds += ` "npm run ${inngestCmd}"`;
|
|
433
|
-
names += ',INNGEST';
|
|
434
|
-
colors += ',magenta';
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
if (services.hasNgrok) {
|
|
438
|
-
cmds += ' "npm run ngrok"';
|
|
439
|
-
names += ',NGROK';
|
|
440
|
-
colors += ',yellow';
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
pkg.scripts['dev:all:local'] = `concurrently ${cmds} --names "${names}" --prefix-colors "${colors}"`;
|
|
426
|
+
pkg.scripts['dev:all:local'] = './scripts/dev-local.sh';
|
|
444
427
|
log.success('Added dev:all:local script');
|
|
445
428
|
}
|
|
446
429
|
|
|
@@ -475,6 +458,11 @@ async function installGitHubWorkflow(workflowType, force = false) {
|
|
|
475
458
|
|
|
476
459
|
log.success(`Created ${targetFile} (${workflowType === 'migrations' ? 'migrations only' : 'migrations + Vercel deploy'})`);
|
|
477
460
|
|
|
461
|
+
// For full workflow, add vercel.json to disable auto-deploy
|
|
462
|
+
if (workflowType === 'full') {
|
|
463
|
+
await addVercelConfig();
|
|
464
|
+
}
|
|
465
|
+
|
|
478
466
|
// Show required secrets
|
|
479
467
|
console.log('');
|
|
480
468
|
log.info('Required GitHub secrets:');
|
|
@@ -485,9 +473,44 @@ async function installGitHubWorkflow(workflowType, force = false) {
|
|
|
485
473
|
console.log(' - VERCEL_TOKEN');
|
|
486
474
|
console.log(' - VERCEL_ORG_ID');
|
|
487
475
|
console.log(' - VERCEL_PROJECT_ID');
|
|
476
|
+
console.log('');
|
|
477
|
+
log.info('Run `npx vercel link` to get VERCEL_ORG_ID and VERCEL_PROJECT_ID');
|
|
488
478
|
}
|
|
489
479
|
}
|
|
490
480
|
|
|
481
|
+
/**
|
|
482
|
+
* Add or update vercel.json to disable automatic deployments
|
|
483
|
+
* This ensures deploys only happen via GitHub Actions (after migrations pass)
|
|
484
|
+
*/
|
|
485
|
+
async function addVercelConfig() {
|
|
486
|
+
const vercelJsonPath = 'vercel.json';
|
|
487
|
+
let config = {};
|
|
488
|
+
|
|
489
|
+
// Read existing config if it exists
|
|
490
|
+
if (await fileExists(vercelJsonPath)) {
|
|
491
|
+
try {
|
|
492
|
+
const content = await fs.readFile(vercelJsonPath, 'utf8');
|
|
493
|
+
config = JSON.parse(content);
|
|
494
|
+
} catch {
|
|
495
|
+
// If we can't parse it, start fresh
|
|
496
|
+
config = {};
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Check if already configured
|
|
501
|
+
if (config.git?.deploymentEnabled === false) {
|
|
502
|
+
log.dim('vercel.json already has deploymentEnabled: false');
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Add git.deploymentEnabled = false
|
|
507
|
+
config.git = config.git || {};
|
|
508
|
+
config.git.deploymentEnabled = false;
|
|
509
|
+
|
|
510
|
+
await fs.writeFile(vercelJsonPath, JSON.stringify(config, null, 2) + '\n');
|
|
511
|
+
log.success('Updated vercel.json to disable auto-deploy (deploys only via GitHub Actions)');
|
|
512
|
+
}
|
|
513
|
+
|
|
491
514
|
/**
|
|
492
515
|
* Generate dev-local.sh script content
|
|
493
516
|
*/
|
|
@@ -512,42 +535,50 @@ function generateDevLocalScript(services) {
|
|
|
512
535
|
|
|
513
536
|
# Local Development Script with Graceful Shutdown
|
|
514
537
|
# Generated by supabase-stateful setup
|
|
515
|
-
# Press Ctrl+C to stop
|
|
538
|
+
# Press Ctrl+C to stop and save Supabase state
|
|
516
539
|
|
|
517
540
|
GREEN='\\033[0;32m'
|
|
518
541
|
YELLOW='\\033[0;33m'
|
|
519
542
|
CYAN='\\033[0;36m'
|
|
520
|
-
RED='\\033[0;31m'
|
|
521
543
|
NC='\\033[0m'
|
|
522
544
|
|
|
523
545
|
echo -e "\${CYAN}Starting local development environment...\${NC}"
|
|
524
546
|
echo ""
|
|
525
547
|
|
|
526
|
-
#
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
${commands.join(' \\\n ')}
|
|
548
|
+
# Cleanup function called on Ctrl+C
|
|
549
|
+
cleanup() {
|
|
550
|
+
echo ""
|
|
551
|
+
echo -e "\${YELLOW}Shutting down gracefully...\${NC}"
|
|
552
|
+
echo -e "\${CYAN}Saving Supabase state...\${NC}"
|
|
532
553
|
|
|
533
|
-
#
|
|
534
|
-
|
|
535
|
-
echo -e "\${CYAN}Save Supabase state and stop? [Y/n]\${NC}"
|
|
536
|
-
echo -e "\${CYAN}(Choose 'n' if you're just restarting the dev server)\${NC}"
|
|
554
|
+
# Kill the concurrently process group
|
|
555
|
+
kill \$DEV_PID 2>/dev/null
|
|
537
556
|
|
|
538
|
-
#
|
|
539
|
-
|
|
540
|
-
echo ""
|
|
557
|
+
# Wait a moment for processes to terminate
|
|
558
|
+
sleep 1
|
|
541
559
|
|
|
542
|
-
|
|
543
|
-
echo -e "\${GREEN}Dev server stopped. Supabase still running.\${NC}"
|
|
544
|
-
echo -e "Run \${YELLOW}npx supabase-stateful stop\${NC} later to save state."
|
|
545
|
-
else
|
|
546
|
-
echo -e "\${CYAN}Saving Supabase state...\${NC}"
|
|
560
|
+
# Save Supabase state
|
|
547
561
|
npx supabase-stateful stop
|
|
562
|
+
|
|
548
563
|
echo ""
|
|
549
564
|
echo -e "\${GREEN}Development environment stopped. State saved.\${NC}"
|
|
550
|
-
|
|
565
|
+
exit 0
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
# Trap Ctrl+C (SIGINT) and call cleanup
|
|
569
|
+
trap cleanup SIGINT SIGTERM
|
|
570
|
+
|
|
571
|
+
# Start the development environment in background
|
|
572
|
+
npx concurrently \\
|
|
573
|
+
--names "${names.join(',')}" \\
|
|
574
|
+
--prefix-colors "${colors.join(',')}" \\
|
|
575
|
+
--kill-others-on-fail \\
|
|
576
|
+
${commands.join(' \\\n ')} &
|
|
577
|
+
|
|
578
|
+
DEV_PID=\$!
|
|
579
|
+
|
|
580
|
+
# Wait for the background process
|
|
581
|
+
wait \$DEV_PID
|
|
551
582
|
`;
|
|
552
583
|
}
|
|
553
584
|
|
package/src/commands/start.js
CHANGED
|
@@ -59,12 +59,33 @@ async function applyMigrations() {
|
|
|
59
59
|
log.info('Checking for pending migrations...');
|
|
60
60
|
|
|
61
61
|
try {
|
|
62
|
-
|
|
62
|
+
// Get migration list with --local flag to check local database status
|
|
63
|
+
const output = execSync('supabase migration list --local', {
|
|
63
64
|
encoding: 'utf8',
|
|
64
65
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
65
66
|
});
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
// Parse table output - pending migrations have version in Local column but empty in Remote column
|
|
69
|
+
// Format: " 20251221044839 | | 2025-12-21 04:48:39"
|
|
70
|
+
// A pending local migration has the version but an empty second column
|
|
71
|
+
const lines = output.split('\n');
|
|
72
|
+
let pendingCount = 0;
|
|
73
|
+
|
|
74
|
+
for (const line of lines) {
|
|
75
|
+
// Skip header lines and empty lines
|
|
76
|
+
if (line.includes('Local') || line.includes('---') || !line.trim()) continue;
|
|
77
|
+
|
|
78
|
+
// Split by | and check columns
|
|
79
|
+
const parts = line.split('|').map(p => p.trim());
|
|
80
|
+
if (parts.length >= 2) {
|
|
81
|
+
const localVersion = parts[0];
|
|
82
|
+
const remoteVersion = parts[1];
|
|
83
|
+
// If there's a local version but no remote version, it's pending
|
|
84
|
+
if (localVersion && /^\d+$/.test(localVersion) && !remoteVersion) {
|
|
85
|
+
pendingCount++;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
68
89
|
|
|
69
90
|
if (pendingCount > 0) {
|
|
70
91
|
log.info(`Found ${pendingCount} pending migration(s)`);
|