@agenticmail/enterprise 0.5.24 → 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/dashboard/pages/knowledge.js +1 -1
- 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/src/dashboard/pages/knowledge.js +1 -1
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import {
|
|
2
|
+
withRetry
|
|
3
|
+
} from "./chunk-JLSQOQ5L.js";
|
|
4
|
+
|
|
5
|
+
// src/deploy/fly.ts
|
|
6
|
+
var FLY_API = "https://api.machines.dev";
|
|
7
|
+
var DEFAULT_IMAGE = "agenticmail/enterprise:latest";
|
|
8
|
+
async function flyRequest(path, opts) {
|
|
9
|
+
const resp = await fetch(`${FLY_API}${path}`, {
|
|
10
|
+
method: opts.method || "GET",
|
|
11
|
+
headers: {
|
|
12
|
+
Authorization: `Bearer ${opts.apiToken}`,
|
|
13
|
+
"Content-Type": "application/json"
|
|
14
|
+
},
|
|
15
|
+
body: opts.body ? JSON.stringify(opts.body) : void 0,
|
|
16
|
+
signal: AbortSignal.timeout(3e4)
|
|
17
|
+
});
|
|
18
|
+
if (!resp.ok) {
|
|
19
|
+
const text = await resp.text().catch(() => "Unknown error");
|
|
20
|
+
throw new Error(`Fly.io API error (${resp.status}): ${text}`);
|
|
21
|
+
}
|
|
22
|
+
return resp.json();
|
|
23
|
+
}
|
|
24
|
+
async function createApp(name, fly) {
|
|
25
|
+
await flyRequest("/v1/apps", {
|
|
26
|
+
method: "POST",
|
|
27
|
+
apiToken: fly.apiToken,
|
|
28
|
+
body: {
|
|
29
|
+
app_name: name,
|
|
30
|
+
org_slug: fly.org || "personal"
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async function createMachine(appName, config, fly) {
|
|
35
|
+
const region = fly.regions?.[0] || "iad";
|
|
36
|
+
const env = {
|
|
37
|
+
PORT: "3000",
|
|
38
|
+
NODE_ENV: "production",
|
|
39
|
+
DATABASE_TYPE: config.dbType,
|
|
40
|
+
DATABASE_URL: config.dbConnectionString,
|
|
41
|
+
JWT_SECRET: config.jwtSecret
|
|
42
|
+
};
|
|
43
|
+
if (config.smtpHost) env.SMTP_HOST = config.smtpHost;
|
|
44
|
+
if (config.smtpPort) env.SMTP_PORT = String(config.smtpPort);
|
|
45
|
+
if (config.smtpUser) env.SMTP_USER = config.smtpUser;
|
|
46
|
+
if (config.smtpPass) env.SMTP_PASS = config.smtpPass;
|
|
47
|
+
const result = await flyRequest(`/v1/apps/${appName}/machines`, {
|
|
48
|
+
method: "POST",
|
|
49
|
+
apiToken: fly.apiToken,
|
|
50
|
+
body: {
|
|
51
|
+
name: `${appName}-web`,
|
|
52
|
+
region,
|
|
53
|
+
config: {
|
|
54
|
+
image: fly.image || DEFAULT_IMAGE,
|
|
55
|
+
env,
|
|
56
|
+
services: [
|
|
57
|
+
{
|
|
58
|
+
ports: [
|
|
59
|
+
{ port: 443, handlers: ["tls", "http"] },
|
|
60
|
+
{ port: 80, handlers: ["http"] }
|
|
61
|
+
],
|
|
62
|
+
protocol: "tcp",
|
|
63
|
+
internal_port: 3e3,
|
|
64
|
+
concurrency: {
|
|
65
|
+
type: "connections",
|
|
66
|
+
hard_limit: 100,
|
|
67
|
+
soft_limit: 80
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
checks: {
|
|
72
|
+
health: {
|
|
73
|
+
type: "http",
|
|
74
|
+
port: 3e3,
|
|
75
|
+
path: "/health",
|
|
76
|
+
interval: "30s",
|
|
77
|
+
timeout: "5s",
|
|
78
|
+
grace_period: "10s"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
guest: {
|
|
82
|
+
cpu_kind: config.cpuKind || "shared",
|
|
83
|
+
cpus: config.cpus || 1,
|
|
84
|
+
memory_mb: config.memoryMb || 256
|
|
85
|
+
},
|
|
86
|
+
auto_destroy: false,
|
|
87
|
+
restart: {
|
|
88
|
+
policy: "always",
|
|
89
|
+
max_retries: 5
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
return { id: result.id, region: result.region || region };
|
|
95
|
+
}
|
|
96
|
+
async function allocateIp(appName, fly) {
|
|
97
|
+
try {
|
|
98
|
+
const resp = await fetch("https://api.fly.io/graphql", {
|
|
99
|
+
method: "POST",
|
|
100
|
+
headers: {
|
|
101
|
+
Authorization: `Bearer ${fly.apiToken}`,
|
|
102
|
+
"Content-Type": "application/json"
|
|
103
|
+
},
|
|
104
|
+
body: JSON.stringify({
|
|
105
|
+
query: `mutation($input: AllocateIPAddressInput!) {
|
|
106
|
+
allocateIpAddress(input: $input) {
|
|
107
|
+
ipAddress { id address type region createdAt }
|
|
108
|
+
}
|
|
109
|
+
}`,
|
|
110
|
+
variables: {
|
|
111
|
+
input: { appId: appName, type: "v4", region: "" }
|
|
112
|
+
}
|
|
113
|
+
}),
|
|
114
|
+
signal: AbortSignal.timeout(15e3)
|
|
115
|
+
});
|
|
116
|
+
const data = await resp.json();
|
|
117
|
+
const v4 = data?.data?.allocateIpAddress?.ipAddress?.address;
|
|
118
|
+
return { v4 };
|
|
119
|
+
} catch {
|
|
120
|
+
return {};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async function addCertificate(appName, hostname, fly) {
|
|
124
|
+
await fetch("https://api.fly.io/graphql", {
|
|
125
|
+
method: "POST",
|
|
126
|
+
headers: {
|
|
127
|
+
Authorization: `Bearer ${fly.apiToken}`,
|
|
128
|
+
"Content-Type": "application/json"
|
|
129
|
+
},
|
|
130
|
+
body: JSON.stringify({
|
|
131
|
+
query: `mutation($appId: ID!, $hostname: String!) {
|
|
132
|
+
addCertificate(appId: $appId, hostname: $hostname) {
|
|
133
|
+
certificate { hostname configured }
|
|
134
|
+
}
|
|
135
|
+
}`,
|
|
136
|
+
variables: { appId: appName, hostname }
|
|
137
|
+
}),
|
|
138
|
+
signal: AbortSignal.timeout(15e3)
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async function deployToFly(config, fly) {
|
|
142
|
+
const appName = `am-${config.subdomain}`;
|
|
143
|
+
const domain = `${config.subdomain}.agenticmail.io`;
|
|
144
|
+
try {
|
|
145
|
+
console.log(` Creating app: ${appName}...`);
|
|
146
|
+
await withRetry(() => createApp(appName, fly), {
|
|
147
|
+
maxAttempts: 2,
|
|
148
|
+
retryableErrors: (err) => !err.message.includes("already exists")
|
|
149
|
+
});
|
|
150
|
+
console.log(` Deploying machine...`);
|
|
151
|
+
const machine = await withRetry(() => createMachine(appName, config, fly), {
|
|
152
|
+
maxAttempts: 3,
|
|
153
|
+
baseDelayMs: 2e3
|
|
154
|
+
});
|
|
155
|
+
console.log(` Allocating IP address...`);
|
|
156
|
+
const ips = await allocateIp(appName, fly);
|
|
157
|
+
console.log(` Setting up TLS for ${domain}...`);
|
|
158
|
+
await addCertificate(appName, domain, fly).catch(() => {
|
|
159
|
+
});
|
|
160
|
+
return {
|
|
161
|
+
appName,
|
|
162
|
+
url: `https://${domain}`,
|
|
163
|
+
ipv4: ips.v4,
|
|
164
|
+
ipv6: ips.v6,
|
|
165
|
+
region: machine.region,
|
|
166
|
+
machineId: machine.id,
|
|
167
|
+
status: "started"
|
|
168
|
+
};
|
|
169
|
+
} catch (err) {
|
|
170
|
+
return {
|
|
171
|
+
appName,
|
|
172
|
+
url: `https://${domain}`,
|
|
173
|
+
region: fly.regions?.[0] || "iad",
|
|
174
|
+
machineId: "",
|
|
175
|
+
status: "error",
|
|
176
|
+
error: err.message
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async function getAppStatus(appName, fly) {
|
|
181
|
+
try {
|
|
182
|
+
const machines = await flyRequest(`/v1/apps/${appName}/machines`, {
|
|
183
|
+
apiToken: fly.apiToken
|
|
184
|
+
});
|
|
185
|
+
const running = machines.some((m) => m.state === "started");
|
|
186
|
+
return { running, machines };
|
|
187
|
+
} catch {
|
|
188
|
+
return { running: false, machines: [] };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async function destroyApp(appName, fly) {
|
|
192
|
+
const { machines } = await getAppStatus(appName, fly);
|
|
193
|
+
for (const m of machines) {
|
|
194
|
+
try {
|
|
195
|
+
await flyRequest(`/v1/apps/${appName}/machines/${m.id}/stop`, {
|
|
196
|
+
method: "POST",
|
|
197
|
+
apiToken: fly.apiToken
|
|
198
|
+
});
|
|
199
|
+
} catch {
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
await fetch("https://api.fly.io/graphql", {
|
|
203
|
+
method: "POST",
|
|
204
|
+
headers: {
|
|
205
|
+
Authorization: `Bearer ${fly.apiToken}`,
|
|
206
|
+
"Content-Type": "application/json"
|
|
207
|
+
},
|
|
208
|
+
body: JSON.stringify({
|
|
209
|
+
query: `mutation($appId: ID!) { deleteApp(appId: $appId) { organization { id } } }`,
|
|
210
|
+
variables: { appId: appName }
|
|
211
|
+
}),
|
|
212
|
+
signal: AbortSignal.timeout(15e3)
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export {
|
|
217
|
+
deployToFly,
|
|
218
|
+
getAppStatus,
|
|
219
|
+
destroyApp
|
|
220
|
+
};
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deployToFly
|
|
3
|
+
} from "./chunk-3SMTCIR4.js";
|
|
4
|
+
|
|
5
|
+
// src/deploy/managed.ts
|
|
6
|
+
async function deployToCloud(config, flyToken) {
|
|
7
|
+
const token = flyToken || process.env.FLY_API_TOKEN;
|
|
8
|
+
if (!token) {
|
|
9
|
+
return {
|
|
10
|
+
url: `https://${config.subdomain}.agenticmail.io`,
|
|
11
|
+
appName: `am-${config.subdomain}`,
|
|
12
|
+
region: config.region || "iad",
|
|
13
|
+
status: "pending",
|
|
14
|
+
error: "FLY_API_TOKEN not set. Set it to enable cloud deployment."
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const flyConfig = {
|
|
18
|
+
apiToken: token,
|
|
19
|
+
org: process.env.FLY_ORG || "agenticmail",
|
|
20
|
+
regions: [config.region || "iad"]
|
|
21
|
+
};
|
|
22
|
+
const appConfig = {
|
|
23
|
+
subdomain: config.subdomain,
|
|
24
|
+
dbType: config.dbType,
|
|
25
|
+
dbConnectionString: config.dbConnectionString,
|
|
26
|
+
jwtSecret: config.jwtSecret,
|
|
27
|
+
memoryMb: config.plan === "free" ? 256 : config.plan === "team" ? 512 : 1024,
|
|
28
|
+
cpuKind: config.plan === "enterprise" ? "performance" : "shared",
|
|
29
|
+
cpus: config.plan === "enterprise" ? 2 : 1
|
|
30
|
+
};
|
|
31
|
+
const result = await deployToFly(appConfig, flyConfig);
|
|
32
|
+
return {
|
|
33
|
+
url: result.url,
|
|
34
|
+
appName: result.appName,
|
|
35
|
+
region: result.region,
|
|
36
|
+
status: result.status === "error" ? "error" : "deployed",
|
|
37
|
+
error: result.error
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function generateEnvFile(opts) {
|
|
41
|
+
const lines = [
|
|
42
|
+
"# AgenticMail Enterprise \u2014 Environment Variables",
|
|
43
|
+
"# WARNING: Contains secrets. Do NOT commit to version control.",
|
|
44
|
+
`# Generated at ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
45
|
+
"",
|
|
46
|
+
`DATABASE_TYPE=${opts.dbType}`,
|
|
47
|
+
`DATABASE_URL=${opts.dbConnectionString}`,
|
|
48
|
+
`JWT_SECRET=${opts.jwtSecret}`
|
|
49
|
+
];
|
|
50
|
+
if (opts.smtpUser) lines.push(`SMTP_USER=${opts.smtpUser}`);
|
|
51
|
+
if (opts.smtpPass) lines.push(`SMTP_PASS=${opts.smtpPass}`);
|
|
52
|
+
return lines.join("\n") + "\n";
|
|
53
|
+
}
|
|
54
|
+
function generateDockerCompose(opts) {
|
|
55
|
+
const env = [
|
|
56
|
+
` - NODE_ENV=production`,
|
|
57
|
+
` - PORT=3000`
|
|
58
|
+
];
|
|
59
|
+
if (opts.smtpHost) {
|
|
60
|
+
env.push(` - SMTP_HOST=${opts.smtpHost}`);
|
|
61
|
+
env.push(` - SMTP_PORT=${opts.smtpPort || 587}`);
|
|
62
|
+
}
|
|
63
|
+
return `# AgenticMail Enterprise \u2014 Docker Compose
|
|
64
|
+
# Generated at ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
65
|
+
#
|
|
66
|
+
# Usage:
|
|
67
|
+
# docker compose up -d
|
|
68
|
+
# open http://localhost:${opts.port}
|
|
69
|
+
#
|
|
70
|
+
# Secrets are loaded from .env file (DATABASE_URL, JWT_SECRET, etc.)
|
|
71
|
+
# Do NOT commit .env to version control.
|
|
72
|
+
|
|
73
|
+
version: "3.8"
|
|
74
|
+
|
|
75
|
+
services:
|
|
76
|
+
agenticmail:
|
|
77
|
+
image: agenticmail/enterprise:latest
|
|
78
|
+
ports:
|
|
79
|
+
- "${opts.port}:3000"
|
|
80
|
+
env_file:
|
|
81
|
+
- .env
|
|
82
|
+
environment:
|
|
83
|
+
${env.join("\n")}
|
|
84
|
+
restart: unless-stopped
|
|
85
|
+
healthcheck:
|
|
86
|
+
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/health"]
|
|
87
|
+
interval: 30s
|
|
88
|
+
timeout: 10s
|
|
89
|
+
retries: 3
|
|
90
|
+
start_period: 15s
|
|
91
|
+
deploy:
|
|
92
|
+
resources:
|
|
93
|
+
limits:
|
|
94
|
+
memory: 512M
|
|
95
|
+
cpus: '1.0'
|
|
96
|
+
reservations:
|
|
97
|
+
memory: 128M
|
|
98
|
+
logging:
|
|
99
|
+
driver: json-file
|
|
100
|
+
options:
|
|
101
|
+
max-size: "10m"
|
|
102
|
+
max-file: "3"
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
105
|
+
function generateFlyToml(appName, region) {
|
|
106
|
+
return `# AgenticMail Enterprise \u2014 Fly.io Config
|
|
107
|
+
# Generated at ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
108
|
+
#
|
|
109
|
+
# Deploy:
|
|
110
|
+
# fly launch --copy-config
|
|
111
|
+
# fly secrets set DATABASE_URL="..." JWT_SECRET="..."
|
|
112
|
+
# fly deploy
|
|
113
|
+
|
|
114
|
+
app = "${appName}"
|
|
115
|
+
primary_region = "${region}"
|
|
116
|
+
|
|
117
|
+
[build]
|
|
118
|
+
image = "agenticmail/enterprise:latest"
|
|
119
|
+
|
|
120
|
+
[env]
|
|
121
|
+
PORT = "3000"
|
|
122
|
+
NODE_ENV = "production"
|
|
123
|
+
|
|
124
|
+
[http_service]
|
|
125
|
+
internal_port = 3000
|
|
126
|
+
force_https = true
|
|
127
|
+
auto_stop_machines = "stop"
|
|
128
|
+
auto_start_machines = true
|
|
129
|
+
min_machines_running = 1
|
|
130
|
+
|
|
131
|
+
[http_service.concurrency]
|
|
132
|
+
type = "connections"
|
|
133
|
+
hard_limit = 100
|
|
134
|
+
soft_limit = 80
|
|
135
|
+
|
|
136
|
+
[checks]
|
|
137
|
+
[checks.health]
|
|
138
|
+
type = "http"
|
|
139
|
+
port = 3000
|
|
140
|
+
path = "/health"
|
|
141
|
+
interval = "30s"
|
|
142
|
+
timeout = "5s"
|
|
143
|
+
grace_period = "10s"
|
|
144
|
+
|
|
145
|
+
[[vm]]
|
|
146
|
+
size = "shared-cpu-1x"
|
|
147
|
+
memory = "256mb"
|
|
148
|
+
`;
|
|
149
|
+
}
|
|
150
|
+
function generateRailwayConfig() {
|
|
151
|
+
return `# AgenticMail Enterprise \u2014 Railway Config
|
|
152
|
+
# Generated at ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
153
|
+
#
|
|
154
|
+
# Deploy:
|
|
155
|
+
# railway init
|
|
156
|
+
# railway link
|
|
157
|
+
# railway up
|
|
158
|
+
|
|
159
|
+
[build]
|
|
160
|
+
builder = "DOCKERFILE"
|
|
161
|
+
dockerfilePath = "Dockerfile"
|
|
162
|
+
|
|
163
|
+
[deploy]
|
|
164
|
+
healthcheckPath = "/health"
|
|
165
|
+
healthcheckTimeout = 10
|
|
166
|
+
restartPolicyType = "ON_FAILURE"
|
|
167
|
+
restartPolicyMaxRetries = 3
|
|
168
|
+
`;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export {
|
|
172
|
+
deployToCloud,
|
|
173
|
+
generateEnvFile,
|
|
174
|
+
generateDockerCompose,
|
|
175
|
+
generateFlyToml,
|
|
176
|
+
generateRailwayConfig
|
|
177
|
+
};
|