@agenticmail/enterprise 0.5.69 → 0.5.70

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.
@@ -0,0 +1,47 @@
1
+ import {
2
+ AgentRuntime,
3
+ EmailChannel,
4
+ FollowUpScheduler,
5
+ SessionManager,
6
+ SubAgentManager,
7
+ ToolRegistry,
8
+ callLLM,
9
+ createAgentRuntime,
10
+ createNoopHooks,
11
+ createRuntimeHooks,
12
+ estimateMessageTokens,
13
+ estimateTokens,
14
+ executeTool,
15
+ runAgentLoop,
16
+ toolsToDefinitions
17
+ } from "./chunk-SWD4HRGX.js";
18
+ import "./chunk-TYW5XTOW.js";
19
+ import "./chunk-JLSQOQ5L.js";
20
+ import {
21
+ PROVIDER_REGISTRY,
22
+ listAllProviders,
23
+ resolveApiKeyForProvider,
24
+ resolveProvider
25
+ } from "./chunk-67KZYSLU.js";
26
+ import "./chunk-KFQGP6VL.js";
27
+ export {
28
+ AgentRuntime,
29
+ EmailChannel,
30
+ FollowUpScheduler,
31
+ PROVIDER_REGISTRY,
32
+ SessionManager,
33
+ SubAgentManager,
34
+ ToolRegistry,
35
+ callLLM,
36
+ createAgentRuntime,
37
+ createNoopHooks,
38
+ createRuntimeHooks,
39
+ estimateMessageTokens,
40
+ estimateTokens,
41
+ executeTool,
42
+ listAllProviders,
43
+ resolveApiKeyForProvider,
44
+ resolveProvider,
45
+ runAgentLoop,
46
+ toolsToDefinitions
47
+ };
@@ -0,0 +1,12 @@
1
+ import {
2
+ createServer
3
+ } from "./chunk-5KWBRCXT.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-77QJHMFG.js";
10
+ import "./chunk-WP76IB36.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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticmail/enterprise",
3
- "version": "0.5.69",
3
+ "version": "0.5.70",
4
4
  "description": "AgenticMail Enterprise — cloud-hosted AI agent identity, email, auth & compliance for organizations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -3912,14 +3912,14 @@ function EmailSection(props) {
3912
3912
  oauthClientId: form.oauthClientId,
3913
3913
  oauthClientSecret: form.oauthClientSecret,
3914
3914
  oauthTenantId: form.oauthTenantId,
3915
- oauthRedirectUri: baseUrl + '/oauth/callback',
3915
+ oauthRedirectUri: baseUrl + '/api/engine/oauth/callback',
3916
3916
  });
3917
3917
  } else if (form.provider === 'google') {
3918
3918
  var gBaseUrl = window.location.origin;
3919
3919
  Object.assign(body, {
3920
3920
  oauthClientId: form.oauthClientId,
3921
3921
  oauthClientSecret: form.oauthClientSecret,
3922
- oauthRedirectUri: gBaseUrl + '/oauth/callback',
3922
+ oauthRedirectUri: gBaseUrl + '/api/engine/oauth/callback',
3923
3923
  });
3924
3924
  }
3925
3925
 
