@bobfrankston/mailx 1.0.293 → 1.0.294

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.293",
3
+ "version": "1.0.294",
4
4
  "description": "Local-first email client with IMAP sync and standalone native app",
5
5
  "type": "module",
6
6
  "main": "bin/mailx.js",
@@ -47,9 +47,13 @@ function findGoogleCredentials() {
47
47
  return null;
48
48
  }
49
49
  const GDRIVE_TOKEN_DIR = path.join(SETTINGS_DIR, "tokens", "gdrive");
50
- // drive.file: app can only see files it created. Safe, publishable without security audit.
51
- // All machines sharing the same OAuth client ID see the same files.
52
- const GDRIVE_SCOPES = "https://www.googleapis.com/auth/drive.file";
50
+ // drive: full access so we can find pre-existing folders like "home/.mailx"
51
+ // that weren't created by this OAuth client. drive.file was safer but couldn't
52
+ // discover folders created manually or by other tools — which broke first-run
53
+ // setup when the user's convention is a nested path.
54
+ // The Gmail scope is already mail.google.com (full email), so this isn't a
55
+ // bigger privacy ask. Token cache at tokens/gdrive/ will re-auth on scope change.
56
+ const GDRIVE_SCOPES = "https://www.googleapis.com/auth/drive";
53
57
  /** Paths to try when no config.path is set (fresh install). Order matters:
54
58
  * "home/.mailx" is the user convention for shared family settings; "mailx"
55
59
  * is the auto-created default. First one that exists on GDrive wins. */
@@ -107,11 +111,13 @@ async function getGoogleDriveToken() {
107
111
  * missing. When `create` is true, creates the LAST segment if missing (won't
108
112
  * create intermediate segments — that's a user error). */
109
113
  async function walkGDrivePath(token, segments, create) {
114
+ const fullPath = segments.join("/");
110
115
  let parentId;
111
116
  for (let i = 0; i < segments.length; i++) {
112
117
  const seg = segments[i];
113
118
  const found = await gDriveFindFolder(token, seg, parentId);
114
119
  if (found) {
120
+ console.log(` [cloud] walk '${fullPath}': '${seg}' → ${found}${parentId ? ` (in ${parentId})` : ""}`);
115
121
  parentId = found;
116
122
  }
117
123
  else if (create && i === segments.length - 1) {
@@ -134,6 +140,21 @@ async function walkGDrivePath(token, segments, create) {
134
140
  }
135
141
  return parentId || null;
136
142
  }
143
+ /** Resolve a folder ID back to its name (for diagnostic logging). */
144
+ async function gDriveGetFolderName(token, folderId) {
145
+ try {
146
+ const res = await fetch(`https://www.googleapis.com/drive/v3/files/${folderId}?fields=name,parents`, {
147
+ headers: { Authorization: `Bearer ${token}` },
148
+ });
149
+ if (!res.ok)
150
+ return null;
151
+ const data = await res.json();
152
+ return data.name || null;
153
+ }
154
+ catch {
155
+ return null;
156
+ }
157
+ }
137
158
  /** Find a single folder by name, optionally inside a parent. */
138
159
  async function gDriveFindFolder(token, name, parentId) {
139
160
  let query = `name='${name}' and mimeType='application/vnd.google-apps.folder' and trashed=false`;
@@ -174,14 +195,18 @@ export async function gDriveFindOrCreateFolder() {
174
195
  : GDRIVE_PATH_SEARCH_ORDER;
175
196
  try {
176
197
  for (const tryPath of pathsToTry) {
198
+ console.log(` [cloud] Trying GDrive path: '${tryPath}'`);
177
199
  const segments = tryPath.split(/[/\\]/).filter(Boolean);
178
200
  const folderId = await walkGDrivePath(token, segments, false);
179
201
  if (folderId) {
180
- console.log(` [cloud] Found existing '${tryPath}' folder: ${folderId}`);
202
+ // Resolve folder ID back to name for verification
203
+ const name = await gDriveGetFolderName(token, folderId);
204
+ console.log(` [cloud] Found existing '${tryPath}' → folder '${name || "?"}' (${folderId})`);
181
205
  return folderId;
182
206
  }
207
+ console.log(` [cloud] Path '${tryPath}' not found on GDrive`);
183
208
  }
184
- // None found — create the first path (configured or default "mailx")
209
+ // None found — create the last (simplest) path
185
210
  const createPath = configuredPath || GDRIVE_PATH_SEARCH_ORDER[GDRIVE_PATH_SEARCH_ORDER.length - 1];
186
211
  const segments = createPath.split(/[/\\]/).filter(Boolean);
187
212
  const created = await walkGDrivePath(token, segments, true);