@remit/backend 0.0.125 → 0.0.126
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
|
@@ -69,6 +69,8 @@ const run = async (): Promise<void> => {
|
|
|
69
69
|
const result = await backfillClassifications(
|
|
70
70
|
{
|
|
71
71
|
accountConfigService: client.accountConfig,
|
|
72
|
+
accountService: client.account,
|
|
73
|
+
mailboxSpecialUseService: client.mailboxSpecialUse,
|
|
72
74
|
addressService: client.address,
|
|
73
75
|
threadMessageService: client.threadMessage,
|
|
74
76
|
messageService: client.message,
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { afterEach, describe, it } from "node:test";
|
|
3
|
+
import type { APIGatewayProxyEvent } from "aws-lambda";
|
|
4
|
+
import type { Context } from "openapi-backend";
|
|
5
|
+
import {
|
|
6
|
+
_resetForTest,
|
|
7
|
+
type RemitClient,
|
|
8
|
+
setClient,
|
|
9
|
+
} from "../service/data-client.js";
|
|
10
|
+
import { MessageOperations } from "./message.js";
|
|
11
|
+
|
|
12
|
+
type Handler = (
|
|
13
|
+
context: Context,
|
|
14
|
+
event: APIGatewayProxyEvent,
|
|
15
|
+
) => Promise<unknown>;
|
|
16
|
+
|
|
17
|
+
const describeMessage =
|
|
18
|
+
MessageOperations.MessageOperations_describeMessage as unknown as Handler;
|
|
19
|
+
const getRawMessage =
|
|
20
|
+
MessageOperations.MessageOperations_getRawMessage as unknown as Handler;
|
|
21
|
+
|
|
22
|
+
const MESSAGE_ID = "msg-1";
|
|
23
|
+
const MAILBOX_ID = "mb-1";
|
|
24
|
+
const ACCOUNT_ID = "acc-1";
|
|
25
|
+
|
|
26
|
+
const event = {
|
|
27
|
+
requestContext: { authorizer: { claims: { sub: "sub-610" } } },
|
|
28
|
+
} as unknown as APIGatewayProxyEvent;
|
|
29
|
+
|
|
30
|
+
const context = {
|
|
31
|
+
request: { params: { messageId: MESSAGE_ID } },
|
|
32
|
+
} as unknown as Context;
|
|
33
|
+
|
|
34
|
+
const unstoredMessage = {
|
|
35
|
+
messageId: MESSAGE_ID,
|
|
36
|
+
mailboxId: MAILBOX_ID,
|
|
37
|
+
uid: 7,
|
|
38
|
+
internalDate: 1,
|
|
39
|
+
status: "active",
|
|
40
|
+
syncStatus: "synced",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const mailboxRow = {
|
|
44
|
+
mailboxId: MAILBOX_ID,
|
|
45
|
+
accountId: ACCOUNT_ID,
|
|
46
|
+
fullPath: "Junk",
|
|
47
|
+
cursorState: "normal",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const clientWithFailingFolderLookup = (opened: string[]): RemitClient =>
|
|
51
|
+
({
|
|
52
|
+
message: {
|
|
53
|
+
get: async () => unstoredMessage,
|
|
54
|
+
describe: async () => ({
|
|
55
|
+
message: [unstoredMessage],
|
|
56
|
+
envelope: [],
|
|
57
|
+
envelopeAddress: [],
|
|
58
|
+
messageFlag: [],
|
|
59
|
+
bodyPart: [],
|
|
60
|
+
messageReference: [],
|
|
61
|
+
}),
|
|
62
|
+
},
|
|
63
|
+
messageLabel: { listByMessageId: async () => [] },
|
|
64
|
+
account: {
|
|
65
|
+
listAllByAccountConfig: async () => [{ accountId: ACCOUNT_ID }],
|
|
66
|
+
},
|
|
67
|
+
mailbox: {
|
|
68
|
+
get: async (_accountId: string, ids: string | string[]) =>
|
|
69
|
+
Array.isArray(ids) ? [mailboxRow] : mailboxRow,
|
|
70
|
+
},
|
|
71
|
+
storage: { bodyPartExists: async () => false },
|
|
72
|
+
mailboxSpecialUse: {
|
|
73
|
+
findJunkMailbox: async () => {
|
|
74
|
+
throw new Error("special-use lookup timed out");
|
|
75
|
+
},
|
|
76
|
+
findInboxMailbox: async () => null,
|
|
77
|
+
},
|
|
78
|
+
createConnectionScope: async (accountId: string) => {
|
|
79
|
+
opened.push(accountId);
|
|
80
|
+
return {
|
|
81
|
+
getConnection: async () => ({}),
|
|
82
|
+
disconnect: async () => {},
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
}) as unknown as RemitClient;
|
|
86
|
+
|
|
87
|
+
describe("reading an unstored message when the folder lookup fails", () => {
|
|
88
|
+
afterEach(() => _resetForTest());
|
|
89
|
+
|
|
90
|
+
for (const [name, handler] of [
|
|
91
|
+
["describeMessage", describeMessage],
|
|
92
|
+
["getRawMessage", getRawMessage],
|
|
93
|
+
] as const) {
|
|
94
|
+
it(`${name} opens no IMAP connection`, async () => {
|
|
95
|
+
const opened: string[] = [];
|
|
96
|
+
setClient(clientWithFailingFolderLookup(opened));
|
|
97
|
+
|
|
98
|
+
await assert.rejects(handler(context, event), /special-use lookup/);
|
|
99
|
+
|
|
100
|
+
assert.deepEqual(opened, []);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
});
|
package/src/handlers/message.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
MailboxCursorPausedError,
|
|
27
27
|
MoveNotSettledError,
|
|
28
28
|
NoJunkMailboxError,
|
|
29
|
+
resolveFolderPlacement,
|
|
29
30
|
} from "@remit/mailbox-service";
|
|
30
31
|
import {
|
|
31
32
|
isStorageNotFoundError as isStorageNotFoundErrorFromService,
|
|
@@ -605,6 +606,14 @@ export const MessageOperations: Record<
|
|
|
605
606
|
"Mailbox cursor not normal; skipping IMAP body backfill for this request",
|
|
606
607
|
);
|
|
607
608
|
} else {
|
|
609
|
+
const folder = {
|
|
610
|
+
fullPath: mailbox.fullPath,
|
|
611
|
+
placement: await resolveFolderPlacement(
|
|
612
|
+
client.mailboxSpecialUse,
|
|
613
|
+
accountId,
|
|
614
|
+
mailbox.mailboxId,
|
|
615
|
+
),
|
|
616
|
+
};
|
|
608
617
|
const scope = await client.createConnectionScope(accountId);
|
|
609
618
|
// Guard at the one choke point every UID-based IMAP op already
|
|
610
619
|
// passes through: openBox. A mismatch trips the mailbox to
|
|
@@ -619,12 +628,8 @@ export const MessageOperations: Record<
|
|
|
619
628
|
);
|
|
620
629
|
|
|
621
630
|
await client.bodySync
|
|
622
|
-
.fetchAndGetBody(
|
|
623
|
-
|
|
624
|
-
accountId,
|
|
625
|
-
accountConfigId,
|
|
626
|
-
mailbox.fullPath,
|
|
627
|
-
() => Promise.resolve(connection),
|
|
631
|
+
.fetchAndGetBody(messageId, accountId, accountConfigId, folder, () =>
|
|
632
|
+
Promise.resolve(connection),
|
|
628
633
|
)
|
|
629
634
|
.catch((error: unknown) => {
|
|
630
635
|
if (error instanceof MailboxCursorPausedError) {
|
|
@@ -742,6 +747,14 @@ export const MessageOperations: Record<
|
|
|
742
747
|
"Mailbox cursor not normal; skipping IMAP body backfill for this request",
|
|
743
748
|
);
|
|
744
749
|
} else {
|
|
750
|
+
const folder = {
|
|
751
|
+
fullPath: mailbox.fullPath,
|
|
752
|
+
placement: await resolveFolderPlacement(
|
|
753
|
+
client.mailboxSpecialUse,
|
|
754
|
+
accountId,
|
|
755
|
+
mailbox.mailboxId,
|
|
756
|
+
),
|
|
757
|
+
};
|
|
745
758
|
const scope = await client.createConnectionScope(accountId);
|
|
746
759
|
// Guard at the openBox choke point — a fresh mismatch trips the
|
|
747
760
|
// mailbox and throws once the SELECT reveals it; caught below.
|
|
@@ -752,12 +765,8 @@ export const MessageOperations: Record<
|
|
|
752
765
|
mailbox,
|
|
753
766
|
);
|
|
754
767
|
await client.bodySync
|
|
755
|
-
.fetchAndGetBody(
|
|
756
|
-
|
|
757
|
-
accountId,
|
|
758
|
-
accountConfigId,
|
|
759
|
-
mailbox.fullPath,
|
|
760
|
-
() => Promise.resolve(connection),
|
|
768
|
+
.fetchAndGetBody(messageId, accountId, accountConfigId, folder, () =>
|
|
769
|
+
Promise.resolve(connection),
|
|
761
770
|
)
|
|
762
771
|
.catch((error: unknown) => {
|
|
763
772
|
if (error instanceof MailboxCursorPausedError) {
|