@agenticmail/enterprise 0.3.0 → 0.3.2
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/LICENSE +26 -0
- package/README.md +14 -4
- package/dist/dashboard/index.html +5 -5
- package/live-test.mjs +165 -0
- package/package.json +11 -2
- package/serve.mjs +19 -0
- package/src/dashboard/index.html +5 -5
- package/start-live.mjs +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ope Olatunji (https://github.com/ope-olatunji)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
AgenticMail Enterprise - AI agent deployment platform for organizations.
|
|
26
|
+
Part of the AgenticMail project: https://github.com/agenticmail
|
package/README.md
CHANGED
|
@@ -96,13 +96,13 @@ Think of AgenticMail Enterprise as an HR department for AI agents.
|
|
|
96
96
|
|
|
97
97
|
```
|
|
98
98
|
┌──────────────────────────────────────────────────────┐
|
|
99
|
-
│ Dashboard (Web UI)
|
|
100
|
-
│ Single HTML · React 18 · CDN
|
|
99
|
+
│ Dashboard (Web UI) │
|
|
100
|
+
│ Single HTML · React 18 · CDN │
|
|
101
101
|
└─────────────────────────┬────────────────────────────┘
|
|
102
102
|
│ HTTP
|
|
103
103
|
┌─────────────────────────▼────────────────────────────┐
|
|
104
|
-
│ Hono API Server
|
|
105
|
-
│
|
|
104
|
+
│ Hono API Server │
|
|
105
|
+
│ │
|
|
106
106
|
│ ┌─────────┐ ┌──────────┐ ┌──────────────────────┐ │
|
|
107
107
|
│ │ Auth │ │ Admin │ │ Engine │ │
|
|
108
108
|
│ │ Routes │ │ Routes │ │ │ │
|
|
@@ -924,6 +924,16 @@ packages/enterprise/src/
|
|
|
924
924
|
|
|
925
925
|
---
|
|
926
926
|
|
|
927
|
+
## Author
|
|
928
|
+
|
|
929
|
+
Created by **[Ope Olatunji](https://github.com/ope-olatunji)**.
|
|
930
|
+
|
|
931
|
+
Part of the [AgenticMail](https://github.com/agenticmail/agenticmail) project — the first platform to give AI agents real email addresses and phone numbers.
|
|
932
|
+
|
|
933
|
+
- GitHub: [@ope-olatunji](https://github.com/ope-olatunji)
|
|
934
|
+
- Website: [agenticmail.io](https://agenticmail.io)
|
|
935
|
+
- Twitter: [@agenticmail](https://x.com/agenticmail)
|
|
936
|
+
|
|
927
937
|
## License
|
|
928
938
|
|
|
929
939
|
MIT — see [LICENSE](./LICENSE)
|
|
@@ -400,10 +400,10 @@
|
|
|
400
400
|
return h(Fragment, null,
|
|
401
401
|
h('div', { className: 'page-header' }, h('h1', { className: 'page-title' }, 'Dashboard'), h('p', { className: 'page-desc' }, 'System overview and recent activity')),
|
|
402
402
|
h('div', { className: 'stats-row' },
|
|
403
|
-
h(Stat, { label: 'Agents', value: stats?.agents ?? 0, color: 'accent', sub: '
|
|
404
|
-
h(Stat, { label: 'Users', value: stats?.users ?? 0 }),
|
|
405
|
-
h(Stat, { label: 'Emails
|
|
406
|
-
h(Stat, { label: 'Events', value: stats?.events ?? 0 }),
|
|
403
|
+
h(Stat, { label: 'Agents', value: stats?.totalAgents ?? stats?.agents ?? 0, color: 'accent', sub: (stats?.activeAgents ?? 0) + ' active' }),
|
|
404
|
+
h(Stat, { label: 'Users', value: stats?.totalUsers ?? stats?.users ?? 0 }),
|
|
405
|
+
h(Stat, { label: 'Emails', value: stats?.totalEmails ?? stats?.emails ?? 0, color: 'success' }),
|
|
406
|
+
h(Stat, { label: 'Events', value: stats?.totalAuditEvents ?? stats?.events ?? 0 }),
|
|
407
407
|
),
|
|
408
408
|
h('div', { className: 'card' },
|
|
409
409
|
h('div', { className: 'card-header' }, h('h3', null, 'Recent Activity')),
|
|
@@ -414,7 +414,7 @@
|
|
|
414
414
|
h('div', { className: 'activity-dot' }),
|
|
415
415
|
h('div', { className: 'activity-text' },
|
|
416
416
|
h('strong', null, e.action || e.type || 'Event'), ' ',
|
|
417
|
-
e.details
|
|
417
|
+
typeof e.details === 'string' ? e.details : e.description || JSON.stringify(e.details || e).slice(0, 80)
|
|
418
418
|
),
|
|
419
419
|
h('div', { className: 'activity-time' }, e.timestamp ? new Date(e.timestamp).toLocaleString() : '')
|
|
420
420
|
))
|
package/live-test.mjs
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live end-to-end test — starts server, runs all HTTP tests, shuts down.
|
|
3
|
+
*/
|
|
4
|
+
import { createAdapter, createServer } from './dist/index.js';
|
|
5
|
+
import { randomUUID } from 'crypto';
|
|
6
|
+
|
|
7
|
+
const PORT = 3201;
|
|
8
|
+
const BASE = `http://localhost:${PORT}`;
|
|
9
|
+
|
|
10
|
+
async function req(path, opts = {}) {
|
|
11
|
+
const res = await fetch(`${BASE}${path}`, {
|
|
12
|
+
headers: { 'Content-Type': 'application/json', ...opts.headers },
|
|
13
|
+
...opts,
|
|
14
|
+
});
|
|
15
|
+
return { status: res.status, data: await res.json().catch(() => null), headers: res.headers };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let pass = 0, fail = 0;
|
|
19
|
+
function ok(cond, name) { if (cond) { pass++; console.log(` ✅ ${name}`); } else { fail++; console.error(` ❌ ${name}`); } }
|
|
20
|
+
|
|
21
|
+
// ─── Setup ────────────────────────────────────
|
|
22
|
+
const db = await createAdapter({ type: 'sqlite', connectionString: ':memory:' });
|
|
23
|
+
await db.migrate();
|
|
24
|
+
const user = await db.createUser({ email: 'ope@agenticmail.io', name: 'Ope', role: 'owner', password: 'Test1234!' });
|
|
25
|
+
await db.updateSettings({ name: 'AgenticMail', subdomain: 'agenticmail', domain: 'agenticmail.io' });
|
|
26
|
+
const apiKey = (await db.createApiKey({ name: 'k', createdBy: user.id, scopes: ['read','write','admin'] })).plaintext;
|
|
27
|
+
|
|
28
|
+
const jwtSecret = randomUUID() + randomUUID();
|
|
29
|
+
const server = createServer({ port: PORT, db, jwtSecret, logging: false, rateLimit: 500 });
|
|
30
|
+
const handle = await server.start();
|
|
31
|
+
|
|
32
|
+
console.log('\n🏢 Live E2E Test — Enterprise Server on :' + PORT + '\n');
|
|
33
|
+
|
|
34
|
+
// ─── 1. Health ────────────────────────────────
|
|
35
|
+
console.log('─── Health & Ready ───');
|
|
36
|
+
const health = await req('/health');
|
|
37
|
+
ok(health.status === 200 && health.data?.status === 'ok', `GET /health → ${health.data?.status}`);
|
|
38
|
+
ok(health.data?.version === '0.3.0', `Version: ${health.data?.version}`);
|
|
39
|
+
|
|
40
|
+
const ready = await req('/ready');
|
|
41
|
+
ok(ready.status === 200, `GET /ready → ${ready.status}`);
|
|
42
|
+
|
|
43
|
+
// ─── 2. Auth ──────────────────────────────────
|
|
44
|
+
console.log('\n─── Auth ───');
|
|
45
|
+
const login = await req('/auth/login', { method: 'POST', body: JSON.stringify({ email: 'ope@agenticmail.io', password: 'Test1234!' }) });
|
|
46
|
+
ok(login.status === 200 && login.data?.token, 'Login → JWT token');
|
|
47
|
+
const jwt = login.data?.token;
|
|
48
|
+
|
|
49
|
+
const badLogin = await req('/auth/login', { method: 'POST', body: JSON.stringify({ email: 'ope@agenticmail.io', password: 'wrong' }) });
|
|
50
|
+
ok(badLogin.status === 401, 'Bad password → 401');
|
|
51
|
+
|
|
52
|
+
const noAuth = await req('/api/stats');
|
|
53
|
+
ok(noAuth.status === 401, 'No auth → 401');
|
|
54
|
+
|
|
55
|
+
const keyAuth = await req('/api/stats', { headers: { 'X-API-Key': apiKey } });
|
|
56
|
+
ok(keyAuth.status === 200, 'API key auth → 200');
|
|
57
|
+
|
|
58
|
+
const badKey = await req('/api/stats', { headers: { 'X-API-Key': 'ek_fake' } });
|
|
59
|
+
ok(badKey.status === 401, 'Bad API key → 401');
|
|
60
|
+
|
|
61
|
+
const auth = { Authorization: `Bearer ${jwt}` };
|
|
62
|
+
|
|
63
|
+
// ─── 3. Admin ─────────────────────────────────
|
|
64
|
+
console.log('\n─── Admin API ───');
|
|
65
|
+
const stats = await req('/api/stats', { headers: auth });
|
|
66
|
+
ok(stats.status === 200 && stats.data, `Stats: ${JSON.stringify(stats.data).slice(0, 80)}`);
|
|
67
|
+
|
|
68
|
+
// Create agent
|
|
69
|
+
const createAgent = await req('/api/agents', { method: 'POST', headers: auth, body: JSON.stringify({ name: 'support-bot', email: 'support@agenticmail.io', role: 'customer-support' }) });
|
|
70
|
+
ok(createAgent.status === 201, `Create agent → ${createAgent.status} (${createAgent.data?.name})`);
|
|
71
|
+
const agentId = createAgent.data?.id;
|
|
72
|
+
|
|
73
|
+
// List agents
|
|
74
|
+
const agents = await req('/api/agents', { headers: auth });
|
|
75
|
+
ok(agents.data?.agents?.length >= 1, `List agents → ${agents.data?.agents?.length}`);
|
|
76
|
+
|
|
77
|
+
// Get agent
|
|
78
|
+
const getAgent = await req(`/api/agents/${agentId}`, { headers: auth });
|
|
79
|
+
ok(getAgent.status === 200 && getAgent.data?.name === 'support-bot', 'Get agent by ID');
|
|
80
|
+
|
|
81
|
+
// Update agent
|
|
82
|
+
const updateAgent = await req(`/api/agents/${agentId}`, { method: 'PATCH', headers: auth, body: JSON.stringify({ role: 'lead-support' }) });
|
|
83
|
+
ok(updateAgent.status === 200 && updateAgent.data?.role === 'lead-support', 'Update agent role');
|
|
84
|
+
|
|
85
|
+
// Create second agent
|
|
86
|
+
const agent2 = await req('/api/agents', { method: 'POST', headers: auth, body: JSON.stringify({ name: 'research-bot', email: 'research@agenticmail.io', role: 'researcher' }) });
|
|
87
|
+
ok(agent2.status === 201, `Create second agent: ${agent2.data?.name}`);
|
|
88
|
+
|
|
89
|
+
// Users
|
|
90
|
+
const users = await req('/api/users', { headers: auth });
|
|
91
|
+
ok(users.status === 200, `List users → ${users.status}`);
|
|
92
|
+
|
|
93
|
+
// Audit log
|
|
94
|
+
const audit = await req('/api/audit', { headers: auth });
|
|
95
|
+
ok(audit.status === 200 && audit.data?.events?.length > 0, `Audit log → ${audit.data?.events?.length} events`);
|
|
96
|
+
|
|
97
|
+
// Settings
|
|
98
|
+
const settings = await req('/api/settings', { headers: auth });
|
|
99
|
+
ok(settings.status === 200 && settings.data?.name === 'AgenticMail', `Settings: ${settings.data?.name}`);
|
|
100
|
+
|
|
101
|
+
const patchSettings = await req('/api/settings', { method: 'PATCH', headers: auth, body: JSON.stringify({ name: 'AgenticMail Inc' }) });
|
|
102
|
+
ok(patchSettings.status === 200 && patchSettings.data?.name === 'AgenticMail Inc', 'Patch settings');
|
|
103
|
+
|
|
104
|
+
// Delete agent
|
|
105
|
+
const delAgent = await req(`/api/agents/${agent2.data?.id}`, { method: 'DELETE', headers: auth });
|
|
106
|
+
ok(delAgent.status === 200 || delAgent.status === 204, 'Delete agent');
|
|
107
|
+
|
|
108
|
+
// ─── 4. Engine ────────────────────────────────
|
|
109
|
+
console.log('\n─── Engine API ───');
|
|
110
|
+
const skills = await req('/api/engine/skills', { headers: auth });
|
|
111
|
+
ok(skills.status === 200, `Skills endpoint → ${skills.status}`);
|
|
112
|
+
const skillList = skills.data?.skills || skills.data || [];
|
|
113
|
+
ok(skillList.length >= 38, `${skillList.length} skills loaded`);
|
|
114
|
+
|
|
115
|
+
// Single skill
|
|
116
|
+
if (skillList.length) {
|
|
117
|
+
const s = await req(`/api/engine/skills/${skillList[0].id}`, { headers: auth });
|
|
118
|
+
ok(s.status === 200, `Get skill: ${s.data?.name || skillList[0].id}`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Presets
|
|
122
|
+
const presets = await req('/api/engine/profiles/presets', { headers: auth });
|
|
123
|
+
ok(presets.status === 200, 'Presets endpoint');
|
|
124
|
+
const presetList = presets.data?.presets || presets.data || [];
|
|
125
|
+
ok(presetList.length >= 5, `${presetList.length} presets`);
|
|
126
|
+
|
|
127
|
+
// Permission check
|
|
128
|
+
const permCheck = await req('/api/engine/permissions/check', { method: 'POST', headers: auth, body: JSON.stringify({ agentId: 'test', tool: 'web_search' }) });
|
|
129
|
+
ok(permCheck.status === 200, `Permission check → ${permCheck.status}`);
|
|
130
|
+
|
|
131
|
+
// Skills by category
|
|
132
|
+
const byCategory = await req('/api/engine/skills/by-category', { headers: auth });
|
|
133
|
+
ok(byCategory.status === 200, 'Skills by category');
|
|
134
|
+
|
|
135
|
+
// ─── 5. Dashboard ─────────────────────────────
|
|
136
|
+
console.log('\n─── Dashboard ───');
|
|
137
|
+
const dash = await fetch(`${BASE}/dashboard`);
|
|
138
|
+
ok(dash.status === 200, 'Dashboard serves');
|
|
139
|
+
const html = await dash.text();
|
|
140
|
+
ok(html.length > 1000 && html.includes('AgenticMail'), `Dashboard HTML: ${html.length} chars`);
|
|
141
|
+
|
|
142
|
+
const root = await fetch(`${BASE}/`, { redirect: 'manual' });
|
|
143
|
+
ok(root.status === 302, 'Root → /dashboard redirect');
|
|
144
|
+
|
|
145
|
+
// ─── 6. Security ──────────────────────────────
|
|
146
|
+
console.log('\n─── Security ───');
|
|
147
|
+
const secRes = await req('/health');
|
|
148
|
+
ok(secRes.headers.get('x-request-id'), 'X-Request-Id header');
|
|
149
|
+
ok(secRes.headers.get('x-content-type-options') === 'nosniff', 'nosniff header');
|
|
150
|
+
ok(secRes.headers.get('x-frame-options') === 'DENY', 'X-Frame-Options: DENY');
|
|
151
|
+
|
|
152
|
+
// 404 (outside /api so no auth wall)
|
|
153
|
+
const notFound = await req('/nonexistent-path');
|
|
154
|
+
ok(notFound.status === 404, '404 for unknown path');
|
|
155
|
+
|
|
156
|
+
// ─── Done ─────────────────────────────────────
|
|
157
|
+
handle.close();
|
|
158
|
+
server.healthMonitor.stop();
|
|
159
|
+
await db.disconnect();
|
|
160
|
+
|
|
161
|
+
console.log(`\n═══════════════════════════════════════`);
|
|
162
|
+
console.log(` ${pass} passed, ${fail} failed, ${pass + fail} total`);
|
|
163
|
+
console.log(`═══════════════════════════════════════`);
|
|
164
|
+
console.log(fail === 0 ? '\n✅ ALL LIVE TESTS PASSED\n' : '\n❌ SOME TESTS FAILED\n');
|
|
165
|
+
process.exit(fail > 0 ? 1 : 0);
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticmail/enterprise",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "AgenticMail Enterprise — cloud-hosted AI agent identity, email, auth & compliance for organizations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"agenticmail-enterprise": "
|
|
7
|
+
"agenticmail-enterprise": "dist/cli.js"
|
|
8
8
|
},
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
@@ -27,6 +27,15 @@
|
|
|
27
27
|
"scim",
|
|
28
28
|
"identity"
|
|
29
29
|
],
|
|
30
|
+
"author": "Ope Olatunji (https://github.com/ope-olatunji)",
|
|
31
|
+
"homepage": "https://github.com/agenticmail/enterprise",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/agenticmail/enterprise.git"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/agenticmail/enterprise/issues"
|
|
38
|
+
},
|
|
30
39
|
"license": "MIT",
|
|
31
40
|
"peerDependencies": {
|
|
32
41
|
"openclaw": ">=0.1.0",
|
package/serve.mjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createAdapter, createServer } from './dist/index.js';
|
|
2
|
+
import { randomUUID } from 'crypto';
|
|
3
|
+
|
|
4
|
+
const db = await createAdapter({ type: 'sqlite', connectionString: './enterprise-live.db' });
|
|
5
|
+
await db.migrate();
|
|
6
|
+
let user = await db.getUserByEmail('ope@agenticmail.io');
|
|
7
|
+
if (!user) {
|
|
8
|
+
user = await db.createUser({ email: 'ope@agenticmail.io', name: 'Ope Olatunji', role: 'owner', password: 'Enterprise2026!' });
|
|
9
|
+
await db.updateSettings({ name: 'AgenticMail', subdomain: 'agenticmail', domain: 'agenticmail.io' });
|
|
10
|
+
// Create some agents
|
|
11
|
+
await db.createAgent({ name: 'support-bot', email: 'support@agenticmail.io', role: 'customer-support', status: 'active', createdBy: user.id });
|
|
12
|
+
await db.createAgent({ name: 'research-bot', email: 'research@agenticmail.io', role: 'researcher', status: 'active', createdBy: user.id });
|
|
13
|
+
await db.createAgent({ name: 'writer-bot', email: 'writer@agenticmail.io', role: 'content-writer', status: 'active', createdBy: user.id });
|
|
14
|
+
console.log('✅ Seeded: admin + 3 agents');
|
|
15
|
+
}
|
|
16
|
+
const server = createServer({ port: 3200, db, jwtSecret: randomUUID()+randomUUID(), logging: true });
|
|
17
|
+
await server.start();
|
|
18
|
+
console.log('\nLogin: ope@agenticmail.io / Enterprise2026!');
|
|
19
|
+
setInterval(() => {}, 30000);
|
package/src/dashboard/index.html
CHANGED
|
@@ -400,10 +400,10 @@
|
|
|
400
400
|
return h(Fragment, null,
|
|
401
401
|
h('div', { className: 'page-header' }, h('h1', { className: 'page-title' }, 'Dashboard'), h('p', { className: 'page-desc' }, 'System overview and recent activity')),
|
|
402
402
|
h('div', { className: 'stats-row' },
|
|
403
|
-
h(Stat, { label: 'Agents', value: stats?.agents ?? 0, color: 'accent', sub: '
|
|
404
|
-
h(Stat, { label: 'Users', value: stats?.users ?? 0 }),
|
|
405
|
-
h(Stat, { label: 'Emails
|
|
406
|
-
h(Stat, { label: 'Events', value: stats?.events ?? 0 }),
|
|
403
|
+
h(Stat, { label: 'Agents', value: stats?.totalAgents ?? stats?.agents ?? 0, color: 'accent', sub: (stats?.activeAgents ?? 0) + ' active' }),
|
|
404
|
+
h(Stat, { label: 'Users', value: stats?.totalUsers ?? stats?.users ?? 0 }),
|
|
405
|
+
h(Stat, { label: 'Emails', value: stats?.totalEmails ?? stats?.emails ?? 0, color: 'success' }),
|
|
406
|
+
h(Stat, { label: 'Events', value: stats?.totalAuditEvents ?? stats?.events ?? 0 }),
|
|
407
407
|
),
|
|
408
408
|
h('div', { className: 'card' },
|
|
409
409
|
h('div', { className: 'card-header' }, h('h3', null, 'Recent Activity')),
|
|
@@ -414,7 +414,7 @@
|
|
|
414
414
|
h('div', { className: 'activity-dot' }),
|
|
415
415
|
h('div', { className: 'activity-text' },
|
|
416
416
|
h('strong', null, e.action || e.type || 'Event'), ' ',
|
|
417
|
-
e.details
|
|
417
|
+
typeof e.details === 'string' ? e.details : e.description || JSON.stringify(e.details || e).slice(0, 80)
|
|
418
418
|
),
|
|
419
419
|
h('div', { className: 'activity-time' }, e.timestamp ? new Date(e.timestamp).toLocaleString() : '')
|
|
420
420
|
))
|
package/start-live.mjs
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createAdapter, createServer } from './dist/index.js';
|
|
2
|
+
import { randomUUID } from 'crypto';
|
|
3
|
+
|
|
4
|
+
const db = await createAdapter({ type: 'sqlite', connectionString: './enterprise-live-test.db' });
|
|
5
|
+
await db.migrate();
|
|
6
|
+
console.log('✅ DB migrated');
|
|
7
|
+
|
|
8
|
+
// Check if admin already exists
|
|
9
|
+
let user = await db.getUserByEmail('ope@agenticmail.io');
|
|
10
|
+
if (!user) {
|
|
11
|
+
user = await db.createUser({
|
|
12
|
+
email: 'ope@agenticmail.io',
|
|
13
|
+
name: 'Ope Olatunji',
|
|
14
|
+
role: 'owner',
|
|
15
|
+
password: 'Enterprise2026!',
|
|
16
|
+
});
|
|
17
|
+
console.log('✅ Admin created:', user.id);
|
|
18
|
+
} else {
|
|
19
|
+
console.log('✅ Admin exists:', user.id);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
await db.updateSettings({ name: 'AgenticMail', subdomain: 'agenticmail', domain: 'agenticmail.io' });
|
|
23
|
+
console.log('✅ Company: AgenticMail / agenticmail.io');
|
|
24
|
+
|
|
25
|
+
const key = await db.createApiKey({ name: 'live-key', createdBy: user.id, scopes: ['read', 'write', 'admin'] });
|
|
26
|
+
console.log('✅ API Key:', key.plaintext);
|
|
27
|
+
|
|
28
|
+
const jwtSecret = randomUUID() + randomUUID();
|
|
29
|
+
const server = createServer({ port: 3200, db, jwtSecret, corsOrigins: ['*'], rateLimit: 200 });
|
|
30
|
+
await server.start();
|
|
31
|
+
|
|
32
|
+
console.log('');
|
|
33
|
+
console.log('Login: ope@agenticmail.io / Enterprise2026!');
|
|
34
|
+
console.log('Key: ', key.plaintext);
|
|
35
|
+
|
|
36
|
+
// Keep process alive
|
|
37
|
+
process.on('SIGINT', () => { console.log('\nShutting down...'); process.exit(0); });
|
|
38
|
+
process.on('SIGTERM', () => { console.log('\nShutting down...'); process.exit(0); });
|
|
39
|
+
setInterval(() => {}, 60000);
|