@agenticmail/enterprise 0.2.1 → 0.3.0

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.
Files changed (41) hide show
  1. package/README.md +929 -0
  2. package/dashboards/dotnet/Program.cs +5 -5
  3. package/dashboards/express/app.js +5 -5
  4. package/dashboards/go/main.go +8 -8
  5. package/dashboards/html/index.html +41 -18
  6. package/dashboards/java/AgenticMailDashboard.java +5 -5
  7. package/dashboards/php/index.php +8 -8
  8. package/dashboards/python/app.py +8 -8
  9. package/dashboards/ruby/app.rb +7 -7
  10. package/dashboards/shared-styles.css +57 -0
  11. package/dist/{chunk-LCUZGIDH.js → chunk-BE7MXVLA.js} +48 -256
  12. package/dist/chunk-BS2WCSHO.js +48 -0
  13. package/dist/chunk-FL3VQBGL.js +757 -0
  14. package/dist/chunk-GXIEEA2T.js +48 -0
  15. package/dist/chunk-JLSQOQ5L.js +255 -0
  16. package/dist/{chunk-O462UJBH.js → chunk-TVF23PUW.js} +23 -48
  17. package/dist/{chunk-DXNKR3TG.js → chunk-YFDSE4BW.js} +1 -1
  18. package/dist/cli.js +305 -140
  19. package/dist/dashboard/index.html +833 -510
  20. package/dist/factory-HINWFYZ3.js +9 -0
  21. package/dist/factory-V37IG5AT.js +9 -0
  22. package/dist/index.js +18 -12
  23. package/dist/managed-RZITNPXG.js +14 -0
  24. package/dist/{server.js → server-32YYCI3A.js} +2 -1
  25. package/dist/server-H3C6WUOS.js +8 -0
  26. package/dist/sqlite-VLKVAJA4.js +442 -0
  27. package/package.json +18 -2
  28. package/src/cli.ts +15 -251
  29. package/src/dashboard/index.html +833 -510
  30. package/src/db/sqlite.ts +4 -1
  31. package/src/server.ts +1 -1
  32. package/src/setup/company.ts +64 -0
  33. package/src/setup/database.ts +119 -0
  34. package/src/setup/deployment.ts +50 -0
  35. package/src/setup/domain.ts +46 -0
  36. package/src/setup/index.ts +82 -0
  37. package/src/setup/provision.ts +226 -0
  38. package/test-integration.mjs +383 -0
  39. package/agenticmail-enterprise.db +0 -0
  40. package/dist/engine/index.js +0 -1261
  41. package/dist/routes-74ZLKJKP.js +0 -399
