@remit/imap-worker 0.0.84 → 0.0.85
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
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import type { MailboxItem } from "@remit/data-ports";
|
|
4
|
+
import type { CreateMailboxQueueInput } from "@remit/mailbox-service";
|
|
5
|
+
import { createImportedFolder } from "./imported-folder.js";
|
|
6
|
+
|
|
7
|
+
const inbox = {
|
|
8
|
+
mailboxId: "mbx-inbox",
|
|
9
|
+
accountId: "acc-1",
|
|
10
|
+
fullPath: "INBOX",
|
|
11
|
+
namespaceType: "personal",
|
|
12
|
+
namespacePrefix: "INBOX.",
|
|
13
|
+
hierarchyDelimiter: ".",
|
|
14
|
+
} as MailboxItem;
|
|
15
|
+
|
|
16
|
+
describe("createImportedFolder (#1103)", () => {
|
|
17
|
+
it("creates the folder through the pending folder-create path, in the INBOX namespace", async () => {
|
|
18
|
+
const calls: [CreateMailboxQueueInput, string, boolean | undefined][] = [];
|
|
19
|
+
const create = createImportedFolder(
|
|
20
|
+
{ findByPath: async () => inbox },
|
|
21
|
+
{
|
|
22
|
+
createMailbox: async (input, accountId, subscribe) => {
|
|
23
|
+
calls.push([input, accountId, subscribe]);
|
|
24
|
+
return {
|
|
25
|
+
outcome: "Created" as const,
|
|
26
|
+
mailbox: {
|
|
27
|
+
...inbox,
|
|
28
|
+
mailboxId: "mbx-new",
|
|
29
|
+
fullPath: input.fullPath,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const created = await create("acc-1", "INBOX.Facturen");
|
|
37
|
+
|
|
38
|
+
assert.equal(
|
|
39
|
+
created.outcome === "Created" && created.mailbox.mailboxId,
|
|
40
|
+
"mbx-new",
|
|
41
|
+
);
|
|
42
|
+
assert.equal(calls.length, 1);
|
|
43
|
+
const [input, accountId, subscribe] = calls[0];
|
|
44
|
+
assert.equal(accountId, "acc-1");
|
|
45
|
+
assert.equal(subscribe, true);
|
|
46
|
+
assert.equal(input.fullPath, "INBOX.Facturen");
|
|
47
|
+
assert.equal(input.namespacePrefix, "INBOX.");
|
|
48
|
+
assert.equal(input.hierarchyDelimiter, ".");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("refuses to guess a namespace for an account with no INBOX", async () => {
|
|
52
|
+
const create = createImportedFolder(
|
|
53
|
+
{ findByPath: async () => null },
|
|
54
|
+
{
|
|
55
|
+
createMailbox: async () => {
|
|
56
|
+
throw new Error("must not be called");
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
await assert.rejects(create("acc-1", "Facturen"), /no INBOX/);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { CreateImportedFolder } from "@remit/config-transfer";
|
|
2
|
+
import type { IMailboxRepository } from "@remit/data-ports";
|
|
3
|
+
import type { MailboxQueueService } from "@remit/mailbox-service";
|
|
4
|
+
|
|
5
|
+
export const createImportedFolder =
|
|
6
|
+
(
|
|
7
|
+
mailbox: Pick<IMailboxRepository, "findByPath">,
|
|
8
|
+
queue: Pick<MailboxQueueService, "createMailbox">,
|
|
9
|
+
): CreateImportedFolder =>
|
|
10
|
+
async (accountId, folderPath) => {
|
|
11
|
+
const inbox = await mailbox.findByPath(accountId, "INBOX");
|
|
12
|
+
if (!inbox) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`Account ${accountId} has no INBOX to take a namespace from, so "${folderPath}" cannot be created`,
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
return queue.createMailbox(
|
|
18
|
+
{
|
|
19
|
+
accountId,
|
|
20
|
+
namespaceType: inbox.namespaceType,
|
|
21
|
+
namespacePrefix: inbox.namespacePrefix,
|
|
22
|
+
hierarchyDelimiter: inbox.hierarchyDelimiter,
|
|
23
|
+
fullPath: folderPath,
|
|
24
|
+
uidValidity: 0,
|
|
25
|
+
uidNext: 1,
|
|
26
|
+
highestModseq: "0",
|
|
27
|
+
messageCount: 0,
|
|
28
|
+
unseenCount: 0,
|
|
29
|
+
deletedCount: 0,
|
|
30
|
+
totalSize: 0,
|
|
31
|
+
lastSyncUid: 0,
|
|
32
|
+
highWaterMarkUid: 0,
|
|
33
|
+
lastMessageSyncAt: 0,
|
|
34
|
+
},
|
|
35
|
+
accountId,
|
|
36
|
+
true,
|
|
37
|
+
);
|
|
38
|
+
};
|
|
@@ -3,6 +3,7 @@ import { writeFolderRoleAppointment } from "@remit/backend/folder-role-appointme
|
|
|
3
3
|
import {
|
|
4
4
|
bindImportedFolders,
|
|
5
5
|
type ConfigBinderDeps,
|
|
6
|
+
disableFiltersMissingFolders,
|
|
6
7
|
} from "@remit/config-transfer";
|
|
7
8
|
import type {
|
|
8
9
|
AccountItem,
|
|
@@ -16,10 +17,12 @@ import type { Logger } from "@remit/logger-lambda";
|
|
|
16
17
|
import { RefreshTokenError } from "@remit/mail-oauth-service";
|
|
17
18
|
import {
|
|
18
19
|
createConnectionWithCredentials,
|
|
20
|
+
MailboxQueueService,
|
|
19
21
|
MailboxSyncService,
|
|
20
22
|
MailConnectionError,
|
|
21
23
|
type MailCredentials,
|
|
22
24
|
} from "@remit/mailbox-service";
|
|
25
|
+
import { env } from "expect-env";
|
|
23
26
|
import pMap from "p-map";
|
|
24
27
|
import {
|
|
25
28
|
isAccountDeleted,
|
|
@@ -30,6 +33,7 @@ import { emitEvent } from "../emit.js";
|
|
|
30
33
|
import type { SyncMailboxesEvent, SyncMessagesEvent } from "../events.js";
|
|
31
34
|
import { withOAuthLifecycle } from "../with-oauth-lifecycle.js";
|
|
32
35
|
import { buildLifecycleDeps } from "../with-oauth-lifecycle-deps.js";
|
|
36
|
+
import { createImportedFolder } from "./imported-folder.js";
|
|
33
37
|
import { orderMailboxesForSync } from "./mailbox-sync-order.js";
|
|
34
38
|
|
|
35
39
|
const EVENT_EMIT_CONCURRENCY = 20;
|
|
@@ -110,6 +114,14 @@ export const syncMailboxes = async (
|
|
|
110
114
|
mailboxId,
|
|
111
115
|
lastKnownPath,
|
|
112
116
|
),
|
|
117
|
+
createFolder: createImportedFolder(
|
|
118
|
+
mailboxService,
|
|
119
|
+
new MailboxQueueService({
|
|
120
|
+
mailboxService,
|
|
121
|
+
sqsQueueUrl: env.SQS_QUEUE_URL_MAILBOX_MGMT,
|
|
122
|
+
logger: log,
|
|
123
|
+
}),
|
|
124
|
+
),
|
|
113
125
|
};
|
|
114
126
|
|
|
115
127
|
const { accountId } = event;
|
|
@@ -233,10 +245,21 @@ const syncMailboxesForAccount = async (
|
|
|
233
245
|
account.accountConfigId,
|
|
234
246
|
accountId,
|
|
235
247
|
);
|
|
236
|
-
if (
|
|
248
|
+
if (Object.values(bound).some((count) => count > 0)) {
|
|
237
249
|
log.info({ accountId, ...bound }, "Bound imported folder references");
|
|
238
250
|
}
|
|
239
251
|
|
|
252
|
+
const disabled = await disableFiltersMissingFolders(
|
|
253
|
+
binder.repositories,
|
|
254
|
+
account.accountConfigId,
|
|
255
|
+
);
|
|
256
|
+
if (disabled > 0) {
|
|
257
|
+
log.warn(
|
|
258
|
+
{ accountId, disabled },
|
|
259
|
+
"Disabled filters whose move folder no longer exists",
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
240
263
|
const allMailboxes = await collectAllMailboxes(accountId, mailboxService);
|
|
241
264
|
|
|
242
265
|
// This fan-out is where an account's IMAP work is decided: one SEARCH per
|