@bobfrankston/mailx 1.0.71 → 1.0.74

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx",
3
- "version": "1.0.71",
3
+ "version": "1.0.74",
4
4
  "description": "Local-first email client with IMAP sync and standalone native app",
5
5
  "type": "module",
6
6
  "main": "bin/mailx.js",
@@ -20,9 +20,9 @@
20
20
  "postinstall": "node launcher/builder/postinstall.js"
21
21
  },
22
22
  "dependencies": {
23
- "@bobfrankston/iflow": "^1.0.32",
23
+ "@bobfrankston/iflow": "^1.0.34",
24
24
  "@bobfrankston/miscinfo": "^1.0.6",
25
- "@bobfrankston/oauthsupport": "^1.0.17",
25
+ "@bobfrankston/oauthsupport": "^1.0.19",
26
26
  "@bobfrankston/rust-builder": "^0.1.2",
27
27
  "@capacitor/android": "^8.3.0",
28
28
  "@capacitor/cli": "^8.3.0",
@@ -112,7 +112,8 @@ export declare class ImapManager extends EventEmitter {
112
112
  /** Stop Outbox worker */
113
113
  stopOutboxWorker(): void;
114
114
  private contactsSyncToken;
115
- /** Get an OAuth token for Google Contacts API */
115
+ /** Get an OAuth token for Google APIs (contacts, calendar, etc.)
116
+ * Uses the SAME token as IMAP — scopes are combined in one grant */
116
117
  private getContactsToken;
117
118
  /** Sync contacts from Google People API */
118
119
  syncGoogleContacts(accountId: string): Promise<number>;
@@ -4,7 +4,6 @@
4
4
  * Syncs messages to local store, emits events for new mail.
5
5
  */
6
6
  import { ImapClient, createAutoImapConfig } from "@bobfrankston/iflow";
7
- import { authenticateOAuth } from "@bobfrankston/oauthsupport";
8
7
  import { FileMessageStore } from "@bobfrankston/mailx-store";
9
8
  import { loadSettings, getStorePath, getConfigDir } from "@bobfrankston/mailx-settings";
10
9
  import { EventEmitter } from "node:events";
@@ -1194,40 +1193,11 @@ export class ImapManager extends EventEmitter {
1194
1193
  }
1195
1194
  // ── Google Contacts Sync ──
1196
1195
  contactsSyncToken = null;
1197
- /** Get an OAuth token for Google Contacts API */
1196
+ /** Get an OAuth token for Google APIs (contacts, calendar, etc.)
1197
+ * Uses the SAME token as IMAP — scopes are combined in one grant */
1198
1198
  async getContactsToken(accountId) {
1199
- const settings = loadSettings();
1200
- const account = settings.accounts.find(a => a.id === accountId);
1201
- if (!account || account.imap.auth !== "oauth2")
1202
- return null;
1203
- // Find iflow-credentials.json from the iflow package
1204
- const credentialsCandidates = [
1205
- path.resolve(import.meta.dirname, "..", "..", "node_modules", "@bobfrankston", "iflow", "iflow-credentials.json"),
1206
- path.resolve(import.meta.dirname, "..", "..", "..", "node_modules", "@bobfrankston", "iflow", "iflow-credentials.json"),
1207
- ];
1208
- const credentialsPath = credentialsCandidates.find(p => fs.existsSync(p));
1209
- if (!credentialsPath) {
1210
- console.error(" [contacts] iflow-credentials.json not found");
1211
- return null;
1212
- }
1213
- const accountDir = account.imap.user.replace(/[@.]/g, "_");
1214
- const tokenDir = path.join(getConfigDir(), "tokens", accountDir);
1215
- const tokenPath = path.join(tokenDir, "contacts-token.json");
1216
- // If no cached token exists, skip — don't open interactive browser consent for contacts
1217
- // The user can trigger contacts sync manually or it will be set up during mailx -setup
1218
- if (!fs.existsSync(tokenPath)) {
1219
- console.log(` [contacts] No token for ${accountId} — skipping (run mailx -setup to authorize)`);
1220
- return null;
1221
- }
1222
- const token = await authenticateOAuth(credentialsPath, {
1223
- scope: "https://www.googleapis.com/auth/contacts.readonly",
1224
- tokenDirectory: tokenDir,
1225
- tokenFileName: "contacts-token.json",
1226
- credentialsKey: "installed",
1227
- includeOfflineAccess: true,
1228
- loginHint: account.imap.user,
1229
- });
1230
- return token?.access_token || null;
1199
+ // Reuse the IMAP token — it now includes contacts.readonly scope
1200
+ return this.getOAuthToken(accountId);
1231
1201
  }
1232
1202
  /** Sync contacts from Google People API */
1233
1203
  async syncGoogleContacts(accountId) {