@realtimex/email-automator 2.9.4 → 2.9.6
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/api/src/routes/deploy.ts +140 -0
- package/api/src/routes/index.ts +2 -0
- package/api/src/routes/migrate.ts +5 -0
- package/bin/email-automator-deploy.js +25 -50
- package/dist/api/src/routes/deploy.js +121 -0
- package/dist/api/src/routes/index.js +2 -0
- package/dist/api/src/routes/migrate.js +5 -0
- package/dist/assets/{index-CE8vDdPr.js → index-Be1NX_az.js} +15 -15
- package/dist/assets/index-SRvHiNrG.css +1 -0
- package/dist/index.html +2 -2
- package/package.json +3 -3
- package/scripts/deploy-functions.sh +113 -14
- package/scripts/migrate.sh +72 -78
- package/dist/assets/index-DZkAuJEw.css +0 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import { asyncHandler } from '../middleware/errorHandler.js';
|
|
4
|
+
import { validateBody, schemas } from '../middleware/validation.js';
|
|
5
|
+
import { config } from '../config/index.js';
|
|
6
|
+
import { createLogger } from '../utils/logger.js';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
|
|
9
|
+
const router = Router();
|
|
10
|
+
const logger = createLogger('DeployRoutes');
|
|
11
|
+
|
|
12
|
+
// Deploy Edge Functions
|
|
13
|
+
router.post('/',
|
|
14
|
+
validateBody(schemas.migrate), // Reuse migrate schema (same credentials needed)
|
|
15
|
+
asyncHandler(async (req, res) => {
|
|
16
|
+
const { projectRef, dbPassword, accessToken } = req.body;
|
|
17
|
+
|
|
18
|
+
logger.info('Starting Edge Functions deployment', { projectRef });
|
|
19
|
+
|
|
20
|
+
res.setHeader('Content-Type', 'text/plain');
|
|
21
|
+
res.setHeader('Transfer-Encoding', 'chunked');
|
|
22
|
+
|
|
23
|
+
const sendLog = (message: string) => {
|
|
24
|
+
res.write(message + '\n');
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
sendLog('🚀 Starting Edge Functions deployment...');
|
|
29
|
+
sendLog('');
|
|
30
|
+
|
|
31
|
+
const scriptPath = join(config.scriptsDir, 'deploy-functions.sh');
|
|
32
|
+
|
|
33
|
+
const env = {
|
|
34
|
+
...process.env,
|
|
35
|
+
SUPABASE_PROJECT_ID: projectRef,
|
|
36
|
+
SUPABASE_DB_PASSWORD: dbPassword || '',
|
|
37
|
+
SUPABASE_ACCESS_TOKEN: accessToken || '',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
if (accessToken) {
|
|
41
|
+
sendLog('✓ Using Supabase access token for authentication');
|
|
42
|
+
} else {
|
|
43
|
+
sendLog('✓ Using database password for authentication');
|
|
44
|
+
}
|
|
45
|
+
sendLog('');
|
|
46
|
+
|
|
47
|
+
const child = spawn('bash', [scriptPath], {
|
|
48
|
+
env,
|
|
49
|
+
cwd: config.rootDir,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
let hasError = false;
|
|
53
|
+
|
|
54
|
+
child.stdout.on('data', (data) => {
|
|
55
|
+
const lines = data.toString().split('\n');
|
|
56
|
+
lines.forEach((line: string) => {
|
|
57
|
+
if (line.trim()) {
|
|
58
|
+
sendLog(line);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
child.stderr.on('data', (data) => {
|
|
64
|
+
const lines = data.toString().split('\n');
|
|
65
|
+
lines.forEach((line: string) => {
|
|
66
|
+
if (line.trim()) {
|
|
67
|
+
// Check for error patterns
|
|
68
|
+
if (
|
|
69
|
+
line.includes('error') ||
|
|
70
|
+
line.includes('Error') ||
|
|
71
|
+
line.includes('ERROR') ||
|
|
72
|
+
line.includes('failed')
|
|
73
|
+
) {
|
|
74
|
+
sendLog(`❌ ${line}`);
|
|
75
|
+
hasError = true;
|
|
76
|
+
} else {
|
|
77
|
+
sendLog(`⚠️ ${line}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
child.on('close', (code) => {
|
|
84
|
+
sendLog('');
|
|
85
|
+
sendLog('─'.repeat(60));
|
|
86
|
+
|
|
87
|
+
if (code === 0 && !hasError) {
|
|
88
|
+
sendLog('');
|
|
89
|
+
sendLog('✅ Edge Functions deployed successfully!');
|
|
90
|
+
sendLog('RESULT: success');
|
|
91
|
+
sendLog('');
|
|
92
|
+
sendLog('🎉 Your API endpoints are now live.');
|
|
93
|
+
logger.info('Deployment completed successfully', { projectRef });
|
|
94
|
+
} else {
|
|
95
|
+
sendLog('');
|
|
96
|
+
sendLog(`❌ Deployment failed with exit code: ${code}`);
|
|
97
|
+
sendLog('RESULT: failure');
|
|
98
|
+
sendLog('');
|
|
99
|
+
sendLog('💡 Troubleshooting tips:');
|
|
100
|
+
sendLog(' 1. Verify your Supabase credentials are correct');
|
|
101
|
+
sendLog(' 2. Ensure you are logged in: supabase login');
|
|
102
|
+
sendLog(' 3. Check if Supabase CLI is installed (npm install -g supabase)');
|
|
103
|
+
sendLog(' 4. Review the error messages above for specific issues');
|
|
104
|
+
logger.error('Deployment failed', new Error(`Exit code: ${code}`), { projectRef });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
res.end();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
child.on('error', (error) => {
|
|
111
|
+
sendLog('');
|
|
112
|
+
sendLog(`❌ Failed to run deployment: ${error.message}`);
|
|
113
|
+
sendLog('RESULT: failure');
|
|
114
|
+
sendLog('');
|
|
115
|
+
sendLog('💡 This usually means:');
|
|
116
|
+
sendLog(' - Bash is not available on your system');
|
|
117
|
+
sendLog(' - The deployment script is not executable');
|
|
118
|
+
sendLog(' - There are permission issues');
|
|
119
|
+
logger.error('Deployment spawn error', error);
|
|
120
|
+
res.end();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Handle client disconnect
|
|
124
|
+
req.on('close', () => {
|
|
125
|
+
if (!child.killed) {
|
|
126
|
+
child.kill();
|
|
127
|
+
logger.info('Deployment process terminated - client disconnected');
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
} catch (error: any) {
|
|
131
|
+
sendLog('');
|
|
132
|
+
sendLog(`❌ Server error: ${error.message}`);
|
|
133
|
+
sendLog('RESULT: failure');
|
|
134
|
+
logger.error('Deployment error', error);
|
|
135
|
+
res.end();
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
export default router;
|
package/api/src/routes/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import rulesRoutes from './rules.js';
|
|
|
7
7
|
import settingsRoutes from './settings.js';
|
|
8
8
|
import emailsRoutes from './emails.js';
|
|
9
9
|
import migrateRoutes from './migrate.js';
|
|
10
|
+
import deployRoutes from './deploy.js';
|
|
10
11
|
|
|
11
12
|
const router = Router();
|
|
12
13
|
|
|
@@ -18,5 +19,6 @@ router.use('/rules', rulesRoutes);
|
|
|
18
19
|
router.use('/settings', settingsRoutes);
|
|
19
20
|
router.use('/emails', emailsRoutes);
|
|
20
21
|
router.use('/migrate', migrateRoutes);
|
|
22
|
+
router.use('/deploy', deployRoutes);
|
|
21
23
|
|
|
22
24
|
export default router;
|
|
@@ -34,6 +34,7 @@ router.post('/',
|
|
|
34
34
|
SUPABASE_PROJECT_ID: projectRef,
|
|
35
35
|
SUPABASE_DB_PASSWORD: dbPassword || '',
|
|
36
36
|
SUPABASE_ACCESS_TOKEN: accessToken || '',
|
|
37
|
+
SKIP_FUNCTIONS: '1',
|
|
37
38
|
};
|
|
38
39
|
|
|
39
40
|
const child = spawn('bash', [scriptPath], {
|
|
@@ -52,9 +53,11 @@ router.post('/',
|
|
|
52
53
|
child.on('close', (code) => {
|
|
53
54
|
if (code === 0) {
|
|
54
55
|
sendLog('✅ Migration successful!');
|
|
56
|
+
sendLog('RESULT: success');
|
|
55
57
|
logger.info('Migration completed successfully', { projectRef });
|
|
56
58
|
} else {
|
|
57
59
|
sendLog(`❌ Migration failed with code ${code}`);
|
|
60
|
+
sendLog('RESULT: failure');
|
|
58
61
|
logger.error('Migration failed', new Error(`Exit code: ${code}`), { projectRef });
|
|
59
62
|
}
|
|
60
63
|
res.end();
|
|
@@ -62,11 +65,13 @@ router.post('/',
|
|
|
62
65
|
|
|
63
66
|
child.on('error', (error) => {
|
|
64
67
|
sendLog(`❌ Failed to run migration: ${error.message}`);
|
|
68
|
+
sendLog('RESULT: failure');
|
|
65
69
|
logger.error('Migration spawn error', error);
|
|
66
70
|
res.end();
|
|
67
71
|
});
|
|
68
72
|
} catch (error: any) {
|
|
69
73
|
sendLog(`❌ Server error: ${error.message}`);
|
|
74
|
+
sendLog('RESULT: failure');
|
|
70
75
|
logger.error('Migration error', error);
|
|
71
76
|
res.end();
|
|
72
77
|
}
|
|
@@ -17,63 +17,38 @@ console.log('🚀 Email Automator - Edge Functions Deployment');
|
|
|
17
17
|
console.log('===============================================');
|
|
18
18
|
console.log('');
|
|
19
19
|
|
|
20
|
-
//
|
|
21
|
-
const
|
|
20
|
+
// Run deployment script (handles CLI detection internally)
|
|
21
|
+
const deployScript = join(__dirname, '..', 'scripts', 'deploy-functions.sh');
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
console.error('❌
|
|
25
|
-
console.error('');
|
|
26
|
-
console.error('Install it with:');
|
|
27
|
-
console.error(' npm install -g supabase');
|
|
28
|
-
console.error('');
|
|
29
|
-
console.error('Or via Homebrew (macOS):');
|
|
30
|
-
console.error(' brew install supabase/tap/supabase');
|
|
31
|
-
console.error('');
|
|
23
|
+
if (!existsSync(deployScript)) {
|
|
24
|
+
console.error('❌ Deployment script not found:', deployScript);
|
|
32
25
|
process.exit(1);
|
|
33
|
-
}
|
|
26
|
+
}
|
|
34
27
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
console.error('❌ Supabase CLI check failed');
|
|
38
|
-
process.exit(1);
|
|
39
|
-
}
|
|
28
|
+
console.log('📦 Deploying Edge Functions...');
|
|
29
|
+
console.log('');
|
|
40
30
|
|
|
41
|
-
|
|
42
|
-
|
|
31
|
+
const deploy = spawn('bash', [deployScript], {
|
|
32
|
+
stdio: 'inherit',
|
|
33
|
+
cwd: join(__dirname, '..'),
|
|
34
|
+
});
|
|
43
35
|
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
deploy.on('error', (error) => {
|
|
37
|
+
console.error('❌ Deployment failed:', error.message);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
});
|
|
46
40
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
deploy.on('close', (code) => {
|
|
42
|
+
if (code !== 0) {
|
|
43
|
+
console.error('\n❌ Deployment failed with code', code);
|
|
44
|
+
process.exit(code);
|
|
50
45
|
}
|
|
51
46
|
|
|
52
|
-
console.log('📦 Deploying Edge Functions...');
|
|
53
47
|
console.log('');
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
deploy.on('error', (error) => {
|
|
61
|
-
console.error('❌ Deployment failed:', error.message);
|
|
62
|
-
process.exit(1);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
deploy.on('close', (code) => {
|
|
66
|
-
if (code !== 0) {
|
|
67
|
-
console.error('\n❌ Deployment failed with code', code);
|
|
68
|
-
process.exit(code);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
console.log('');
|
|
72
|
-
console.log('✅ Deployment complete!');
|
|
73
|
-
console.log('');
|
|
74
|
-
console.log('🔐 Don\'t forget to configure secrets in Supabase Dashboard:');
|
|
75
|
-
console.log(' Settings → Edge Functions → Add secrets');
|
|
76
|
-
console.log('');
|
|
77
|
-
process.exit(0);
|
|
78
|
-
});
|
|
48
|
+
console.log('✅ Deployment complete!');
|
|
49
|
+
console.log('');
|
|
50
|
+
console.log('🔐 Don\'t forget to configure secrets in Supabase Dashboard:');
|
|
51
|
+
console.log(' Settings → Edge Functions → Add secrets');
|
|
52
|
+
console.log('');
|
|
53
|
+
process.exit(0);
|
|
79
54
|
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import { asyncHandler } from '../middleware/errorHandler.js';
|
|
4
|
+
import { validateBody, schemas } from '../middleware/validation.js';
|
|
5
|
+
import { config } from '../config/index.js';
|
|
6
|
+
import { createLogger } from '../utils/logger.js';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
const router = Router();
|
|
9
|
+
const logger = createLogger('DeployRoutes');
|
|
10
|
+
// Deploy Edge Functions
|
|
11
|
+
router.post('/', validateBody(schemas.migrate), // Reuse migrate schema (same credentials needed)
|
|
12
|
+
asyncHandler(async (req, res) => {
|
|
13
|
+
const { projectRef, dbPassword, accessToken } = req.body;
|
|
14
|
+
logger.info('Starting Edge Functions deployment', { projectRef });
|
|
15
|
+
res.setHeader('Content-Type', 'text/plain');
|
|
16
|
+
res.setHeader('Transfer-Encoding', 'chunked');
|
|
17
|
+
const sendLog = (message) => {
|
|
18
|
+
res.write(message + '\n');
|
|
19
|
+
};
|
|
20
|
+
try {
|
|
21
|
+
sendLog('🚀 Starting Edge Functions deployment...');
|
|
22
|
+
sendLog('');
|
|
23
|
+
const scriptPath = join(config.scriptsDir, 'deploy-functions.sh');
|
|
24
|
+
const env = {
|
|
25
|
+
...process.env,
|
|
26
|
+
SUPABASE_PROJECT_ID: projectRef,
|
|
27
|
+
SUPABASE_DB_PASSWORD: dbPassword || '',
|
|
28
|
+
SUPABASE_ACCESS_TOKEN: accessToken || '',
|
|
29
|
+
};
|
|
30
|
+
if (accessToken) {
|
|
31
|
+
sendLog('✓ Using Supabase access token for authentication');
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
sendLog('✓ Using database password for authentication');
|
|
35
|
+
}
|
|
36
|
+
sendLog('');
|
|
37
|
+
const child = spawn('bash', [scriptPath], {
|
|
38
|
+
env,
|
|
39
|
+
cwd: config.rootDir,
|
|
40
|
+
});
|
|
41
|
+
let hasError = false;
|
|
42
|
+
child.stdout.on('data', (data) => {
|
|
43
|
+
const lines = data.toString().split('\n');
|
|
44
|
+
lines.forEach((line) => {
|
|
45
|
+
if (line.trim()) {
|
|
46
|
+
sendLog(line);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
child.stderr.on('data', (data) => {
|
|
51
|
+
const lines = data.toString().split('\n');
|
|
52
|
+
lines.forEach((line) => {
|
|
53
|
+
if (line.trim()) {
|
|
54
|
+
// Check for error patterns
|
|
55
|
+
if (line.includes('error') ||
|
|
56
|
+
line.includes('Error') ||
|
|
57
|
+
line.includes('ERROR') ||
|
|
58
|
+
line.includes('failed')) {
|
|
59
|
+
sendLog(`❌ ${line}`);
|
|
60
|
+
hasError = true;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
sendLog(`⚠️ ${line}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
child.on('close', (code) => {
|
|
69
|
+
sendLog('');
|
|
70
|
+
sendLog('─'.repeat(60));
|
|
71
|
+
if (code === 0 && !hasError) {
|
|
72
|
+
sendLog('');
|
|
73
|
+
sendLog('✅ Edge Functions deployed successfully!');
|
|
74
|
+
sendLog('RESULT: success');
|
|
75
|
+
sendLog('');
|
|
76
|
+
sendLog('🎉 Your API endpoints are now live.');
|
|
77
|
+
logger.info('Deployment completed successfully', { projectRef });
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
sendLog('');
|
|
81
|
+
sendLog(`❌ Deployment failed with exit code: ${code}`);
|
|
82
|
+
sendLog('RESULT: failure');
|
|
83
|
+
sendLog('');
|
|
84
|
+
sendLog('💡 Troubleshooting tips:');
|
|
85
|
+
sendLog(' 1. Verify your Supabase credentials are correct');
|
|
86
|
+
sendLog(' 2. Ensure you are logged in: supabase login');
|
|
87
|
+
sendLog(' 3. Check if Supabase CLI is installed (npm install -g supabase)');
|
|
88
|
+
sendLog(' 4. Review the error messages above for specific issues');
|
|
89
|
+
logger.error('Deployment failed', new Error(`Exit code: ${code}`), { projectRef });
|
|
90
|
+
}
|
|
91
|
+
res.end();
|
|
92
|
+
});
|
|
93
|
+
child.on('error', (error) => {
|
|
94
|
+
sendLog('');
|
|
95
|
+
sendLog(`❌ Failed to run deployment: ${error.message}`);
|
|
96
|
+
sendLog('RESULT: failure');
|
|
97
|
+
sendLog('');
|
|
98
|
+
sendLog('💡 This usually means:');
|
|
99
|
+
sendLog(' - Bash is not available on your system');
|
|
100
|
+
sendLog(' - The deployment script is not executable');
|
|
101
|
+
sendLog(' - There are permission issues');
|
|
102
|
+
logger.error('Deployment spawn error', error);
|
|
103
|
+
res.end();
|
|
104
|
+
});
|
|
105
|
+
// Handle client disconnect
|
|
106
|
+
req.on('close', () => {
|
|
107
|
+
if (!child.killed) {
|
|
108
|
+
child.kill();
|
|
109
|
+
logger.info('Deployment process terminated - client disconnected');
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
sendLog('');
|
|
115
|
+
sendLog(`❌ Server error: ${error.message}`);
|
|
116
|
+
sendLog('RESULT: failure');
|
|
117
|
+
logger.error('Deployment error', error);
|
|
118
|
+
res.end();
|
|
119
|
+
}
|
|
120
|
+
}));
|
|
121
|
+
export default router;
|
|
@@ -7,6 +7,7 @@ import rulesRoutes from './rules.js';
|
|
|
7
7
|
import settingsRoutes from './settings.js';
|
|
8
8
|
import emailsRoutes from './emails.js';
|
|
9
9
|
import migrateRoutes from './migrate.js';
|
|
10
|
+
import deployRoutes from './deploy.js';
|
|
10
11
|
const router = Router();
|
|
11
12
|
router.use('/health', healthRoutes);
|
|
12
13
|
router.use('/auth', authRoutes);
|
|
@@ -16,4 +17,5 @@ router.use('/rules', rulesRoutes);
|
|
|
16
17
|
router.use('/settings', settingsRoutes);
|
|
17
18
|
router.use('/emails', emailsRoutes);
|
|
18
19
|
router.use('/migrate', migrateRoutes);
|
|
20
|
+
router.use('/deploy', deployRoutes);
|
|
19
21
|
export default router;
|
|
@@ -24,6 +24,7 @@ router.post('/', validateBody(schemas.migrate), asyncHandler(async (req, res) =>
|
|
|
24
24
|
SUPABASE_PROJECT_ID: projectRef,
|
|
25
25
|
SUPABASE_DB_PASSWORD: dbPassword || '',
|
|
26
26
|
SUPABASE_ACCESS_TOKEN: accessToken || '',
|
|
27
|
+
SKIP_FUNCTIONS: '1',
|
|
27
28
|
};
|
|
28
29
|
const child = spawn('bash', [scriptPath], {
|
|
29
30
|
env,
|
|
@@ -38,22 +39,26 @@ router.post('/', validateBody(schemas.migrate), asyncHandler(async (req, res) =>
|
|
|
38
39
|
child.on('close', (code) => {
|
|
39
40
|
if (code === 0) {
|
|
40
41
|
sendLog('✅ Migration successful!');
|
|
42
|
+
sendLog('RESULT: success');
|
|
41
43
|
logger.info('Migration completed successfully', { projectRef });
|
|
42
44
|
}
|
|
43
45
|
else {
|
|
44
46
|
sendLog(`❌ Migration failed with code ${code}`);
|
|
47
|
+
sendLog('RESULT: failure');
|
|
45
48
|
logger.error('Migration failed', new Error(`Exit code: ${code}`), { projectRef });
|
|
46
49
|
}
|
|
47
50
|
res.end();
|
|
48
51
|
});
|
|
49
52
|
child.on('error', (error) => {
|
|
50
53
|
sendLog(`❌ Failed to run migration: ${error.message}`);
|
|
54
|
+
sendLog('RESULT: failure');
|
|
51
55
|
logger.error('Migration spawn error', error);
|
|
52
56
|
res.end();
|
|
53
57
|
});
|
|
54
58
|
}
|
|
55
59
|
catch (error) {
|
|
56
60
|
sendLog(`❌ Server error: ${error.message}`);
|
|
61
|
+
sendLog('RESULT: failure');
|
|
57
62
|
logger.error('Migration error', error);
|
|
58
63
|
res.end();
|
|
59
64
|
}
|