@agenticmail/enterprise 0.5.187 → 0.5.188
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.
|
@@ -158,6 +158,7 @@ export function DomainStatusPage() {
|
|
|
158
158
|
);
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
var isLocalhost = /^(localhost|127\.0\.0\.1|0\.0\.0\.0)(:\d+)?$/.test(actualHost);
|
|
161
162
|
var hasDomain = data && data.domain;
|
|
162
163
|
var isDomainVerified = hasDomain && data.status === 'verified';
|
|
163
164
|
var isDomainPending = hasDomain && data.status === 'pending_dns';
|
|
@@ -175,6 +176,11 @@ export function DomainStatusPage() {
|
|
|
175
176
|
h('p', { style: { color: 'var(--text-muted)', fontSize: 13 } }, 'Manage the domain and URL for your AgenticMail Enterprise deployment')
|
|
176
177
|
),
|
|
177
178
|
|
|
179
|
+
// ═══════════════════════════════════════════════
|
|
180
|
+
// DEPLOY TO PRODUCTION (shown when on localhost)
|
|
181
|
+
// ═══════════════════════════════════════════════
|
|
182
|
+
isLocalhost && DeployToProduction({ toast: toast }),
|
|
183
|
+
|
|
178
184
|
// ═══════════════════════════════════════════════
|
|
179
185
|
// SECTION 1: Current Deployment
|
|
180
186
|
// ═══════════════════════════════════════════════
|
|
@@ -501,3 +507,187 @@ function cliRow(label, cmd) {
|
|
|
501
507
|
h('code', { style: { fontSize: 12, color: 'var(--accent)' } }, cmd)
|
|
502
508
|
);
|
|
503
509
|
}
|
|
510
|
+
|
|
511
|
+
// ─── Deploy to Production Component ─────────────────────
|
|
512
|
+
|
|
513
|
+
function DeployToProduction({ toast }) {
|
|
514
|
+
var [expanded, setExpanded] = useState(false);
|
|
515
|
+
var [selectedMethod, setSelectedMethod] = useState(null);
|
|
516
|
+
|
|
517
|
+
var card = { padding: 24, background: 'linear-gradient(135deg, rgba(99,102,241,0.08), rgba(139,92,246,0.08))', borderRadius: 'var(--radius-lg)', border: '1px solid rgba(99,102,241,0.25)', marginBottom: 20 };
|
|
518
|
+
var methodCard = function(id, icon, title, subtitle, difficulty, recommended) {
|
|
519
|
+
var isActive = selectedMethod === id;
|
|
520
|
+
return h('div', {
|
|
521
|
+
onClick: function() { setSelectedMethod(isActive ? null : id); },
|
|
522
|
+
style: {
|
|
523
|
+
padding: 16, borderRadius: 'var(--radius)', cursor: 'pointer', transition: 'all 0.15s',
|
|
524
|
+
background: isActive ? 'rgba(99,102,241,0.12)' : 'var(--bg-secondary)',
|
|
525
|
+
border: '1px solid ' + (isActive ? 'var(--accent)' : 'var(--border)'),
|
|
526
|
+
position: 'relative',
|
|
527
|
+
},
|
|
528
|
+
},
|
|
529
|
+
recommended && h('span', { style: { position: 'absolute', top: -8, right: 12, fontSize: 9, fontWeight: 700, padding: '2px 8px', borderRadius: 99, background: 'var(--accent)', color: '#fff', textTransform: 'uppercase', letterSpacing: '0.05em' } }, 'Recommended'),
|
|
530
|
+
h('div', { style: { display: 'flex', alignItems: 'center', gap: 10, marginBottom: 6 } },
|
|
531
|
+
h('span', { style: { fontSize: 20 } }, icon),
|
|
532
|
+
h('span', { style: { fontWeight: 600, fontSize: 14 } }, title),
|
|
533
|
+
),
|
|
534
|
+
h('div', { style: { fontSize: 12, color: 'var(--text-muted)', marginBottom: 6, lineHeight: 1.5 } }, subtitle),
|
|
535
|
+
h('div', { style: { fontSize: 10, fontWeight: 600, color: difficulty === 'Easy' ? 'var(--success)' : difficulty === 'Medium' ? 'var(--warning)' : 'var(--text-muted)' } }, difficulty),
|
|
536
|
+
);
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
var copyCmd = function(cmd) {
|
|
540
|
+
navigator.clipboard.writeText(cmd);
|
|
541
|
+
toast('Command copied!', 'success');
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
var cmdBlock = function(cmd, label) {
|
|
545
|
+
return h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '8px 12px', background: '#0d1117', borderRadius: 6, marginBottom: 6, fontFamily: 'var(--font-mono)', fontSize: 12, color: '#e6edf3', border: '1px solid rgba(255,255,255,0.08)' } },
|
|
546
|
+
h('span', { style: { flex: 1, wordBreak: 'break-all' } }, cmd),
|
|
547
|
+
h('button', { onClick: function() { copyCmd(cmd); }, style: { background: 'none', border: 'none', color: 'var(--text-muted)', cursor: 'pointer', fontSize: 11, padding: '2px 6px', borderRadius: 4, flexShrink: 0 }, title: 'Copy' }, 'Copy'),
|
|
548
|
+
);
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
var stepItem = function(num, text) {
|
|
552
|
+
return h('div', { style: { display: 'flex', gap: 10, marginBottom: 8, fontSize: 13, lineHeight: 1.6 } },
|
|
553
|
+
h('span', { style: { width: 22, height: 22, borderRadius: '50%', background: 'var(--accent-soft)', color: 'var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 11, fontWeight: 700, flexShrink: 0, marginTop: 1 } }, num),
|
|
554
|
+
h('div', null, text),
|
|
555
|
+
);
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
return h('div', { style: card },
|
|
559
|
+
h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', cursor: 'pointer' }, onClick: function() { setExpanded(!expanded); } },
|
|
560
|
+
h('div', null,
|
|
561
|
+
h('div', { style: { fontSize: 16, fontWeight: 700, marginBottom: 4, display: 'flex', alignItems: 'center', gap: 8 } },
|
|
562
|
+
'\uD83D\uDE80 Deploy to Production',
|
|
563
|
+
h('span', { style: { fontSize: 10, padding: '2px 8px', borderRadius: 99, background: 'rgba(245,158,11,0.15)', color: 'var(--warning)', fontWeight: 600 } }, 'LOCALHOST'),
|
|
564
|
+
),
|
|
565
|
+
h('div', { style: { fontSize: 13, color: 'var(--text-muted)' } }, 'You\'re running locally. Deploy to a domain so your agents can be reached from anywhere.'),
|
|
566
|
+
),
|
|
567
|
+
h('span', { style: { fontSize: 18, color: 'var(--text-muted)', transform: expanded ? 'rotate(180deg)' : 'none', transition: 'transform 0.2s' } }, '\u25BC'),
|
|
568
|
+
),
|
|
569
|
+
|
|
570
|
+
expanded && h('div', { style: { marginTop: 20 } },
|
|
571
|
+
// Method cards
|
|
572
|
+
h('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))', gap: 12, marginBottom: 20 } },
|
|
573
|
+
methodCard('vps', '\uD83D\uDDA5\uFE0F', 'VPS / Server', 'Deploy to any Linux server (DigitalOcean, Hetzner, AWS, etc.)', 'Easy', true),
|
|
574
|
+
methodCard('docker', '\uD83D\uDC33', 'Docker', 'Run as a Docker container on any host', 'Medium'),
|
|
575
|
+
methodCard('railway', '\uD83D\uDE82', 'Railway', 'One-click deploy to Railway.app', 'Easy'),
|
|
576
|
+
methodCard('fly', '\u2708\uFE0F', 'Fly.io', 'Deploy to Fly.io edge network', 'Medium'),
|
|
577
|
+
),
|
|
578
|
+
|
|
579
|
+
// ─── VPS Instructions ─────────────────────────
|
|
580
|
+
selectedMethod === 'vps' && h('div', { style: { padding: 20, background: 'var(--bg-secondary)', borderRadius: 'var(--radius)', border: '1px solid var(--border)' } },
|
|
581
|
+
h('h3', { style: { fontSize: 15, fontWeight: 700, marginBottom: 16 } }, 'Deploy to a VPS'),
|
|
582
|
+
h('p', { style: { fontSize: 13, color: 'var(--text-muted)', marginBottom: 16, lineHeight: 1.6 } },
|
|
583
|
+
'Works with any Linux server: DigitalOcean ($6/mo), Hetzner ($4/mo), Linode, AWS EC2, etc. Minimum: 1 CPU, 1GB RAM.',
|
|
584
|
+
),
|
|
585
|
+
|
|
586
|
+
stepItem('1', h(Fragment, null, h('strong', null, 'Get a server'), ' — Any Ubuntu/Debian VPS. Point your domain\'s DNS to the server\'s IP address.')),
|
|
587
|
+
|
|
588
|
+
stepItem('2', h(Fragment, null, h('strong', null, 'SSH in and install Node.js + PM2:'),
|
|
589
|
+
cmdBlock('curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs'),
|
|
590
|
+
cmdBlock('sudo npm install -g pm2'),
|
|
591
|
+
)),
|
|
592
|
+
|
|
593
|
+
stepItem('3', h(Fragment, null, h('strong', null, 'Install AgenticMail Enterprise:'),
|
|
594
|
+
cmdBlock('sudo npm install -g @agenticmail/enterprise'),
|
|
595
|
+
)),
|
|
596
|
+
|
|
597
|
+
stepItem('4', h(Fragment, null, h('strong', null, 'Run the setup wizard:'),
|
|
598
|
+
cmdBlock('agenticmail-enterprise setup'),
|
|
599
|
+
h('span', { style: { fontSize: 12, color: 'var(--text-muted)' } }, 'This will walk you through Google Workspace, database, and domain configuration.'),
|
|
600
|
+
)),
|
|
601
|
+
|
|
602
|
+
stepItem('5', h(Fragment, null, h('strong', null, 'Start with PM2 (auto-restart on crash):'),
|
|
603
|
+
cmdBlock('pm2 start agenticmail-enterprise -- start'),
|
|
604
|
+
cmdBlock('pm2 save && pm2 startup'),
|
|
605
|
+
)),
|
|
606
|
+
|
|
607
|
+
stepItem('6', h(Fragment, null, h('strong', null, 'Set up HTTPS with Caddy (automatic SSL):'),
|
|
608
|
+
cmdBlock('sudo apt install -y caddy'),
|
|
609
|
+
cmdBlock('echo "yourdomain.com { reverse_proxy localhost:3200 }" | sudo tee /etc/caddy/Caddyfile'),
|
|
610
|
+
cmdBlock('sudo systemctl restart caddy'),
|
|
611
|
+
h('span', { style: { fontSize: 12, color: 'var(--text-muted)' } }, 'Replace yourdomain.com with your actual domain. Caddy handles SSL automatically.'),
|
|
612
|
+
)),
|
|
613
|
+
|
|
614
|
+
h('div', { style: { marginTop: 16, padding: '12px 16px', background: 'var(--success-soft)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--success)', lineHeight: 1.6 } },
|
|
615
|
+
'\u2705 Done! Your dashboard will be live at ', h('strong', null, 'https://yourdomain.com'), '. All your agents, settings, and data will be on your own server.'
|
|
616
|
+
),
|
|
617
|
+
),
|
|
618
|
+
|
|
619
|
+
// ─── Docker Instructions ──────────────────────
|
|
620
|
+
selectedMethod === 'docker' && h('div', { style: { padding: 20, background: 'var(--bg-secondary)', borderRadius: 'var(--radius)', border: '1px solid var(--border)' } },
|
|
621
|
+
h('h3', { style: { fontSize: 15, fontWeight: 700, marginBottom: 16 } }, 'Deploy with Docker'),
|
|
622
|
+
|
|
623
|
+
stepItem('1', h(Fragment, null, h('strong', null, 'Create docker-compose.yml:'),
|
|
624
|
+
cmdBlock('mkdir agenticmail && cd agenticmail'),
|
|
625
|
+
h('div', { style: { padding: '10px 12px', background: '#0d1117', borderRadius: 6, marginBottom: 6, fontFamily: 'var(--font-mono)', fontSize: 11, color: '#e6edf3', whiteSpace: 'pre', overflowX: 'auto', border: '1px solid rgba(255,255,255,0.08)' } },
|
|
626
|
+
'version: "3.8"\nservices:\n enterprise:\n image: node:22\n working_dir: /app\n command: npx @agenticmail/enterprise start\n ports:\n - "3200:3200"\n volumes:\n - ./data:/app/data\n restart: unless-stopped'
|
|
627
|
+
),
|
|
628
|
+
)),
|
|
629
|
+
|
|
630
|
+
stepItem('2', h(Fragment, null, h('strong', null, 'Start:'),
|
|
631
|
+
cmdBlock('docker compose up -d'),
|
|
632
|
+
)),
|
|
633
|
+
|
|
634
|
+
stepItem('3', h(Fragment, null, h('strong', null, 'Add a reverse proxy (Caddy/Nginx) for HTTPS, same as VPS step 6.'))),
|
|
635
|
+
),
|
|
636
|
+
|
|
637
|
+
// ─── Railway Instructions ─────────────────────
|
|
638
|
+
selectedMethod === 'railway' && h('div', { style: { padding: 20, background: 'var(--bg-secondary)', borderRadius: 'var(--radius)', border: '1px solid var(--border)' } },
|
|
639
|
+
h('h3', { style: { fontSize: 15, fontWeight: 700, marginBottom: 16 } }, 'Deploy to Railway'),
|
|
640
|
+
|
|
641
|
+
stepItem('1', h(Fragment, null,
|
|
642
|
+
h('strong', null, 'Click to deploy:'),
|
|
643
|
+
h('div', { style: { marginTop: 8 } },
|
|
644
|
+
h('a', { href: 'https://railway.app/new', target: '_blank', style: { display: 'inline-flex', alignItems: 'center', gap: 8, padding: '8px 16px', background: 'var(--accent)', color: '#fff', borderRadius: 6, textDecoration: 'none', fontSize: 13, fontWeight: 600 } }, '\uD83D\uDE82 Open Railway'),
|
|
645
|
+
),
|
|
646
|
+
)),
|
|
647
|
+
stepItem('2', h(Fragment, null, h('strong', null, 'Create a new project'), ' and select "Deploy from GitHub" or "Empty Project".')),
|
|
648
|
+
stepItem('3', h(Fragment, null, h('strong', null, 'Add a service'), ' with start command:',
|
|
649
|
+
cmdBlock('npx @agenticmail/enterprise start'),
|
|
650
|
+
)),
|
|
651
|
+
stepItem('4', h(Fragment, null, h('strong', null, 'Set environment variables'), ' (DATABASE_URL, MASTER_KEY, etc.) in the Railway dashboard.')),
|
|
652
|
+
stepItem('5', h(Fragment, null, h('strong', null, 'Generate a domain'), ' — Railway gives you a free URL, or add your custom domain.')),
|
|
653
|
+
),
|
|
654
|
+
|
|
655
|
+
// ─── Fly.io Instructions ──────────────────────
|
|
656
|
+
selectedMethod === 'fly' && h('div', { style: { padding: 20, background: 'var(--bg-secondary)', borderRadius: 'var(--radius)', border: '1px solid var(--border)' } },
|
|
657
|
+
h('h3', { style: { fontSize: 15, fontWeight: 700, marginBottom: 16 } }, 'Deploy to Fly.io'),
|
|
658
|
+
|
|
659
|
+
stepItem('1', h(Fragment, null, h('strong', null, 'Install Fly CLI:'),
|
|
660
|
+
cmdBlock('curl -L https://fly.io/install.sh | sh'),
|
|
661
|
+
cmdBlock('fly auth login'),
|
|
662
|
+
)),
|
|
663
|
+
stepItem('2', h(Fragment, null, h('strong', null, 'Create fly.toml:'),
|
|
664
|
+
h('div', { style: { padding: '10px 12px', background: '#0d1117', borderRadius: 6, marginBottom: 6, fontFamily: 'var(--font-mono)', fontSize: 11, color: '#e6edf3', whiteSpace: 'pre', overflowX: 'auto', border: '1px solid rgba(255,255,255,0.08)' } },
|
|
665
|
+
'app = "my-agenticmail"\n\n[build]\n builder = "heroku/buildpacks:22"\n\n[env]\n PORT = "3200"\n\n[[services]]\n internal_port = 3200\n protocol = "tcp"\n [services.concurrency]\n hard_limit = 250\n soft_limit = 200\n [[services.ports]]\n port = 443\n handlers = ["tls", "http"]'
|
|
666
|
+
),
|
|
667
|
+
)),
|
|
668
|
+
stepItem('3', h(Fragment, null, h('strong', null, 'Set secrets and deploy:'),
|
|
669
|
+
cmdBlock('fly secrets set MASTER_KEY=your-key DATABASE_URL=your-db-url'),
|
|
670
|
+
cmdBlock('fly deploy'),
|
|
671
|
+
)),
|
|
672
|
+
stepItem('4', h(Fragment, null, h('strong', null, 'Add custom domain:'),
|
|
673
|
+
cmdBlock('fly certs create yourdomain.com'),
|
|
674
|
+
)),
|
|
675
|
+
),
|
|
676
|
+
|
|
677
|
+
// ─── Export / Migrate Data ────────────────────
|
|
678
|
+
h('div', { style: { marginTop: 16, padding: '14px 16px', background: 'var(--bg-tertiary)', borderRadius: 'var(--radius)', border: '1px solid var(--border)' } },
|
|
679
|
+
h('div', { style: { fontSize: 13, fontWeight: 600, marginBottom: 6 } }, 'Migrating from Localhost?'),
|
|
680
|
+
h('div', { style: { fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.6 } },
|
|
681
|
+
'Your local data (SQLite) lives in ', h('code', { style: { fontSize: 11, color: 'var(--accent)' } }, './data/'),
|
|
682
|
+
'. To migrate to a production Postgres database:',
|
|
683
|
+
),
|
|
684
|
+
h('ol', { style: { fontSize: 12, color: 'var(--text-secondary)', lineHeight: 1.8, paddingLeft: 20, marginTop: 8, marginBottom: 0 } },
|
|
685
|
+
h('li', null, 'Set up a Postgres database (Neon, Supabase, Railway, or self-hosted)'),
|
|
686
|
+
h('li', null, 'Set ', h('code', { style: { fontSize: 11, color: 'var(--accent)' } }, 'DATABASE_URL'), ' environment variable to your Postgres connection string'),
|
|
687
|
+
h('li', null, 'Run ', h('code', { style: { fontSize: 11, color: 'var(--accent)' } }, 'agenticmail-enterprise setup'), ' — tables are auto-created on first run'),
|
|
688
|
+
h('li', null, 'Re-configure your Google Workspace credentials in the setup wizard'),
|
|
689
|
+
),
|
|
690
|
+
),
|
|
691
|
+
),
|
|
692
|
+
);
|
|
693
|
+
}
|
package/package.json
CHANGED
|
@@ -158,6 +158,7 @@ export function DomainStatusPage() {
|
|
|
158
158
|
);
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
var isLocalhost = /^(localhost|127\.0\.0\.1|0\.0\.0\.0)(:\d+)?$/.test(actualHost);
|
|
161
162
|
var hasDomain = data && data.domain;
|
|
162
163
|
var isDomainVerified = hasDomain && data.status === 'verified';
|
|
163
164
|
var isDomainPending = hasDomain && data.status === 'pending_dns';
|
|
@@ -175,6 +176,11 @@ export function DomainStatusPage() {
|
|
|
175
176
|
h('p', { style: { color: 'var(--text-muted)', fontSize: 13 } }, 'Manage the domain and URL for your AgenticMail Enterprise deployment')
|
|
176
177
|
),
|
|
177
178
|
|
|
179
|
+
// ═══════════════════════════════════════════════
|
|
180
|
+
// DEPLOY TO PRODUCTION (shown when on localhost)
|
|
181
|
+
// ═══════════════════════════════════════════════
|
|
182
|
+
isLocalhost && DeployToProduction({ toast: toast }),
|
|
183
|
+
|
|
178
184
|
// ═══════════════════════════════════════════════
|
|
179
185
|
// SECTION 1: Current Deployment
|
|
180
186
|
// ═══════════════════════════════════════════════
|
|
@@ -501,3 +507,187 @@ function cliRow(label, cmd) {
|
|
|
501
507
|
h('code', { style: { fontSize: 12, color: 'var(--accent)' } }, cmd)
|
|
502
508
|
);
|
|
503
509
|
}
|
|
510
|
+
|
|
511
|
+
// ─── Deploy to Production Component ─────────────────────
|
|
512
|
+
|
|
513
|
+
function DeployToProduction({ toast }) {
|
|
514
|
+
var [expanded, setExpanded] = useState(false);
|
|
515
|
+
var [selectedMethod, setSelectedMethod] = useState(null);
|
|
516
|
+
|
|
517
|
+
var card = { padding: 24, background: 'linear-gradient(135deg, rgba(99,102,241,0.08), rgba(139,92,246,0.08))', borderRadius: 'var(--radius-lg)', border: '1px solid rgba(99,102,241,0.25)', marginBottom: 20 };
|
|
518
|
+
var methodCard = function(id, icon, title, subtitle, difficulty, recommended) {
|
|
519
|
+
var isActive = selectedMethod === id;
|
|
520
|
+
return h('div', {
|
|
521
|
+
onClick: function() { setSelectedMethod(isActive ? null : id); },
|
|
522
|
+
style: {
|
|
523
|
+
padding: 16, borderRadius: 'var(--radius)', cursor: 'pointer', transition: 'all 0.15s',
|
|
524
|
+
background: isActive ? 'rgba(99,102,241,0.12)' : 'var(--bg-secondary)',
|
|
525
|
+
border: '1px solid ' + (isActive ? 'var(--accent)' : 'var(--border)'),
|
|
526
|
+
position: 'relative',
|
|
527
|
+
},
|
|
528
|
+
},
|
|
529
|
+
recommended && h('span', { style: { position: 'absolute', top: -8, right: 12, fontSize: 9, fontWeight: 700, padding: '2px 8px', borderRadius: 99, background: 'var(--accent)', color: '#fff', textTransform: 'uppercase', letterSpacing: '0.05em' } }, 'Recommended'),
|
|
530
|
+
h('div', { style: { display: 'flex', alignItems: 'center', gap: 10, marginBottom: 6 } },
|
|
531
|
+
h('span', { style: { fontSize: 20 } }, icon),
|
|
532
|
+
h('span', { style: { fontWeight: 600, fontSize: 14 } }, title),
|
|
533
|
+
),
|
|
534
|
+
h('div', { style: { fontSize: 12, color: 'var(--text-muted)', marginBottom: 6, lineHeight: 1.5 } }, subtitle),
|
|
535
|
+
h('div', { style: { fontSize: 10, fontWeight: 600, color: difficulty === 'Easy' ? 'var(--success)' : difficulty === 'Medium' ? 'var(--warning)' : 'var(--text-muted)' } }, difficulty),
|
|
536
|
+
);
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
var copyCmd = function(cmd) {
|
|
540
|
+
navigator.clipboard.writeText(cmd);
|
|
541
|
+
toast('Command copied!', 'success');
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
var cmdBlock = function(cmd, label) {
|
|
545
|
+
return h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '8px 12px', background: '#0d1117', borderRadius: 6, marginBottom: 6, fontFamily: 'var(--font-mono)', fontSize: 12, color: '#e6edf3', border: '1px solid rgba(255,255,255,0.08)' } },
|
|
546
|
+
h('span', { style: { flex: 1, wordBreak: 'break-all' } }, cmd),
|
|
547
|
+
h('button', { onClick: function() { copyCmd(cmd); }, style: { background: 'none', border: 'none', color: 'var(--text-muted)', cursor: 'pointer', fontSize: 11, padding: '2px 6px', borderRadius: 4, flexShrink: 0 }, title: 'Copy' }, 'Copy'),
|
|
548
|
+
);
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
var stepItem = function(num, text) {
|
|
552
|
+
return h('div', { style: { display: 'flex', gap: 10, marginBottom: 8, fontSize: 13, lineHeight: 1.6 } },
|
|
553
|
+
h('span', { style: { width: 22, height: 22, borderRadius: '50%', background: 'var(--accent-soft)', color: 'var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 11, fontWeight: 700, flexShrink: 0, marginTop: 1 } }, num),
|
|
554
|
+
h('div', null, text),
|
|
555
|
+
);
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
return h('div', { style: card },
|
|
559
|
+
h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', cursor: 'pointer' }, onClick: function() { setExpanded(!expanded); } },
|
|
560
|
+
h('div', null,
|
|
561
|
+
h('div', { style: { fontSize: 16, fontWeight: 700, marginBottom: 4, display: 'flex', alignItems: 'center', gap: 8 } },
|
|
562
|
+
'\uD83D\uDE80 Deploy to Production',
|
|
563
|
+
h('span', { style: { fontSize: 10, padding: '2px 8px', borderRadius: 99, background: 'rgba(245,158,11,0.15)', color: 'var(--warning)', fontWeight: 600 } }, 'LOCALHOST'),
|
|
564
|
+
),
|
|
565
|
+
h('div', { style: { fontSize: 13, color: 'var(--text-muted)' } }, 'You\'re running locally. Deploy to a domain so your agents can be reached from anywhere.'),
|
|
566
|
+
),
|
|
567
|
+
h('span', { style: { fontSize: 18, color: 'var(--text-muted)', transform: expanded ? 'rotate(180deg)' : 'none', transition: 'transform 0.2s' } }, '\u25BC'),
|
|
568
|
+
),
|
|
569
|
+
|
|
570
|
+
expanded && h('div', { style: { marginTop: 20 } },
|
|
571
|
+
// Method cards
|
|
572
|
+
h('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))', gap: 12, marginBottom: 20 } },
|
|
573
|
+
methodCard('vps', '\uD83D\uDDA5\uFE0F', 'VPS / Server', 'Deploy to any Linux server (DigitalOcean, Hetzner, AWS, etc.)', 'Easy', true),
|
|
574
|
+
methodCard('docker', '\uD83D\uDC33', 'Docker', 'Run as a Docker container on any host', 'Medium'),
|
|
575
|
+
methodCard('railway', '\uD83D\uDE82', 'Railway', 'One-click deploy to Railway.app', 'Easy'),
|
|
576
|
+
methodCard('fly', '\u2708\uFE0F', 'Fly.io', 'Deploy to Fly.io edge network', 'Medium'),
|
|
577
|
+
),
|
|
578
|
+
|
|
579
|
+
// ─── VPS Instructions ─────────────────────────
|
|
580
|
+
selectedMethod === 'vps' && h('div', { style: { padding: 20, background: 'var(--bg-secondary)', borderRadius: 'var(--radius)', border: '1px solid var(--border)' } },
|
|
581
|
+
h('h3', { style: { fontSize: 15, fontWeight: 700, marginBottom: 16 } }, 'Deploy to a VPS'),
|
|
582
|
+
h('p', { style: { fontSize: 13, color: 'var(--text-muted)', marginBottom: 16, lineHeight: 1.6 } },
|
|
583
|
+
'Works with any Linux server: DigitalOcean ($6/mo), Hetzner ($4/mo), Linode, AWS EC2, etc. Minimum: 1 CPU, 1GB RAM.',
|
|
584
|
+
),
|
|
585
|
+
|
|
586
|
+
stepItem('1', h(Fragment, null, h('strong', null, 'Get a server'), ' — Any Ubuntu/Debian VPS. Point your domain\'s DNS to the server\'s IP address.')),
|
|
587
|
+
|
|
588
|
+
stepItem('2', h(Fragment, null, h('strong', null, 'SSH in and install Node.js + PM2:'),
|
|
589
|
+
cmdBlock('curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs'),
|
|
590
|
+
cmdBlock('sudo npm install -g pm2'),
|
|
591
|
+
)),
|
|
592
|
+
|
|
593
|
+
stepItem('3', h(Fragment, null, h('strong', null, 'Install AgenticMail Enterprise:'),
|
|
594
|
+
cmdBlock('sudo npm install -g @agenticmail/enterprise'),
|
|
595
|
+
)),
|
|
596
|
+
|
|
597
|
+
stepItem('4', h(Fragment, null, h('strong', null, 'Run the setup wizard:'),
|
|
598
|
+
cmdBlock('agenticmail-enterprise setup'),
|
|
599
|
+
h('span', { style: { fontSize: 12, color: 'var(--text-muted)' } }, 'This will walk you through Google Workspace, database, and domain configuration.'),
|
|
600
|
+
)),
|
|
601
|
+
|
|
602
|
+
stepItem('5', h(Fragment, null, h('strong', null, 'Start with PM2 (auto-restart on crash):'),
|
|
603
|
+
cmdBlock('pm2 start agenticmail-enterprise -- start'),
|
|
604
|
+
cmdBlock('pm2 save && pm2 startup'),
|
|
605
|
+
)),
|
|
606
|
+
|
|
607
|
+
stepItem('6', h(Fragment, null, h('strong', null, 'Set up HTTPS with Caddy (automatic SSL):'),
|
|
608
|
+
cmdBlock('sudo apt install -y caddy'),
|
|
609
|
+
cmdBlock('echo "yourdomain.com { reverse_proxy localhost:3200 }" | sudo tee /etc/caddy/Caddyfile'),
|
|
610
|
+
cmdBlock('sudo systemctl restart caddy'),
|
|
611
|
+
h('span', { style: { fontSize: 12, color: 'var(--text-muted)' } }, 'Replace yourdomain.com with your actual domain. Caddy handles SSL automatically.'),
|
|
612
|
+
)),
|
|
613
|
+
|
|
614
|
+
h('div', { style: { marginTop: 16, padding: '12px 16px', background: 'var(--success-soft)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--success)', lineHeight: 1.6 } },
|
|
615
|
+
'\u2705 Done! Your dashboard will be live at ', h('strong', null, 'https://yourdomain.com'), '. All your agents, settings, and data will be on your own server.'
|
|
616
|
+
),
|
|
617
|
+
),
|
|
618
|
+
|
|
619
|
+
// ─── Docker Instructions ──────────────────────
|
|
620
|
+
selectedMethod === 'docker' && h('div', { style: { padding: 20, background: 'var(--bg-secondary)', borderRadius: 'var(--radius)', border: '1px solid var(--border)' } },
|
|
621
|
+
h('h3', { style: { fontSize: 15, fontWeight: 700, marginBottom: 16 } }, 'Deploy with Docker'),
|
|
622
|
+
|
|
623
|
+
stepItem('1', h(Fragment, null, h('strong', null, 'Create docker-compose.yml:'),
|
|
624
|
+
cmdBlock('mkdir agenticmail && cd agenticmail'),
|
|
625
|
+
h('div', { style: { padding: '10px 12px', background: '#0d1117', borderRadius: 6, marginBottom: 6, fontFamily: 'var(--font-mono)', fontSize: 11, color: '#e6edf3', whiteSpace: 'pre', overflowX: 'auto', border: '1px solid rgba(255,255,255,0.08)' } },
|
|
626
|
+
'version: "3.8"\nservices:\n enterprise:\n image: node:22\n working_dir: /app\n command: npx @agenticmail/enterprise start\n ports:\n - "3200:3200"\n volumes:\n - ./data:/app/data\n restart: unless-stopped'
|
|
627
|
+
),
|
|
628
|
+
)),
|
|
629
|
+
|
|
630
|
+
stepItem('2', h(Fragment, null, h('strong', null, 'Start:'),
|
|
631
|
+
cmdBlock('docker compose up -d'),
|
|
632
|
+
)),
|
|
633
|
+
|
|
634
|
+
stepItem('3', h(Fragment, null, h('strong', null, 'Add a reverse proxy (Caddy/Nginx) for HTTPS, same as VPS step 6.'))),
|
|
635
|
+
),
|
|
636
|
+
|
|
637
|
+
// ─── Railway Instructions ─────────────────────
|
|
638
|
+
selectedMethod === 'railway' && h('div', { style: { padding: 20, background: 'var(--bg-secondary)', borderRadius: 'var(--radius)', border: '1px solid var(--border)' } },
|
|
639
|
+
h('h3', { style: { fontSize: 15, fontWeight: 700, marginBottom: 16 } }, 'Deploy to Railway'),
|
|
640
|
+
|
|
641
|
+
stepItem('1', h(Fragment, null,
|
|
642
|
+
h('strong', null, 'Click to deploy:'),
|
|
643
|
+
h('div', { style: { marginTop: 8 } },
|
|
644
|
+
h('a', { href: 'https://railway.app/new', target: '_blank', style: { display: 'inline-flex', alignItems: 'center', gap: 8, padding: '8px 16px', background: 'var(--accent)', color: '#fff', borderRadius: 6, textDecoration: 'none', fontSize: 13, fontWeight: 600 } }, '\uD83D\uDE82 Open Railway'),
|
|
645
|
+
),
|
|
646
|
+
)),
|
|
647
|
+
stepItem('2', h(Fragment, null, h('strong', null, 'Create a new project'), ' and select "Deploy from GitHub" or "Empty Project".')),
|
|
648
|
+
stepItem('3', h(Fragment, null, h('strong', null, 'Add a service'), ' with start command:',
|
|
649
|
+
cmdBlock('npx @agenticmail/enterprise start'),
|
|
650
|
+
)),
|
|
651
|
+
stepItem('4', h(Fragment, null, h('strong', null, 'Set environment variables'), ' (DATABASE_URL, MASTER_KEY, etc.) in the Railway dashboard.')),
|
|
652
|
+
stepItem('5', h(Fragment, null, h('strong', null, 'Generate a domain'), ' — Railway gives you a free URL, or add your custom domain.')),
|
|
653
|
+
),
|
|
654
|
+
|
|
655
|
+
// ─── Fly.io Instructions ──────────────────────
|
|
656
|
+
selectedMethod === 'fly' && h('div', { style: { padding: 20, background: 'var(--bg-secondary)', borderRadius: 'var(--radius)', border: '1px solid var(--border)' } },
|
|
657
|
+
h('h3', { style: { fontSize: 15, fontWeight: 700, marginBottom: 16 } }, 'Deploy to Fly.io'),
|
|
658
|
+
|
|
659
|
+
stepItem('1', h(Fragment, null, h('strong', null, 'Install Fly CLI:'),
|
|
660
|
+
cmdBlock('curl -L https://fly.io/install.sh | sh'),
|
|
661
|
+
cmdBlock('fly auth login'),
|
|
662
|
+
)),
|
|
663
|
+
stepItem('2', h(Fragment, null, h('strong', null, 'Create fly.toml:'),
|
|
664
|
+
h('div', { style: { padding: '10px 12px', background: '#0d1117', borderRadius: 6, marginBottom: 6, fontFamily: 'var(--font-mono)', fontSize: 11, color: '#e6edf3', whiteSpace: 'pre', overflowX: 'auto', border: '1px solid rgba(255,255,255,0.08)' } },
|
|
665
|
+
'app = "my-agenticmail"\n\n[build]\n builder = "heroku/buildpacks:22"\n\n[env]\n PORT = "3200"\n\n[[services]]\n internal_port = 3200\n protocol = "tcp"\n [services.concurrency]\n hard_limit = 250\n soft_limit = 200\n [[services.ports]]\n port = 443\n handlers = ["tls", "http"]'
|
|
666
|
+
),
|
|
667
|
+
)),
|
|
668
|
+
stepItem('3', h(Fragment, null, h('strong', null, 'Set secrets and deploy:'),
|
|
669
|
+
cmdBlock('fly secrets set MASTER_KEY=your-key DATABASE_URL=your-db-url'),
|
|
670
|
+
cmdBlock('fly deploy'),
|
|
671
|
+
)),
|
|
672
|
+
stepItem('4', h(Fragment, null, h('strong', null, 'Add custom domain:'),
|
|
673
|
+
cmdBlock('fly certs create yourdomain.com'),
|
|
674
|
+
)),
|
|
675
|
+
),
|
|
676
|
+
|
|
677
|
+
// ─── Export / Migrate Data ────────────────────
|
|
678
|
+
h('div', { style: { marginTop: 16, padding: '14px 16px', background: 'var(--bg-tertiary)', borderRadius: 'var(--radius)', border: '1px solid var(--border)' } },
|
|
679
|
+
h('div', { style: { fontSize: 13, fontWeight: 600, marginBottom: 6 } }, 'Migrating from Localhost?'),
|
|
680
|
+
h('div', { style: { fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.6 } },
|
|
681
|
+
'Your local data (SQLite) lives in ', h('code', { style: { fontSize: 11, color: 'var(--accent)' } }, './data/'),
|
|
682
|
+
'. To migrate to a production Postgres database:',
|
|
683
|
+
),
|
|
684
|
+
h('ol', { style: { fontSize: 12, color: 'var(--text-secondary)', lineHeight: 1.8, paddingLeft: 20, marginTop: 8, marginBottom: 0 } },
|
|
685
|
+
h('li', null, 'Set up a Postgres database (Neon, Supabase, Railway, or self-hosted)'),
|
|
686
|
+
h('li', null, 'Set ', h('code', { style: { fontSize: 11, color: 'var(--accent)' } }, 'DATABASE_URL'), ' environment variable to your Postgres connection string'),
|
|
687
|
+
h('li', null, 'Run ', h('code', { style: { fontSize: 11, color: 'var(--accent)' } }, 'agenticmail-enterprise setup'), ' — tables are auto-created on first run'),
|
|
688
|
+
h('li', null, 'Re-configure your Google Workspace credentials in the setup wizard'),
|
|
689
|
+
),
|
|
690
|
+
),
|
|
691
|
+
),
|
|
692
|
+
);
|
|
693
|
+
}
|