@remit/imap-worker 0.0.52 → 0.0.53

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": "@remit/imap-worker",
3
- "version": "0.0.52",
3
+ "version": "0.0.53",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -3,6 +3,7 @@ import { afterEach, before, describe, it, mock } from "node:test";
3
3
  import { getClient, type RemitClient, setClient } from "@remit/backend/client";
4
4
  import type { AccountItem, ThreadMessageItem } from "@remit/data-ports";
5
5
  import type { Logger } from "@remit/logger-lambda";
6
+ import type { IImapConnection } from "@remit/mailbox-service";
6
7
  import type { MessageMoveEvent } from "../events.js";
7
8
  import {
8
9
  buildThreadMessageMoveUpdate,
@@ -11,6 +12,7 @@ import {
11
12
  handleMessageMove,
12
13
  MESSAGE_MOVE_MAX_ATTEMPTS,
13
14
  moveThenResync,
15
+ searchMailboxByMessageId,
14
16
  } from "./message-move.js";
15
17
 
16
18
  const silentLogger = (() => {
@@ -340,3 +342,85 @@ describe("handleMessageMove — the move's own pending state gates every attempt
340
342
  assert.equal(mailboxGet.mock.calls.length, 0);
341
343
  });
342
344
  });
345
+
346
+ describe("searchMailboxByMessageId — the probe that binds a move to a UID (#912)", () => {
347
+ const isMessageIdCriterion = (
348
+ criterion: unknown,
349
+ ): criterion is [string, string, string] =>
350
+ Array.isArray(criterion) &&
351
+ criterion.length === 3 &&
352
+ typeof criterion[0] === "string" &&
353
+ criterion[0].toUpperCase() === "HEADER" &&
354
+ typeof criterion[1] === "string" &&
355
+ criterion[1].toLowerCase() === "message-id" &&
356
+ typeof criterion[2] === "string";
357
+
358
+ const buildDestination = (
359
+ messages: Array<{ uid: number; messageIdHeader: string }>,
360
+ ): IImapConnection => {
361
+ const searchAll = () => messages.map((row) => row.uid);
362
+ return {
363
+ openBox: async () => ({}) as never,
364
+ search: async (criteria: unknown[]) => {
365
+ const criterion = criteria.find(isMessageIdCriterion);
366
+ if (criterion === undefined) return searchAll();
367
+ return messages
368
+ .filter((row) => row.messageIdHeader === criterion[2])
369
+ .map((row) => row.uid);
370
+ },
371
+ } as unknown as IImapConnection;
372
+ };
373
+
374
+ it("asks the folder by Message-ID rather than by an interpolated string", async () => {
375
+ const sent: unknown[][] = [];
376
+ const destination = {
377
+ openBox: async () => ({}) as never,
378
+ search: async (criteria: unknown[]) => {
379
+ sent.push(criteria);
380
+ return [];
381
+ },
382
+ } as unknown as IImapConnection;
383
+
384
+ await searchMailboxByMessageId(
385
+ destination,
386
+ "Archive",
387
+ '<a"b@example.com>\r\nUID 1',
388
+ );
389
+
390
+ assert.deepStrictEqual(sent, [
391
+ [["HEADER", "Message-ID", '<a"b@example.com>\r\nUID 1']],
392
+ ]);
393
+ });
394
+
395
+ it("answers null, not the lowest UID, when the folder holds no such message", async () => {
396
+ const destination = buildDestination([
397
+ { uid: 11, messageIdHeader: "<stranger-a@example.com>" },
398
+ { uid: 12, messageIdHeader: "<stranger-b@example.com>" },
399
+ ]);
400
+
401
+ assert.strictEqual(
402
+ await searchMailboxByMessageId(
403
+ destination,
404
+ "Archive",
405
+ "<moved@example.com>",
406
+ ),
407
+ null,
408
+ );
409
+ });
410
+
411
+ it("answers the UID of the message carrying that Message-ID", async () => {
412
+ const destination = buildDestination([
413
+ { uid: 11, messageIdHeader: "<stranger-a@example.com>" },
414
+ { uid: 12, messageIdHeader: "<moved@example.com>" },
415
+ ]);
416
+
417
+ assert.strictEqual(
418
+ await searchMailboxByMessageId(
419
+ destination,
420
+ "Archive",
421
+ "<moved@example.com>",
422
+ ),
423
+ 12,
424
+ );
425
+ });
426
+ });
@@ -78,7 +78,7 @@ export const searchMailboxByMessageId = async (
78
78
  ): Promise<number | null> => {
79
79
  await connection.openBox(mailboxPath, true);
80
80
  const uids = await connection.search([
81
- `HEADER Message-ID "${messageIdHeader}"`,
81
+ ["HEADER", "Message-ID", messageIdHeader],
82
82
  ]);
83
83
  return uids[0] ?? null;
84
84
  };