@@ -0,0 +1,48 @@
1
+ // src/db/factory.ts
2
+ var ADAPTER_MAP = {
3
+ postgres: () => import("./postgres-LN7A6MGQ.js").then((m) => m.PostgresAdapter),
4
+ supabase: () => import("./postgres-LN7A6MGQ.js").then((m) => m.PostgresAdapter),
5
+ // Supabase IS Postgres
6
+ neon: () => import("./postgres-LN7A6MGQ.js").then((m) => m.PostgresAdapter),
7
+ // Neon IS Postgres
8
+ cockroachdb: () => import("./postgres-LN7A6MGQ.js").then((m) => m.PostgresAdapter),
9
+ // CockroachDB is PG-compatible
10
+ mysql: () => import("./mysql-RM3S2FV5.js").then((m) => m.MysqlAdapter),
11
+ planetscale: () => import("./mysql-RM3S2FV5.js").then((m) => m.MysqlAdapter),
12
+ // PlanetScale IS MySQL
13
+ mongodb: () => import("./mongodb-ODTXIVPV.js").then((m) => m.MongoAdapter),
14
+ sqlite: () => import("./sqlite-3K5YOZ4K.js").then((m) => m.SqliteAdapter),
15
+ turso: () => import("./turso-LDWODSDI.js").then((m) => m.TursoAdapter),
16
+ dynamodb: () => import("./dynamodb-CCGL2E77.js").then((m) => m.DynamoAdapter)
17
+ };
18
+ async function createAdapter(config) {
19
+ const loader = ADAPTER_MAP[config.type];
20
+ if (!loader) {
21
+ throw new Error(
22
+ `Unsupported database type: "${config.type}". Supported: ${Object.keys(ADAPTER_MAP).join(", ")}`
23
+ );
24
+ }
25
+ const AdapterClass = await loader();
26
+ const adapter = new AdapterClass();
27
+ await adapter.connect(config);
28
+ return adapter;
29
+ }
30
+ function getSupportedDatabases() {
31
+ return [
32
+ { type: "postgres", label: "PostgreSQL", group: "SQL" },
33
+ { type: "mysql", label: "MySQL / MariaDB", group: "SQL" },
34
+ { type: "sqlite", label: "SQLite (embedded, dev/small)", group: "SQL" },
35
+ { type: "mongodb", label: "MongoDB", group: "NoSQL" },
36
+ { type: "turso", label: "Turso (LibSQL, edge)", group: "Edge" },
37
+ { type: "dynamodb", label: "DynamoDB (AWS)", group: "Cloud" },
38
+ { type: "supabase", label: "Supabase (managed Postgres)", group: "Cloud" },
39
+ { type: "neon", label: "Neon (serverless Postgres)", group: "Cloud" },
40
+ { type: "planetscale", label: "PlanetScale (managed MySQL)", group: "Cloud" },
41
+ { type: "cockroachdb", label: "CockroachDB", group: "Distributed" }
42
+ ];
43
+ }
44
+
45
+ export {
46
+ createAdapter,
47
+ getSupportedDatabases
48
+ };
@@ -0,0 +1,255 @@
1
+ // src/lib/resilience.ts
2
+ var DEFAULT_RETRY = {
3
+ maxAttempts: 3,
4
+ baseDelayMs: 500,
5
+ maxDelayMs: 3e4,
6
+ backoffMultiplier: 2
7
+ };
8
+ async function withRetry(fn, opts = {}) {
9
+ const config = { ...DEFAULT_RETRY, ...opts };
10
+ let lastError = new Error("No attempts made");
11
+ for (let attempt = 1; attempt <= config.maxAttempts; attempt++) {
12
+ try {
13
+ return await fn();
14
+ } catch (err) {
15
+ lastError = err;
16
+ if (attempt === config.maxAttempts) break;
17
+ if (config.retryableErrors && !config.retryableErrors(err)) break;
18
+ const delay = Math.min(
19
+ config.baseDelayMs * Math.pow(config.backoffMultiplier, attempt - 1) + Math.random() * 200,
20
+ config.maxDelayMs
21
+ );
22
+ config.onRetry?.(attempt, err, delay);
23
+ await sleep(delay);
24
+ }
25
+ }
26
+ throw lastError;
27
+ }
28
+ var CircuitBreaker = class {
29
+ state = "closed";
30
+ failures = 0;
31
+ successes = 0;
32
+ lastFailureTime = 0;
33
+ opts;
34
+ constructor(opts = {}) {
35
+ this.opts = {
36
+ failureThreshold: opts.failureThreshold ?? 5,
37
+ recoveryTimeMs: opts.recoveryTimeMs ?? 3e4,
38
+ successThreshold: opts.successThreshold ?? 2,
39
+ timeout: opts.timeout
40
+ };
41
+ }
42
+ async execute(fn) {
43
+ if (this.state === "open") {
44
+ if (Date.now() - this.lastFailureTime >= this.opts.recoveryTimeMs) {
45
+ this.state = "half-open";
46
+ this.successes = 0;
47
+ } else {
48
+ throw new CircuitOpenError(
49
+ `Circuit breaker is open. Retry after ${this.opts.recoveryTimeMs}ms`
50
+ );
51
+ }
52
+ }
53
+ try {
54
+ const result = this.opts.timeout ? await withTimeout(fn(), this.opts.timeout) : await fn();
55
+ this.onSuccess();
56
+ return result;
57
+ } catch (err) {
58
+ this.onFailure();
59
+ throw err;
60
+ }
61
+ }
62
+ onSuccess() {
63
+ if (this.state === "half-open") {
64
+ this.successes++;
65
+ if (this.successes >= this.opts.successThreshold) {
66
+ this.state = "closed";
67
+ this.failures = 0;
68
+ }
69
+ } else {
70
+ this.failures = 0;
71
+ }
72
+ }
73
+ onFailure() {
74
+ this.failures++;
75
+ this.lastFailureTime = Date.now();
76
+ if (this.failures >= this.opts.failureThreshold) {
77
+ this.state = "open";
78
+ }
79
+ }
80
+ getState() {
81
+ return this.state;
82
+ }
83
+ reset() {
84
+ this.state = "closed";
85
+ this.failures = 0;
86
+ this.successes = 0;
87
+ }
88
+ };
89
+ var CircuitOpenError = class extends Error {
90
+ constructor(message) {
91
+ super(message);
92
+ this.name = "CircuitOpenError";
93
+ }
94
+ };
95
+ var RateLimiter = class {
96
+ tokens;
97
+ lastRefill;
98
+ opts;
99
+ constructor(opts) {
100
+ this.opts = {
101
+ maxTokens: opts.maxTokens,
102
+ refillRate: opts.refillRate,
103
+ refillIntervalMs: opts.refillIntervalMs ?? 1e3
104
+ };
105
+ this.tokens = this.opts.maxTokens;
106
+ this.lastRefill = Date.now();
107
+ }
108
+ /**
109
+ * Try to consume a token. Returns true if allowed, false if rate limited.
110
+ */
111
+ tryConsume(count = 1) {
112
+ this.refill();
113
+ if (this.tokens >= count) {
114
+ this.tokens -= count;
115
+ return true;
116
+ }
117
+ return false;
118
+ }
119
+ /**
120
+ * Get time in ms until next token is available.
121
+ */
122
+ getRetryAfterMs() {
123
+ this.refill();
124
+ if (this.tokens >= 1) return 0;
125
+ const tokensNeeded = 1 - this.tokens;
126
+ return Math.ceil(tokensNeeded / this.opts.refillRate * 1e3);
127
+ }
128
+ refill() {
129
+ const now = Date.now();
130
+ const elapsed = now - this.lastRefill;
131
+ const tokensToAdd = elapsed / 1e3 * this.opts.refillRate;
132
+ this.tokens = Math.min(this.opts.maxTokens, this.tokens + tokensToAdd);
133
+ this.lastRefill = now;
134
+ }
135
+ };
136
+ var KeyedRateLimiter = class {
137
+ limiters = /* @__PURE__ */ new Map();
138
+ opts;
139
+ cleanupTimer = null;
140
+ constructor(opts) {
141
+ this.opts = opts;
142
+ this.cleanupTimer = setInterval(() => this.cleanup(), 5 * 6e4);
143
+ if (this.cleanupTimer && typeof this.cleanupTimer === "object" && "unref" in this.cleanupTimer) {
144
+ this.cleanupTimer.unref();
145
+ }
146
+ }
147
+ tryConsume(key, count = 1) {
148
+ let limiter = this.limiters.get(key);
149
+ if (!limiter) {
150
+ limiter = new RateLimiter(this.opts);
151
+ this.limiters.set(key, limiter);
152
+ }
153
+ return limiter.tryConsume(count);
154
+ }
155
+ getRetryAfterMs(key) {
156
+ const limiter = this.limiters.get(key);
157
+ return limiter ? limiter.getRetryAfterMs() : 0;
158
+ }
159
+ cleanup() {
160
+ for (const [key, limiter] of this.limiters) {
161
+ if (limiter.getRetryAfterMs() === 0) {
162
+ this.limiters.delete(key);
163
+ }
164
+ }
165
+ }
166
+ destroy() {
167
+ if (this.cleanupTimer) clearInterval(this.cleanupTimer);
168
+ this.limiters.clear();
169
+ }
170
+ };
171
+ var HealthMonitor = class {
172
+ healthy = true;
173
+ consecutiveFailures = 0;
174
+ consecutiveSuccesses = 0;
175
+ timer = null;
176
+ check;
177
+ opts;
178
+ listeners = [];
179
+ constructor(check, opts = {}) {
180
+ this.check = check;
181
+ this.opts = {
182
+ intervalMs: opts.intervalMs ?? 3e4,
183
+ timeoutMs: opts.timeoutMs ?? 5e3,
184
+ unhealthyThreshold: opts.unhealthyThreshold ?? 3,
185
+ healthyThreshold: opts.healthyThreshold ?? 2
186
+ };
187
+ }
188
+ start() {
189
+ if (this.timer) return;
190
+ this.timer = setInterval(() => this.runCheck(), this.opts.intervalMs);
191
+ if (this.timer && typeof this.timer === "object" && "unref" in this.timer) {
192
+ this.timer.unref();
193
+ }
194
+ }
195
+ stop() {
196
+ if (this.timer) {
197
+ clearInterval(this.timer);
198
+ this.timer = null;
199
+ }
200
+ }
201
+ isHealthy() {
202
+ return this.healthy;
203
+ }
204
+ onStatusChange(fn) {
205
+ this.listeners.push(fn);
206
+ }
207
+ async runCheck() {
208
+ try {
209
+ await withTimeout(this.check(), this.opts.timeoutMs);
210
+ this.consecutiveFailures = 0;
211
+ this.consecutiveSuccesses++;
212
+ if (!this.healthy && this.consecutiveSuccesses >= this.opts.healthyThreshold) {
213
+ this.healthy = true;
214
+ this.listeners.forEach((fn) => fn(true));
215
+ }
216
+ } catch {
217
+ this.consecutiveSuccesses = 0;
218
+ this.consecutiveFailures++;
219
+ if (this.healthy && this.consecutiveFailures >= this.opts.unhealthyThreshold) {
220
+ this.healthy = false;
221
+ this.listeners.forEach((fn) => fn(false));
222
+ }
223
+ }
224
+ }
225
+ };
226
+ function sleep(ms) {
227
+ return new Promise((resolve) => setTimeout(resolve, ms));
228
+ }
229
+ function withTimeout(promise, ms) {
230
+ return new Promise((resolve, reject) => {
231
+ const timer = setTimeout(() => reject(new Error(`Operation timed out after ${ms}ms`)), ms);
232
+ promise.then((v) => {
233
+ clearTimeout(timer);
234
+ resolve(v);
235
+ }).catch((e) => {
236
+ clearTimeout(timer);
237
+ reject(e);
238
+ });
239
+ });
240
+ }
241
+ var counter = 0;
242
+ var prefix = Math.random().toString(36).substring(2, 8);
243
+ function requestId() {
244
+ return `${prefix}-${(++counter).toString(36)}-${Date.now().toString(36)}`;
245
+ }
246
+
247
+ export {
248
+ withRetry,
249
+ CircuitBreaker,
250
+ CircuitOpenError,
251
+ RateLimiter,
252
+ KeyedRateLimiter,
253
+ HealthMonitor,
254
+ requestId
255
+ };
@@ -1,50 +1,6 @@
1
1
  import {
2
2
  withRetry
3
- } from "./chunk-LCUZGIDH.js";
4
-
5
- // src/db/factory.ts
6
- var ADAPTER_MAP = {
7
- postgres: () => import("./postgres-LN7A6MGQ.js").then((m) => m.PostgresAdapter),
8
- supabase: () => import("./postgres-LN7A6MGQ.js").then((m) => m.PostgresAdapter),
9
- // Supabase IS Postgres
10
- neon: () => import("./postgres-LN7A6MGQ.js").then((m) => m.PostgresAdapter),
11
- // Neon IS Postgres
12
- cockroachdb: () => import("./postgres-LN7A6MGQ.js").then((m) => m.PostgresAdapter),
13
- // CockroachDB is PG-compatible
14
- mysql: () => import("./mysql-RM3S2FV5.js").then((m) => m.MysqlAdapter),
15
- planetscale: () => import("./mysql-RM3S2FV5.js").then((m) => m.MysqlAdapter),
16
- // PlanetScale IS MySQL
17
- mongodb: () => import("./mongodb-ODTXIVPV.js").then((m) => m.MongoAdapter),
18
- sqlite: () => import("./sqlite-3K5YOZ4K.js").then((m) => m.SqliteAdapter),
19
- turso: () => import("./turso-LDWODSDI.js").then((m) => m.TursoAdapter),
20
- dynamodb: () => import("./dynamodb-CCGL2E77.js").then((m) => m.DynamoAdapter)
21
- };
22
- async function createAdapter(config) {
23
- const loader = ADAPTER_MAP[config.type];
24
- if (!loader) {
25
- throw new Error(
26
- `Unsupported database type: "${config.type}". Supported: ${Object.keys(ADAPTER_MAP).join(", ")}`
27
- );
28
- }
29
- const AdapterClass = await loader();
30
- const adapter = new AdapterClass();
31
- await adapter.connect(config);
32
- return adapter;
33
- }
34
- function getSupportedDatabases() {
35
- return [
36
- { type: "postgres", label: "PostgreSQL", group: "SQL" },
37
- { type: "mysql", label: "MySQL / MariaDB", group: "SQL" },
38
- { type: "sqlite", label: "SQLite (embedded, dev/small)", group: "SQL" },
39
- { type: "mongodb", label: "MongoDB", group: "NoSQL" },
40
- { type: "turso", label: "Turso (LibSQL, edge)", group: "Edge" },
41
- { type: "dynamodb", label: "DynamoDB (AWS)", group: "Cloud" },
42
- { type: "supabase", label: "Supabase (managed Postgres)", group: "Cloud" },
43
- { type: "neon", label: "Neon (serverless Postgres)", group: "Cloud" },
44
- { type: "planetscale", label: "PlanetScale (managed MySQL)", group: "Cloud" },
45
- { type: "cockroachdb", label: "CockroachDB", group: "Distributed" }
46
- ];
47
- }
3
+ } from "./chunk-JLSQOQ5L.js";
48
4
 
