@bobfrankston/mailx 1.0.64 → 1.0.69

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 (61) hide show
  1. package/android/app/build/.npmkeep +0 -0
  2. package/android/app/build.gradle +54 -0
  3. package/android/app/capacitor.build.gradle +19 -0
  4. package/android/app/proguard-rules.pro +21 -0
  5. package/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java +26 -0
  6. package/android/app/src/main/AndroidManifest.xml +41 -0
  7. package/android/app/src/main/java/com/frankston/mailx/MainActivity.java +5 -0
  8. package/android/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
  9. package/android/app/src/main/res/drawable/splash.png +0 -0
  10. package/android/app/src/main/res/drawable-land-hdpi/splash.png +0 -0
  11. package/android/app/src/main/res/drawable-land-mdpi/splash.png +0 -0
  12. package/android/app/src/main/res/drawable-land-xhdpi/splash.png +0 -0
  13. package/android/app/src/main/res/drawable-land-xxhdpi/splash.png +0 -0
  14. package/android/app/src/main/res/drawable-land-xxxhdpi/splash.png +0 -0
  15. package/android/app/src/main/res/drawable-port-hdpi/splash.png +0 -0
  16. package/android/app/src/main/res/drawable-port-mdpi/splash.png +0 -0
  17. package/android/app/src/main/res/drawable-port-xhdpi/splash.png +0 -0
  18. package/android/app/src/main/res/drawable-port-xxhdpi/splash.png +0 -0
  19. package/android/app/src/main/res/drawable-port-xxxhdpi/splash.png +0 -0
  20. package/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +34 -0
  21. package/android/app/src/main/res/layout/activity_main.xml +12 -0
  22. package/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
  23. package/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
  24. package/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  25. package/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png +0 -0
  26. package/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  27. package/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  28. package/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png +0 -0
  29. package/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  30. package/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  31. package/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png +0 -0
  32. package/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  33. package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  34. package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png +0 -0
  35. package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  36. package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  37. package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png +0 -0
  38. package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  39. package/android/app/src/main/res/values/ic_launcher_background.xml +4 -0
  40. package/android/app/src/main/res/values/strings.xml +7 -0
  41. package/android/app/src/main/res/values/styles.xml +22 -0
  42. package/android/app/src/main/res/xml/file_paths.xml +5 -0
  43. package/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java +18 -0
  44. package/android/build.gradle +29 -0
  45. package/android/capacitor.settings.gradle +3 -0
  46. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  47. package/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  48. package/android/gradle.properties +23 -0
  49. package/android/gradlew +251 -0
  50. package/android/gradlew.bat +94 -0
  51. package/android/settings.gradle +5 -0
  52. package/android/variables.gradle +16 -0
  53. package/client/app.js +90 -32
  54. package/client/lib/api-client.js +203 -164
  55. package/client/styles/layout.css +31 -0
  56. package/download/apks/mailx-debug.apk +0 -0
  57. package/download/index.html +118 -0
  58. package/download/versions.json +19 -0
  59. package/package.json +17 -11
  60. package/packages/mailx-imap/index.d.ts +2 -0
  61. package/packages/mailx-imap/index.js +39 -19
