emailengine-app 2.61.3 → 2.61.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.61.4](https://github.com/postalsys/emailengine/compare/v2.61.3...v2.61.4) (2026-01-14)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * handle delegation errors in loadAccountData, isApiClient, and UI listing ([c306618](https://github.com/postalsys/emailengine/commit/c306618a37428bbf088ed1289bf832e778f14b9c))
9
+ * show Failed status for accounts with IMAP disabled due to auth errors ([e6b687d](https://github.com/postalsys/emailengine/commit/e6b687d458cfd080795f7176f862109e2c299fff))
10
+
3
11
  ## [2.61.3](https://github.com/postalsys/emailengine/compare/v2.61.2...v2.61.3) (2026-01-14)
4
12
 
5
13
 
package/lib/account.js CHANGED
@@ -697,20 +697,30 @@ class Account {
697
697
  accountData._app = app;
698
698
  }
699
699
  } else if (accountData.oauth2 && accountData.oauth2.auth && accountData.oauth2.auth.delegatedAccount) {
700
- let delegatedAccount = await resolveDelegatedAccount(this.redis, accountData.account);
701
- if (delegatedAccount) {
702
- accountData.delegatedAccount = delegatedAccount;
703
- let delegatedAccountRow = await this.redis.hgetall(`${REDIS_PREFIX}iad:${delegatedAccount}`);
704
- let delegatedAccountData = this.unserializeAccountData(delegatedAccountRow);
705
- if (delegatedAccountData.oauth2 && delegatedAccountData.oauth2.provider) {
706
- let app = await oauth2Apps.get(delegatedAccountData.oauth2.provider);
707
- if (app) {
708
- accountData._app = app;
709
- if (app.baseScopes === 'api') {
710
- accountData.isApi = true;
700
+ try {
701
+ let delegatedAccount = await resolveDelegatedAccount(this.redis, accountData.account);
702
+ if (delegatedAccount) {
703
+ accountData.delegatedAccount = delegatedAccount;
704
+ let delegatedAccountRow = await this.redis.hgetall(`${REDIS_PREFIX}iad:${delegatedAccount}`);
705
+ let delegatedAccountData = this.unserializeAccountData(delegatedAccountRow);
706
+ if (delegatedAccountData.oauth2 && delegatedAccountData.oauth2.provider) {
707
+ let app = await oauth2Apps.get(delegatedAccountData.oauth2.provider);
708
+ if (app) {
709
+ accountData._app = app;
710
+ if (app.baseScopes === 'api') {
711
+ accountData.isApi = true;
712
+ }
711
713
  }
712
714
  }
713
715
  }
716
+ } catch (err) {
717
+ this.logger.warn({
718
+ msg: 'Failed to resolve delegated account',
719
+ account: accountData.account,
720
+ delegatedAccount: accountData.oauth2.auth.delegatedAccount,
721
+ err
722
+ });
723
+ accountData.delegationError = err.message;
714
724
  }
715
725
  }
716
726
 
@@ -2545,17 +2555,22 @@ class Account {
2545
2555
 
2546
2556
  async isApiClient(accountData) {
2547
2557
  if (accountData.oauth2?.auth?.delegatedAccount) {
2548
- let delegatedAccount = await resolveDelegatedAccount(this.redis, accountData.account);
2549
- if (delegatedAccount) {
2550
- accountData.delegatedAccount = delegatedAccount;
2551
- let delegatedAccountRow = await this.redis.hgetall(`${REDIS_PREFIX}iad:${delegatedAccount}`);
2552
- let delegatedAccountData = this.unserializeAccountData(delegatedAccountRow);
2553
- if (delegatedAccountData?.oauth2?.provider) {
2554
- let app = await oauth2Apps.get(delegatedAccountData.oauth2.provider);
2555
- return app?.baseScopes === 'api';
2556
- } else {
2557
- return false;
2558
+ try {
2559
+ let delegatedAccount = await resolveDelegatedAccount(this.redis, accountData.account);
2560
+ if (delegatedAccount) {
2561
+ accountData.delegatedAccount = delegatedAccount;
2562
+ let delegatedAccountRow = await this.redis.hgetall(`${REDIS_PREFIX}iad:${delegatedAccount}`);
2563
+ let delegatedAccountData = this.unserializeAccountData(delegatedAccountRow);
2564
+ if (delegatedAccountData?.oauth2?.provider) {
2565
+ let app = await oauth2Apps.get(delegatedAccountData.oauth2.provider);
2566
+ return app?.baseScopes === 'api';
2567
+ } else {
2568
+ return false;
2569
+ }
2558
2570
  }
2571
+ } catch (err) {
2572
+ // Invalid delegation config - treat as non-API client
2573
+ return false;
2559
2574
  }
2560
2575
  }
2561
2576
 
package/lib/routes-ui.js CHANGED
@@ -618,6 +618,15 @@ function formatAccountData(account, gt) {
618
618
  break;
619
619
  }
620
620
 
621
+ // Check if IMAP was disabled due to errors - override state label to show error
622
+ if (account.imap && account.imap.disabled && account.lastErrorState) {
623
+ account.stateLabel = {
624
+ type: 'danger',
625
+ name: 'Failed',
626
+ error: account.lastErrorState.description || account.lastErrorState.response
627
+ };
628
+ }
629
+
621
630
  if (account.oauth2) {
622
631
  account.oauth2.scopes = []
623
632
  .concat(account.oauth2.scope || [])
@@ -4157,13 +4166,20 @@ ${Buffer.from(data.content, 'base64url').toString('base64')}
4157
4166
 
4158
4167
  for (let account of accounts.accounts) {
4159
4168
  let accountObject = new Account({ redis, account: account.account });
4160
- account.data = await accountObject.loadAccountData(null, null, runIndex);
4169
+ try {
4170
+ account.data = await accountObject.loadAccountData(null, null, runIndex);
4161
4171
 
4162
- if (account.data && account.data.oauth2 && account.data.oauth2.provider) {
4163
- let oauth2App = await oauth2Apps.get(account.data.oauth2.provider);
4164
- if (oauth2App) {
4165
- account.data.oauth2.app = oauth2App;
4172
+ if (account.data && account.data.oauth2 && account.data.oauth2.provider) {
4173
+ let oauth2App = await oauth2Apps.get(account.data.oauth2.provider);
4174
+ if (oauth2App) {
4175
+ account.data.oauth2.app = oauth2App;
4176
+ }
4166
4177
  }
4178
+ } catch (err) {
4179
+ // Account has invalid config (e.g., broken delegation)
4180
+ account.data = {
4181
+ delegationError: err.message
4182
+ };
4167
4183
  }
4168
4184
  }
4169
4185
 
@@ -159,6 +159,15 @@ function formatAccountData(account, gt) {
159
159
  break;
160
160
  }
161
161
 
162
+ // Check if IMAP was disabled due to errors - override state label to show error
163
+ if (account.imap && account.imap.disabled && account.lastErrorState) {
164
+ account.stateLabel = {
165
+ type: 'danger',
166
+ name: 'Failed',
167
+ error: account.lastErrorState.description || account.lastErrorState.response
168
+ };
169
+ }
170
+
162
171
  if (account.oauth2) {
163
172
  account.oauth2.scopes = []
164
173
  .concat(account.oauth2.scope || [])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emailengine-app",
3
- "version": "2.61.3",
3
+ "version": "2.61.4",
4
4
  "private": false,
5
5
  "productTitle": "EmailEngine",
6
6
  "description": "Email Sync Engine",