49
5
  // src/deploy/fly.ts
50
6
  var FLY_API = "https://api.machines.dev";
@@ -353,11 +309,30 @@ primary_region = "${region}"
353
309
  memory = "256mb"
354
310
  `;
355
311
  }
312
+ function generateRailwayConfig() {
313
+ return `# AgenticMail Enterprise \u2014 Railway Config
314
+ # Generated at ${(/* @__PURE__ */ new Date()).toISOString()}
315
+ #
316
+ # Deploy:
317
+ # railway init
318
+ # railway link
319
+ # railway up
320
+
321
+ [build]
322
+ builder = "DOCKERFILE"
323
+ dockerfilePath = "Dockerfile"
324
+
325
+ [deploy]
326
+ healthcheckPath = "/health"
327
+ healthcheckTimeout = 10
328
+ restartPolicyType = "ON_FAILURE"
329
+ restartPolicyMaxRetries = 3
330
+ `;
331
+ }
356
332
 
357
333
  export {
358
- createAdapter,
359
- getSupportedDatabases,
360
334
  deployToCloud,
361
335
  generateDockerCompose,
362
- generateFlyToml
336
+ generateFlyToml,
337
+ generateRailwayConfig
363
338
  };
@@ -857,7 +857,7 @@ function createServer(config) {
857
857
  }
858
858
  app.get("/health", (c) => c.json({
859
859
  status: "ok",
860
- version: "0.2.0",
860
+ version: "0.2.2",
861
861
  uptime: process.uptime()
862
862
  }));
863
863
  app.get("/ready", async (c) => {