@bobfrankston/mailx-sync 0.1.7 → 0.1.8

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 (3) hide show
  1. package/gmail.js +20 -8
  2. package/package.json +1 -1
  3. package/types.d.ts +4 -0
package/gmail.js CHANGED
@@ -207,11 +207,15 @@ export class GmailApiProvider {
207
207
  * real messages from the local DB. Returning [] silently caused the
208
208
  * "INBOX empty in mailx" bug when a rate-limit hit mid-pagination. */
209
209
  async listMessageIds(query, maxResults = 500) {
210
+ // maxResults === 0 → unlimited (for date-bounded queries where the
211
+ // query itself caps the result set).
212
+ const unlimited = maxResults === 0;
210
213
  const ids = [];
211
214
  let pageToken = "";
212
215
  let truncated = false;
213
216
  while (true) {
214
- const params = new URLSearchParams({ q: query, maxResults: String(Math.min(maxResults - ids.length, 500)) });
217
+ const pageSize = unlimited ? 500 : Math.min(maxResults - ids.length, 500);
218
+ const params = new URLSearchParams({ q: query, maxResults: String(pageSize) });
215
219
  if (pageToken)
216
220
  params.set("pageToken", pageToken);
217
221
  const data = await this.fetch(`/messages?${params}`);
@@ -220,7 +224,7 @@ export class GmailApiProvider {
220
224
  }
221
225
  if (!data.nextPageToken)
222
226
  break;
223
- if (ids.length >= maxResults) {
227
+ if (!unlimited && ids.length >= maxResults) {
224
228
  // Hit the caller's cap but the server has more. Flag it so
225
229
  // reconcile-style callers can refuse to treat this as complete.
226
230
  truncated = true;
@@ -299,19 +303,27 @@ export class GmailApiProvider {
299
303
  async fetchSince(folder, sinceUid, options = {}) {
300
304
  // Gmail message IDs are hash-derived, NOT monotonic — filtering by
301
305
  // `uid > sinceUid` silently drops new messages whose hash happens to
302
- // fall below the high-water mark. Fetch the most recent page and let
303
- // upsertMessage dedupe by (account, folder, uid). The sinceUid arg is
304
- // kept for interface compatibility but no longer used for filtering.
306
+ // fall below the high-water mark. Fetch by date (when caller supplied
307
+ // a `since` window) or fall back to the recent-200 page.
305
308
  void sinceUid;
306
- const query = `in:${this.folderToLabel(folder)}`;
307
- const ids = await this.listMessageIds(query, 200);
309
+ let query = `in:${this.folderToLabel(folder)}`;
310
+ if (options.since) {
311
+ // after: is inclusive at day granularity; filter precisely on the
312
+ // client side since Gmail's search is whole-day.
313
+ query += ` after:${this.formatDate(options.since)}`;
314
+ }
315
+ // When the caller bounded by date, let pagination run — the query
316
+ // is self-limiting. Otherwise cap at the recent 200.
317
+ const cap = options.since ? 0 : 200;
318
+ const ids = await this.listMessageIds(query, cap);
308
319
  return this.batchFetch(ids, options);
309
320
  }
310
321
  async fetchByDate(folder, since, before, options = {}, onChunk) {
311
322
  const afterDate = this.formatDate(since);
312
323
  const beforeDate = this.formatDate(before);
313
324
  const query = `in:${this.folderToLabel(folder)} after:${afterDate} before:${beforeDate}`;
314
- const ids = await this.listMessageIds(query);
325
+ // Date-bounded let pagination drain the full range instead of stopping at 500.
326
+ const ids = await this.listMessageIds(query, 0);
315
327
  return this.batchFetch(ids, options, onChunk);
316
328
  }
317
329
  async fetchByUids(folder, uids, options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-sync",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Platform-agnostic mail provider implementations + sync orchestration. Single source of truth for Gmail/IMAP/Outlook protocol code, consumed by both desktop (Node) and Android (WebView) — eliminates the parallel mailx-imap/mailx-store-web Gmail providers that drifted in practice.",
5
5
  "main": "index.js",
6
6
  "types": "index.ts",
package/types.d.ts CHANGED
@@ -43,6 +43,10 @@ export interface ProviderMessage {
43
43
  export interface FetchOptions {
44
44
  source?: boolean;
45
45
  providerId?: string;
46
+ /** Lower bound for "since" queries — bounds the result set by date so
47
+ * the default page-count cap doesn't silently truncate a large folder
48
+ * to the last ~200 messages. */
49
+ since?: Date;
46
50
  }
47
51
  /**
48
52
  * A mail provider that can list folders, fetch messages, and perform actions.