@bobfrankston/iflow 1.0.55 → 1.0.57

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.
@@ -293,7 +293,8 @@ export class NativeImapClient {
293
293
  const uids = await this.search(`UID ${sinceUid + 1}:*`);
294
294
  if (uids.length === 0)
295
295
  return [];
296
- console.log(` [fetch] ${uids.length} UIDs since ${sinceUid}`);
296
+ uids.reverse(); // Newest first
297
+ console.log(` [fetch] ${uids.length} UIDs since ${sinceUid} (newest first)`);
297
298
  if (uids.length <= NativeImapClient.INITIAL_CHUNK_SIZE) {
298
299
  const msgs = await this.fetchMessages(uids.join(","), options);
299
300
  if (onChunk)
@@ -323,7 +324,9 @@ export class NativeImapClient {
323
324
  const uids = await this.search(criteria);
324
325
  if (uids.length === 0)
325
326
  return [];
326
- console.log(` [fetch] ${uids.length} UIDs to fetch`);
327
+ // Reverse so newest messages (highest UIDs) come first
328
+ uids.reverse();
329
+ console.log(` [fetch] ${uids.length} UIDs to fetch (newest first)`);
327
330
  const allMessages = [];
328
331
  let chunkSize = NativeImapClient.INITIAL_CHUNK_SIZE;
329
332
  for (let i = 0; i < uids.length; i += chunkSize) {
@@ -521,11 +524,18 @@ export class NativeImapClient {
521
524
  }
522
525
  processBuffer() {
523
526
  while (true) {
524
- // Check for literal {size}\r\n — reading exact byte count of literal data
527
+ // Check for literal {size}\r\n — reading exact BYTE count of literal data
528
+ // CRITICAL: literalBytes is in octets (from IMAP {N}), but this.buffer is a
529
+ // JavaScript string where multi-byte UTF-8 characters count as 1 character.
530
+ // We must use Buffer.byteLength to find the correct character boundary.
525
531
  if (this.pendingCommand?.literalBytes != null) {
526
- if (this.buffer.length >= this.pendingCommand.literalBytes) {
527
- let literal = this.buffer.substring(0, this.pendingCommand.literalBytes);
528
- this.buffer = this.buffer.substring(this.pendingCommand.literalBytes);
532
+ const neededBytes = this.pendingCommand.literalBytes;
533
+ const bufferBytes = Buffer.byteLength(this.buffer, "utf-8");
534
+ if (bufferBytes >= neededBytes) {
535
+ // Find the character position that corresponds to the byte boundary
536
+ const buf = Buffer.from(this.buffer, "utf-8");
537
+ let literal = buf.subarray(0, neededBytes).toString("utf-8");
538
+ this.buffer = buf.subarray(neededBytes).toString("utf-8");
529
539
  // For non-BODY literals (e.g. display names in ENVELOPE), wrap in quotes
530
540
  // so tokenizeParenList treats them as a single token
531
541
  if (!this.pendingCommand.currentLiteralKey) {
@@ -549,7 +559,7 @@ export class NativeImapClient {
549
559
  continue;
550
560
  }
551
561
  if (this.verbose && this.pendingCommand.literalBytes > 0) {
552
- console.log(` [imap] waiting for literal: need ${this.pendingCommand.literalBytes}, have ${this.buffer.length}`);
562
+ console.log(` [imap] waiting for literal: need ${neededBytes} bytes, have ${bufferBytes} bytes`);
553
563
  }
554
564
  break; // Wait for more data
555
565
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/iflow",
3
- "version": "1.0.55",
3
+ "version": "1.0.57",
4
4
  "description": "IMAP client wrapper library",
5
5
  "main": "index.js",
6
6
  "types": "index.ts",