@agenticmail/enterprise 0.5.25 → 0.5.26
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/dist/chunk-3SMTCIR4.js +220 -0
- package/dist/chunk-7XMV4YKZ.js +177 -0
- package/dist/chunk-P3TYMEZP.js +2113 -0
- package/dist/chunk-UT7KPNBZ.js +898 -0
- package/dist/cli.js +1 -1
- package/dist/dashboard/pages/agents.js +5 -5
- package/dist/index.js +4 -3
- package/dist/managed-GJK5VQMN.js +17 -0
- package/dist/server-4ERCDJOV.js +12 -0
- package/dist/setup-AYFBHCHB.js +20 -0
- package/package.json +1 -1
- package/src/admin/routes.ts +158 -0
- package/src/dashboard/pages/agents.js +5 -5
package/dist/cli.js
CHANGED
|
@@ -31,7 +31,7 @@ export function DeployModal({ agentId, agentConfig, onClose, onDeployed, toast }
|
|
|
31
31
|
const doDeploy = async () => {
|
|
32
32
|
setError(''); setLoading(true);
|
|
33
33
|
try {
|
|
34
|
-
await
|
|
34
|
+
await apiCall('/agents/' + agentId + '/deploy', { method: 'POST', body: JSON.stringify({ targetType: targetType, credentialId: selectedCred || undefined, config: config, deployedBy: 'dashboard' }) });
|
|
35
35
|
if (toast) toast('Deployment started', 'success');
|
|
36
36
|
if (onDeployed) onDeployed();
|
|
37
37
|
onClose();
|
|
@@ -982,10 +982,10 @@ export function CreateAgentWizard({ onClose, onCreated, toast }) {
|
|
|
982
982
|
h('h3', { style: { fontSize: 15, fontWeight: 700, marginBottom: 4 } }, 'Deployment Target'),
|
|
983
983
|
h('p', { style: { color: 'var(--text-secondary)', marginBottom: 16, fontSize: 13 } }, 'Choose where and how this agent will run.'),
|
|
984
984
|
h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 } },
|
|
985
|
-
['docker', 'vps', 'local'].map(t =>
|
|
985
|
+
['fly', 'docker', 'railway', 'vps', 'local'].map(t =>
|
|
986
986
|
h('div', { key: t, className: 'preset-card' + (form.deployTarget === t ? ' selected' : ''), onClick: () => set('deployTarget', t), style: { padding: '16px 18px' } },
|
|
987
|
-
h('h4', { style: { marginBottom: 6 } }, { docker: 'Docker Container', vps: 'VPS / Dedicated Server', local: 'Local Machine' }[t]),
|
|
988
|
-
h('p', null, { docker: 'Run in an isolated Docker container with resource limits.
|
|
987
|
+
h('h4', { style: { marginBottom: 6 } }, { fly: 'Fly.io', docker: 'Docker Container', railway: 'Railway', vps: 'VPS / Dedicated Server', local: 'Local Machine' }[t]),
|
|
988
|
+
h('p', null, { fly: 'Deploy to Fly.io with auto-scaling, TLS, and health checks. Recommended for production.', docker: 'Run in an isolated Docker container with resource limits.', railway: 'Deploy to Railway with zero-config builds and auto-deploys.', vps: 'Deploy to a VPS or dedicated server via SSH. Full control.', local: 'Run on the current machine. Best for development and testing.' }[t])
|
|
989
989
|
)
|
|
990
990
|
)
|
|
991
991
|
)
|
|
@@ -1042,7 +1042,7 @@ export function CreateAgentWizard({ onClose, onCreated, toast }) {
|
|
|
1042
1042
|
h('span', { style: { color: 'var(--text-muted)' } }, 'Approvals'), h('span', null, form.approvalRequired ? 'Required (risk: ' + form.approvalForRiskLevels.join(', ') + ')' : 'Not required'),
|
|
1043
1043
|
h('span', { style: { color: 'var(--text-muted)' } }, 'Rate Limits'), h('span', null, form.rateLimits.toolCallsPerMinute + '/min, ' + form.rateLimits.toolCallsPerHour + '/hr, ' + form.rateLimits.toolCallsPerDay + '/day'),
|
|
1044
1044
|
h('span', { style: { color: 'var(--text-muted)' } }, 'Constraints'), h('span', null, form.constraints.maxConcurrentTasks + ' tasks, ' + form.constraints.maxSessionDurationMinutes + 'min max' + (form.constraints.sandboxMode ? ', sandbox' : '')),
|
|
1045
|
-
h('span', { style: { color: 'var(--text-muted)' } }, 'Deployment'), h('span', null, { docker: 'Docker Container', vps: 'VPS / Dedicated Server', local: 'Local Machine' }[form.deployTarget]),
|
|
1045
|
+
h('span', { style: { color: 'var(--text-muted)' } }, 'Deployment'), h('span', null, { fly: 'Fly.io', docker: 'Docker Container', railway: 'Railway', vps: 'VPS / Dedicated Server', local: 'Local Machine' }[form.deployTarget] || form.deployTarget),
|
|
1046
1046
|
h('span', { style: { color: 'var(--text-muted)' } }, 'Onboarding'), h('span', null, form.autoOnboard ? h('span', { className: 'badge badge-success' }, 'Auto-start') : h('span', { className: 'badge badge-neutral' }, 'Manual'))
|
|
1047
1047
|
)
|
|
1048
1048
|
)
|
package/dist/index.js
CHANGED
|
@@ -50,11 +50,11 @@ import {
|
|
|
50
50
|
requireRole,
|
|
51
51
|
securityHeaders,
|
|
52
52
|
validate
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-P3TYMEZP.js";
|
|
54
54
|
import {
|
|
55
55
|
provision,
|
|
56
56
|
runSetupWizard
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-UT7KPNBZ.js";
|
|
58
58
|
import {
|
|
59
59
|
ENGINE_TABLES,
|
|
60
60
|
ENGINE_TABLES_POSTGRES,
|
|
@@ -70,7 +70,8 @@ import {
|
|
|
70
70
|
generateDockerCompose,
|
|
71
71
|
generateEnvFile,
|
|
72
72
|
generateFlyToml
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-7XMV4YKZ.js";
|
|
74
|
+
import "./chunk-3SMTCIR4.js";
|
|
74
75
|
import {
|
|
75
76
|
CircuitBreaker,
|
|
76
77
|
CircuitOpenError,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deployToCloud,
|
|
3
|
+
generateDockerCompose,
|
|
4
|
+
generateEnvFile,
|
|
5
|
+
generateFlyToml,
|
|
6
|
+
generateRailwayConfig
|
|
7
|
+
} from "./chunk-7XMV4YKZ.js";
|
|
8
|
+
import "./chunk-3SMTCIR4.js";
|
|
9
|
+
import "./chunk-JLSQOQ5L.js";
|
|
10
|
+
import "./chunk-KFQGP6VL.js";
|
|
11
|
+
export {
|
|
12
|
+
deployToCloud,
|
|
13
|
+
generateDockerCompose,
|
|
14
|
+
generateEnvFile,
|
|
15
|
+
generateFlyToml,
|
|
16
|
+
generateRailwayConfig
|
|
17
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createServer
|
|
3
|
+
} from "./chunk-P3TYMEZP.js";
|
|
4
|
+
import "./chunk-3SMTCIR4.js";
|
|
5
|
+
import "./chunk-JLSQOQ5L.js";
|
|
6
|
+
import "./chunk-RO537U6H.js";
|
|
7
|
+
import "./chunk-DRXMYYKN.js";
|
|
8
|
+
import "./chunk-67KZYSLU.js";
|
|
9
|
+
import "./chunk-KFQGP6VL.js";
|
|
10
|
+
export {
|
|
11
|
+
createServer
|
|
12
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
promptCompanyInfo,
|
|
3
|
+
promptDatabase,
|
|
4
|
+
promptDeployment,
|
|
5
|
+
promptDomain,
|
|
6
|
+
promptRegistration,
|
|
7
|
+
provision,
|
|
8
|
+
runSetupWizard
|
|
9
|
+
} from "./chunk-UT7KPNBZ.js";
|
|
10
|
+
import "./chunk-HEK7L3DT.js";
|
|
11
|
+
import "./chunk-KFQGP6VL.js";
|
|
12
|
+
export {
|
|
13
|
+
promptCompanyInfo,
|
|
14
|
+
promptDatabase,
|
|
15
|
+
promptDeployment,
|
|
16
|
+
promptDomain,
|
|
17
|
+
promptRegistration,
|
|
18
|
+
provision,
|
|
19
|
+
runSetupWizard
|
|
20
|
+
};
|
package/package.json
CHANGED
package/src/admin/routes.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { AppEnv } from '../types/hono-env.js';
|
|
|
11
11
|
import type { DatabaseAdapter } from '../db/adapter.js';
|
|
12
12
|
import { validate, requireRole, ValidationError } from '../middleware/index.js';
|
|
13
13
|
import { PROVIDER_REGISTRY, type ProviderDef, type CustomProviderDef } from '../runtime/providers.js';
|
|
14
|
+
import { deployToFly, getAppStatus, destroyApp, type FlyConfig, type AppConfig } from '../deploy/fly.js';
|
|
14
15
|
|
|
15
16
|
export function createAdminRoutes(db: DatabaseAdapter) {
|
|
16
17
|
const api = new Hono<AppEnv>();
|
|
@@ -108,6 +109,163 @@ export function createAdminRoutes(db: DatabaseAdapter) {
|
|
|
108
109
|
return c.json({ ok: true });
|
|
109
110
|
});
|
|
110
111
|
|
|
112
|
+
// ─── Agent Deployment ─────────────────────────────────
|
|
113
|
+
|
|
114
|
+
api.post('/agents/:id/deploy', requireRole('admin'), async (c) => {
|
|
115
|
+
const agentId = c.req.param('id');
|
|
116
|
+
const agent = await db.getAgent(agentId);
|
|
117
|
+
if (!agent) return c.json({ error: 'Agent not found' }, 404);
|
|
118
|
+
|
|
119
|
+
const body = await c.req.json();
|
|
120
|
+
const targetType = body.targetType || 'fly';
|
|
121
|
+
const config = body.config || {};
|
|
122
|
+
|
|
123
|
+
// Get deployment credentials
|
|
124
|
+
const settings = await db.getSettings();
|
|
125
|
+
const pricingConfig = (settings as any)?.modelPricingConfig || {};
|
|
126
|
+
const providerApiKeys = pricingConfig.providerApiKeys || {};
|
|
127
|
+
|
|
128
|
+
if (targetType === 'fly') {
|
|
129
|
+
// Get Fly.io API token from deploy credentials or config
|
|
130
|
+
let flyToken = config.flyApiToken || process.env.FLY_API_TOKEN;
|
|
131
|
+
if (!flyToken && body.credentialId) {
|
|
132
|
+
// Look up stored credential
|
|
133
|
+
try {
|
|
134
|
+
const creds = await (db as any).query?.('SELECT config FROM deploy_credentials WHERE id = $1', [body.credentialId]);
|
|
135
|
+
if (creds?.rows?.[0]?.config) {
|
|
136
|
+
const credConfig = typeof creds.rows[0].config === 'string' ? JSON.parse(creds.rows[0].config) : creds.rows[0].config;
|
|
137
|
+
flyToken = credConfig.apiToken;
|
|
138
|
+
}
|
|
139
|
+
} catch { /* ignore */ }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (!flyToken) {
|
|
143
|
+
return c.json({ error: 'Fly.io API token required. Add it in Settings → Deployments or pass flyApiToken in config.' }, 400);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const flyConfig: FlyConfig = {
|
|
147
|
+
apiToken: flyToken,
|
|
148
|
+
org: config.flyOrg || 'personal',
|
|
149
|
+
image: config.image || 'node:22-slim',
|
|
150
|
+
regions: config.regions || ['iad'],
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const agentName = (agent as any).name || agentId;
|
|
154
|
+
const appConfig: AppConfig = {
|
|
155
|
+
subdomain: agentName.toLowerCase().replace(/[^a-z0-9-]/g, '-'),
|
|
156
|
+
dbType: 'postgres',
|
|
157
|
+
dbConnectionString: process.env.DATABASE_URL || '',
|
|
158
|
+
jwtSecret: process.env.JWT_SECRET || 'agent-' + agentId,
|
|
159
|
+
smtpHost: (settings as any)?.smtpHost,
|
|
160
|
+
smtpPort: (settings as any)?.smtpPort,
|
|
161
|
+
smtpUser: (settings as any)?.smtpUser,
|
|
162
|
+
smtpPass: (settings as any)?.smtpPass,
|
|
163
|
+
memoryMb: config.memoryMb || 256,
|
|
164
|
+
cpuKind: config.cpuKind || 'shared',
|
|
165
|
+
cpus: config.cpus || 1,
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
const result = await deployToFly(appConfig, flyConfig);
|
|
170
|
+
|
|
171
|
+
// Update agent record with deployment info (stored in metadata)
|
|
172
|
+
const existingAgent = await db.getAgent(agentId);
|
|
173
|
+
const existingMeta = (existingAgent as any)?.metadata || {};
|
|
174
|
+
await db.updateAgent(agentId, {
|
|
175
|
+
status: result.status === 'started' ? 'active' : 'error',
|
|
176
|
+
metadata: {
|
|
177
|
+
...existingMeta,
|
|
178
|
+
deployment: {
|
|
179
|
+
target: 'fly',
|
|
180
|
+
appName: result.appName,
|
|
181
|
+
url: result.url,
|
|
182
|
+
region: result.region,
|
|
183
|
+
machineId: result.machineId,
|
|
184
|
+
deployedAt: new Date().toISOString(),
|
|
185
|
+
deployedBy: body.deployedBy || 'dashboard',
|
|
186
|
+
status: result.status,
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
} as any);
|
|
190
|
+
|
|
191
|
+
return c.json({
|
|
192
|
+
success: result.status === 'started',
|
|
193
|
+
deployment: result,
|
|
194
|
+
});
|
|
195
|
+
} catch (err: any) {
|
|
196
|
+
return c.json({ error: 'Deployment failed: ' + err.message }, 500);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (targetType === 'local') {
|
|
201
|
+
const existingAgent = await db.getAgent(agentId);
|
|
202
|
+
const existingMeta = (existingAgent as any)?.metadata || {};
|
|
203
|
+
await db.updateAgent(agentId, {
|
|
204
|
+
status: 'active',
|
|
205
|
+
metadata: {
|
|
206
|
+
...existingMeta,
|
|
207
|
+
deployment: {
|
|
208
|
+
target: 'local',
|
|
209
|
+
url: `http://localhost:${3000 + Math.floor(Math.random() * 1000)}`,
|
|
210
|
+
deployedAt: new Date().toISOString(),
|
|
211
|
+
deployedBy: body.deployedBy || 'dashboard',
|
|
212
|
+
status: 'started',
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
} as any);
|
|
216
|
+
return c.json({ success: true, deployment: { status: 'started', target: 'local' } });
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return c.json({ error: 'Unsupported deploy target: ' + targetType + '. Supported: fly, docker, vps, local' }, 400);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Get deployment status
|
|
223
|
+
api.get('/agents/:id/deploy', requireRole('admin'), async (c) => {
|
|
224
|
+
const agent = await db.getAgent(c.req.param('id'));
|
|
225
|
+
if (!agent) return c.json({ error: 'Agent not found' }, 404);
|
|
226
|
+
|
|
227
|
+
const meta = (agent as any).metadata || {};
|
|
228
|
+
const info = meta.deployment;
|
|
229
|
+
if (!info) return c.json({ deployed: false });
|
|
230
|
+
|
|
231
|
+
if (info.target === 'fly' && info.appName) {
|
|
232
|
+
const flyToken = process.env.FLY_API_TOKEN;
|
|
233
|
+
if (flyToken) {
|
|
234
|
+
try {
|
|
235
|
+
const status = await getAppStatus(info.appName, { apiToken: flyToken });
|
|
236
|
+
return c.json({ deployed: true, ...info, live: status });
|
|
237
|
+
} catch { /* fall through */ }
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return c.json({ deployed: true, ...info });
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Destroy deployment
|
|
245
|
+
api.delete('/agents/:id/deploy', requireRole('admin'), async (c) => {
|
|
246
|
+
const agent = await db.getAgent(c.req.param('id'));
|
|
247
|
+
if (!agent) return c.json({ error: 'Agent not found' }, 404);
|
|
248
|
+
|
|
249
|
+
const meta = (agent as any).metadata || {};
|
|
250
|
+
const info = meta.deployment;
|
|
251
|
+
if (!info) return c.json({ error: 'Agent not deployed' }, 400);
|
|
252
|
+
|
|
253
|
+
if (info.target === 'fly' && info.appName) {
|
|
254
|
+
const flyToken = process.env.FLY_API_TOKEN;
|
|
255
|
+
if (flyToken) {
|
|
256
|
+
try {
|
|
257
|
+
await destroyApp(info.appName, { apiToken: flyToken });
|
|
258
|
+
} catch (err: any) {
|
|
259
|
+
return c.json({ error: 'Failed to destroy: ' + err.message }, 500);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
delete meta.deployment;
|
|
265
|
+
await db.updateAgent(c.req.param('id'), { status: 'inactive', metadata: meta } as any);
|
|
266
|
+
return c.json({ ok: true, message: 'Deployment destroyed' });
|
|
267
|
+
});
|
|
268
|
+
|
|
111
269
|
// ─── Users ──────────────────────────────────────────
|
|
112
270
|
|
|
113
271
|
api.get('/users', requireRole('admin'), async (c) => {
|
|
@@ -31,7 +31,7 @@ export function DeployModal({ agentId, agentConfig, onClose, onDeployed, toast }
|
|
|
31
31
|
const doDeploy = async () => {
|
|
32
32
|
setError(''); setLoading(true);
|
|
33
33
|
try {
|
|
34
|
-
await
|
|
34
|
+
await apiCall('/agents/' + agentId + '/deploy', { method: 'POST', body: JSON.stringify({ targetType: targetType, credentialId: selectedCred || undefined, config: config, deployedBy: 'dashboard' }) });
|
|
35
35
|
if (toast) toast('Deployment started', 'success');
|
|
36
36
|
if (onDeployed) onDeployed();
|
|
37
37
|
onClose();
|
|
@@ -982,10 +982,10 @@ export function CreateAgentWizard({ onClose, onCreated, toast }) {
|
|
|
982
982
|
h('h3', { style: { fontSize: 15, fontWeight: 700, marginBottom: 4 } }, 'Deployment Target'),
|
|
983
983
|
h('p', { style: { color: 'var(--text-secondary)', marginBottom: 16, fontSize: 13 } }, 'Choose where and how this agent will run.'),
|
|
984
984
|
h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 } },
|
|
985
|
-
['docker', 'vps', 'local'].map(t =>
|
|
985
|
+
['fly', 'docker', 'railway', 'vps', 'local'].map(t =>
|
|
986
986
|
h('div', { key: t, className: 'preset-card' + (form.deployTarget === t ? ' selected' : ''), onClick: () => set('deployTarget', t), style: { padding: '16px 18px' } },
|
|
987
|
-
h('h4', { style: { marginBottom: 6 } }, { docker: 'Docker Container', vps: 'VPS / Dedicated Server', local: 'Local Machine' }[t]),
|
|
988
|
-
h('p', null, { docker: 'Run in an isolated Docker container with resource limits.
|
|
987
|
+
h('h4', { style: { marginBottom: 6 } }, { fly: 'Fly.io', docker: 'Docker Container', railway: 'Railway', vps: 'VPS / Dedicated Server', local: 'Local Machine' }[t]),
|
|
988
|
+
h('p', null, { fly: 'Deploy to Fly.io with auto-scaling, TLS, and health checks. Recommended for production.', docker: 'Run in an isolated Docker container with resource limits.', railway: 'Deploy to Railway with zero-config builds and auto-deploys.', vps: 'Deploy to a VPS or dedicated server via SSH. Full control.', local: 'Run on the current machine. Best for development and testing.' }[t])
|
|
989
989
|
)
|
|
990
990
|
)
|
|
991
991
|
)
|
|
@@ -1042,7 +1042,7 @@ export function CreateAgentWizard({ onClose, onCreated, toast }) {
|
|
|
1042
1042
|
h('span', { style: { color: 'var(--text-muted)' } }, 'Approvals'), h('span', null, form.approvalRequired ? 'Required (risk: ' + form.approvalForRiskLevels.join(', ') + ')' : 'Not required'),
|
|
1043
1043
|
h('span', { style: { color: 'var(--text-muted)' } }, 'Rate Limits'), h('span', null, form.rateLimits.toolCallsPerMinute + '/min, ' + form.rateLimits.toolCallsPerHour + '/hr, ' + form.rateLimits.toolCallsPerDay + '/day'),
|
|
1044
1044
|
h('span', { style: { color: 'var(--text-muted)' } }, 'Constraints'), h('span', null, form.constraints.maxConcurrentTasks + ' tasks, ' + form.constraints.maxSessionDurationMinutes + 'min max' + (form.constraints.sandboxMode ? ', sandbox' : '')),
|
|
1045
|
-
h('span', { style: { color: 'var(--text-muted)' } }, 'Deployment'), h('span', null, { docker: 'Docker Container', vps: 'VPS / Dedicated Server', local: 'Local Machine' }[form.deployTarget]),
|
|
1045
|
+
h('span', { style: { color: 'var(--text-muted)' } }, 'Deployment'), h('span', null, { fly: 'Fly.io', docker: 'Docker Container', railway: 'Railway', vps: 'VPS / Dedicated Server', local: 'Local Machine' }[form.deployTarget] || form.deployTarget),
|
|
1046
1046
|
h('span', { style: { color: 'var(--text-muted)' } }, 'Onboarding'), h('span', null, form.autoOnboard ? h('span', { className: 'badge badge-success' }, 'Auto-start') : h('span', { className: 'badge badge-neutral' }, 'Manual'))
|
|
1047
1047
|
)
|
|
1048
1048
|
)
|