@@ -30,6 +30,8 @@ export declare class ImapManager extends EventEmitter {
30
30
  constructor(db: MailxDB);
31
31
  /** Get OAuth access token for an account (for SMTP auth) */
32
32
  getOAuthToken(accountId: string): Promise<string | null>;
33
+ /** Accounts currently re-authenticating — all operations skip these */
34
+ private reauthenticating;
33
35
  /** Force re-authentication for an OAuth account — deletes cached IMAP token, triggers browser consent */
34
36
  reauthenticate(accountId: string): Promise<boolean>;
35
37
  /** Delete a message directly on the IMAP server (for stuck outbox messages not in local DB) */
@@ -72,29 +72,42 @@ export class ImapManager extends EventEmitter {
72
72
  return null;
73
73
  return config.tokenProvider();
74
74
  }
75
+ /** Accounts currently re-authenticating — all operations skip these */
76
+ reauthenticating = new Set();
75
77
  /** Force re-authentication for an OAuth account — deletes cached IMAP token, triggers browser consent */
76
78
  async reauthenticate(accountId) {
77
- const settings = loadSettings();
78
- const account = settings.accounts.find(a => a.id === accountId);
79
- if (!account)
80
- return false;
81
- // Delete only the IMAP token (not contacts — separate scope, separate consent)
82
- const accountDir = account.imap.user.replace(/[@.]/g, "_");
83
- const tokenDir = path.join(getConfigDir(), "tokens", accountDir);
84
- const tokenPath = path.join(tokenDir, "token.json");
85
- if (fs.existsSync(tokenPath)) {
86
- fs.unlinkSync(tokenPath);
87
- console.log(` [reauth] Deleted ${tokenPath}`);
88
- }
89
- // Re-register the account to get a fresh config with new tokenProvider
90
- this.configs.delete(accountId);
91
- await this.addAccount(account);
92
- // Trigger the OAuth flow by requesting a token
79
+ if (this.reauthenticating.has(accountId))
80
+ return false; // already in progress
81
+ this.reauthenticating.add(accountId);
93
82
  try {
94
- const token = await this.getOAuthToken(accountId);
95
- if (token) {
83
+ const settings = loadSettings();
84
+ const account = settings.accounts.find(a => a.id === accountId);
85
+ if (!account)
86
+ return false;
87
+ // Stop IDLE watcher for this account
88
+ const stopWatcher = this.watchers.get(accountId);
89
+ if (stopWatcher) {
90
+ try {
91
+ await stopWatcher();
92
+ }
93
+ catch { /* */ }
94
+ this.watchers.delete(accountId);
95
+ }
96
+ // Delete only the IMAP token (not contacts — separate scope, separate consent)
97
+ const accountDir = account.imap.user.replace(/[@.]/g, "_");
98
+ const tokenDir = path.join(getConfigDir(), "tokens", accountDir);
99
+ const tokenPath = path.join(tokenDir, "token.json");
100
+ if (fs.existsSync(tokenPath)) {
101
+ fs.unlinkSync(tokenPath);
102
+ console.log(` [reauth] Deleted ${tokenPath}`);
103
+ }
104
+ // Re-register the account to get a fresh config with new tokenProvider
105
+ this.configs.delete(accountId);
106
+ await this.addAccount(account);
107
+ // addAccount already pre-validates the token (opens browser if needed)
108
+ const config = this.configs.get(accountId);
109
+ if (config?.tokenProvider) {
96
110
  console.log(` [reauth] ${accountId}: success`);
97
- // Trigger a sync now that auth works
98
111
  this.syncInbox().catch(() => { });
99
112
  return true;
100
113
  }
@@ -102,6 +115,9 @@ export class ImapManager extends EventEmitter {
102
115
  catch (e) {
103
116
  console.error(` [reauth] ${accountId}: ${e.message}`);
104
117
  }
118
+ finally {
119
+ this.reauthenticating.delete(accountId);
120
+ }
105
121
  return false;
106
122
  }
107
123
  /** Delete a message directly on the IMAP server (for stuck outbox messages not in local DB) */
@@ -137,6 +153,8 @@ export class ImapManager extends EventEmitter {
137
153
  }
138
154
  /** Create a fresh ImapClient for an account (disposable, single-use) */
139
155
  createClient(accountId) {
156
+ if (this.reauthenticating.has(accountId))
157
+ throw new Error(`Account ${accountId} is re-authenticating`);
140
158
  const config = this.configs.get(accountId);
141
159
  if (!config)
142
160
  throw new Error(`No config for account ${accountId}`);
@@ -539,6 +557,8 @@ export class ImapManager extends EventEmitter {
539
557
  lastInboxCounts = new Map();
540
558
  async quickInboxCheck() {
541
559
  for (const [accountId] of this.configs) {
560
+ if (this.reauthenticating.has(accountId))
561
+ continue;
542
562
  let client = null;
543
563
  try {
544
564
  const inbox = this.db.getFolders(accountId).find(f => f.specialUse === "inbox");