@@ -4098,7 +4098,7 @@ function EmailSection(props) {
4098
4098
  h('div', { style: { padding: '12px 16px', background: 'var(--info-soft)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--info)', marginBottom: 16 } },
4099
4099
  h('strong', null, 'Setup Instructions:'), h('br'),
4100
4100
  '1. Go to ', h('a', { href: 'https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade', target: '_blank', style: { color: 'var(--accent)' } }, 'Azure Portal → App Registrations'), h('br'),
4101
- '2. Click "New Registration" → name it (e.g., "AgenticMail Agent") → set redirect URI to: ', h('code', { style: { background: 'var(--bg-tertiary)', padding: '1px 4px', borderRadius: 3 } }, window.location.origin + '/oauth/callback'), h('br'),
4101
+ '2. Click "New Registration" → name it (e.g., "AgenticMail Agent") → set redirect URI to: ', h('code', { style: { background: 'var(--bg-tertiary)', padding: '1px 4px', borderRadius: 3 } }, window.location.origin + '/api/engine/oauth/callback'), h('br'),
4102
4102
  '3. Under "Certificates & Secrets" → create a Client Secret', h('br'),
4103
4103
  '4. Under "API Permissions" → add Microsoft Graph: Mail.ReadWrite, Mail.Send, offline_access', h('br'),
4104
4104
  '5. Copy the Application (client) ID and Client Secret below'
@@ -4132,7 +4132,7 @@ function EmailSection(props) {
4132
4132
  h('div', { style: { padding: '12px 16px', background: 'var(--info-soft)', borderRadius: 'var(--radius)', fontSize: 12, color: 'var(--info)', marginBottom: 16 } },
4133
4133
  h('strong', null, 'Setup Instructions:'), h('br'),
4134
4134
  '1. Go to ', h('a', { href: 'https://console.cloud.google.com/apis/credentials', target: '_blank', style: { color: 'var(--accent)' } }, 'Google Cloud Console → Credentials'), h('br'),
4135
- '2. Create an OAuth 2.0 Client ID (Web application) → add redirect URI: ', h('code', { style: { background: 'var(--bg-tertiary)', padding: '1px 4px', borderRadius: 3 } }, window.location.origin + '/oauth/callback'), h('br'),
4135
+ '2. Create an OAuth 2.0 Client ID (Web application) → add redirect URI: ', h('code', { style: { background: 'var(--bg-tertiary)', padding: '1px 4px', borderRadius: 3 } }, window.location.origin + '/api/engine/oauth/callback'), h('br'),
4136
4136
  '3. Enable the Gmail API in your project', h('br'),
4137
4137
  '4. Copy the Client ID and Client Secret below'
4138
4138
  ),
@@ -68,7 +68,7 @@ async function findVaultEntryByName(
68
68
 
69
69
  // ─── Route Factory ──────────────────────────────────────
70
70
 
71
- export function createOAuthConnectRoutes(vault: SecureVault) {
71
+ export function createOAuthConnectRoutes(vault: SecureVault, lifecycle?: any) {
72
72
  const router = new Hono();
73
73
 
74
74
  // ─── GET /authorize/:skillId — Start OAuth flow ─────
@@ -195,9 +195,16 @@ export function createOAuthConnectRoutes(vault: SecureVault) {
195
195
  return c.html(oauthResultPage(false, 'Missing code or state parameter'));
196
196
  }
197
197
 
198
- // Validate state
198
+ // Validate state — check skill OAuth states first, then agent email OAuth
199
199
  const pending = pendingOAuthStates.get(state);
200
200
  if (!pending) {
201
+ // Check if state is an agent ID (agent email OAuth flow)
202
+ if (lifecycle) {
203
+ const managed = lifecycle.getAgent(state);
204
+ if (managed?.config?.emailConfig?.status === 'awaiting_oauth') {
205
+ return await handleAgentEmailOAuthCallback(c, state, code, managed, lifecycle);
206
+ }
207
+ }
201
208
  return c.html(oauthResultPage(false, 'Invalid or expired OAuth state'));
202
209
  }
203
210
 
@@ -338,6 +345,95 @@ export function createOAuthConnectRoutes(vault: SecureVault) {
338
345
  return router;
339
346
  }
340
347
 
348
+ // ─── Agent Email OAuth Callback Handler ─────────────────
349
+
350
+ async function handleAgentEmailOAuthCallback(c: any, agentId: string, code: string, managed: any, lifecycle: any) {
351
+ const emailConfig = managed.config.emailConfig;
352
+ try {
353
+ if (emailConfig.oauthProvider === 'microsoft') {
354
+ const tokenRes = await fetch(`https://login.microsoftonline.com/${emailConfig.oauthTenantId || 'common'}/oauth2/v2.0/token`, {
355
+ method: 'POST',
356
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
357
+ body: new URLSearchParams({
358
+ client_id: emailConfig.oauthClientId,
359
+ client_secret: emailConfig.oauthClientSecret,
360
+ code,
361
+ redirect_uri: emailConfig.oauthRedirectUri,
362
+ grant_type: 'authorization_code',
363
+ scope: emailConfig.oauthScopes.join(' '),
364
+ }),
365
+ });
366
+ if (!tokenRes.ok) {
367
+ const errText = await tokenRes.text();
368
+ return c.html(oauthResultPage(false, `Microsoft token exchange failed: ${errText}`));
369
+ }
370
+ const tokens = await tokenRes.json() as any;
371
+ emailConfig.oauthAccessToken = tokens.access_token;
372
+ emailConfig.oauthRefreshToken = tokens.refresh_token;
373
+ emailConfig.oauthTokenExpiry = new Date(Date.now() + (tokens.expires_in * 1000)).toISOString();
374
+
375
+ // Get user email from Graph
376
+ try {
377
+ const profileRes = await fetch('https://graph.microsoft.com/v1.0/me?$select=mail,displayName', {
378
+ headers: { Authorization: `Bearer ${tokens.access_token}` },
379
+ });
380
+ if (profileRes.ok) {
381
+ const profile = await profileRes.json() as any;
382
+ if (profile.mail) emailConfig.email = profile.mail;
383
+ }
384
+ } catch {}
385
+
386
+ } else if (emailConfig.oauthProvider === 'google') {
387
+ const tokenRes = await fetch('https://oauth2.googleapis.com/token', {
388
+ method: 'POST',
389
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
390
+ body: new URLSearchParams({
391
+ client_id: emailConfig.oauthClientId,
392
+ client_secret: emailConfig.oauthClientSecret,
393
+ code,
394
+ redirect_uri: emailConfig.oauthRedirectUri,
395
+ grant_type: 'authorization_code',
396
+ }),
397
+ });
398
+ if (!tokenRes.ok) {
399
+ const errText = await tokenRes.text();
400
+ return c.html(oauthResultPage(false, `Google token exchange failed: ${errText}`));
401
+ }
402
+ const tokens = await tokenRes.json() as any;
403
+ emailConfig.oauthAccessToken = tokens.access_token;
404
+ emailConfig.oauthRefreshToken = tokens.refresh_token;
405
+ emailConfig.oauthTokenExpiry = tokens.expires_in
406
+ ? new Date(Date.now() + (tokens.expires_in * 1000)).toISOString()
407
+ : undefined;
408
+
409
+ // Get user email from Google
410
+ try {
411
+ const profileRes = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
412
+ headers: { Authorization: `Bearer ${tokens.access_token}` },
413
+ });
414
+ if (profileRes.ok) {
415
+ const profile = await profileRes.json() as any;
416
+ if (profile.email) emailConfig.email = profile.email;
417
+ }
418
+ } catch {}
419
+
420
+ } else {
421
+ return c.html(oauthResultPage(false, `Unknown OAuth provider: ${emailConfig.oauthProvider}`));
422
+ }
423
+
424
+ emailConfig.status = 'connected';
425
+ emailConfig.configured = true;
426
+ delete emailConfig.oauthAuthUrl;
427
+ managed.config.emailConfig = emailConfig;
428
+ managed.updatedAt = new Date().toISOString();
429
+ await lifecycle.saveAgent(agentId);
430
+
431
+ return c.html(oauthResultPage(true, `Email connected via ${emailConfig.oauthProvider === 'google' ? 'Google' : 'Microsoft'} OAuth`));
432
+ } catch (e: any) {
433
+ return c.html(oauthResultPage(false, e.message || 'OAuth token exchange failed'));
434
+ }
435
+ }
436
+
341
437
  // ─── HTML Callback Page ─────────────────────────────────
342
438
 
343
439
  /**
@@ -214,7 +214,7 @@ engine.route('/storage', createStorageRoutes(storageManager));
214
214
  engine.route('/policies', createPolicyImportRoutes(policyImporter));
215
215
  engine.route('/knowledge-contribution', createKnowledgeContributionRoutes(knowledgeContribution));
216
216
  engine.route('/skill-updates', createSkillUpdaterRoutes(skillUpdater));
217
- engine.route('/oauth', createOAuthConnectRoutes(vault));
217
+ engine.route('/oauth', createOAuthConnectRoutes(vault, lifecycle));
218
218
 
219
219
  // ─── setEngineDb ────────────────────────────────────────
220
220
 
package/src/server.ts CHANGED
@@ -177,6 +177,11 @@ export function createServer(config: ServerConfig): ServerInstance {
177
177
 
178
178
  // Authentication middleware
179
179
  api.use('*', async (c, next) => {
180
+ // Skip auth for OAuth callback (browser redirect from Google/Microsoft)
181
+ if (c.req.path.endsWith('/oauth/callback') && c.req.method === 'GET') {
182
+ return next();
183
+ }
184
+
180
185
  // Check API key first
181
186
  const apiKeyHeader = c.req.header('X-API-Key');
182
187
  if (apiKeyHeader) {