@remit/mailbox-service 0.0.111 → 0.0.113
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/dist/account-credentials.d.ts +83 -0
- package/dist/account-credentials.js +104 -0
- package/dist/attribute-mapper.d.ts +36 -0
- package/dist/attribute-mapper.js +119 -0
- package/dist/body-parse.d.ts +28 -0
- package/{src/body-parse.ts → dist/body-parse.js} +18 -26
- package/dist/body-part-mapper.d.ts +92 -0
- package/dist/body-part-mapper.js +301 -0
- package/dist/body-sync-queue.d.ts +59 -0
- package/dist/body-sync-queue.js +56 -0
- package/dist/body-sync-terminal.d.ts +58 -0
- package/dist/body-sync-terminal.js +95 -0
- package/dist/body-sync.d.ts +351 -0
- package/dist/body-sync.js +1204 -0
- package/dist/calendar-parts.d.ts +23 -0
- package/dist/calendar-parts.js +18 -0
- package/dist/classification-backfill.d.ts +91 -0
- package/dist/classification-backfill.js +180 -0
- package/dist/classify-message.d.ts +31 -0
- package/dist/classify-message.js +89 -0
- package/dist/connection-factory.d.ts +54 -0
- package/dist/connection-factory.js +54 -0
- package/dist/connection-test.d.ts +41 -0
- package/dist/connection-test.js +152 -0
- package/dist/external-move.d.ts +94 -0
- package/dist/external-move.js +173 -0
- package/dist/filter-operations.d.ts +42 -0
- package/dist/filter-operations.js +211 -0
- package/dist/filters/filter-config.d.ts +14 -0
- package/dist/filters/filter-config.js +10 -0
- package/{src/filters/list-id.ts → dist/filters/list-id.d.ts} +2 -16
- package/dist/filters/list-id.js +26 -0
- package/dist/filters/match.d.ts +69 -0
- package/dist/filters/match.js +165 -0
- package/dist/filters/pipeline.d.ts +64 -0
- package/dist/filters/pipeline.js +100 -0
- package/{src/flag-push-terminal.ts → dist/flag-push-terminal.d.ts} +19 -77
- package/dist/flag-push-terminal.js +63 -0
- package/dist/flag-push.d.ts +69 -0
- package/dist/flag-push.js +111 -0
- package/dist/flag-queue.d.ts +175 -0
- package/dist/flag-queue.js +291 -0
- package/dist/folder-operations.d.ts +39 -0
- package/dist/folder-operations.js +112 -0
- package/dist/folder-placement.d.ts +13 -0
- package/dist/folder-placement.js +23 -0
- package/dist/heuristics/authenticationResults.d.ts +10 -0
- package/dist/heuristics/authenticationResults.js +187 -0
- package/dist/heuristics/classifyByHeaders.d.ts +82 -0
- package/dist/heuristics/classifyByHeaders.js +365 -0
- package/dist/heuristics/classifyPlacement.d.ts +67 -0
- package/dist/heuristics/classifyPlacement.js +153 -0
- package/dist/heuristics/machineSenders.d.ts +21 -0
- package/{src/heuristics/machineSenders.ts → dist/heuristics/machineSenders.js} +34 -40
- package/dist/heuristics/senderMismatch.d.ts +81 -0
- package/dist/heuristics/senderMismatch.js +192 -0
- package/dist/heuristics/socialDomains.d.ts +14 -0
- package/{src/heuristics/socialDomains.ts → dist/heuristics/socialDomains.js} +9 -9
- package/dist/heuristics/transactionalDomains.d.ts +18 -0
- package/{src/heuristics/transactionalDomains.ts → dist/heuristics/transactionalDomains.js} +8 -8
- package/dist/imapflow-connection.d.ts +377 -0
- package/dist/imapflow-connection.js +1147 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +65 -0
- package/dist/list-id-backfill.d.ts +83 -0
- package/dist/list-id-backfill.js +132 -0
- package/dist/mailbox-cursor-rebuild.d.ts +74 -0
- package/dist/mailbox-cursor-rebuild.js +71 -0
- package/{src/mailbox-cursor.ts → dist/mailbox-cursor.d.ts} +20 -98
- package/dist/mailbox-cursor.js +102 -0
- package/dist/mailbox-intent.d.ts +41 -0
- package/{src/mailbox-intent.ts → dist/mailbox-intent.js} +39 -63
- package/dist/mailbox-management.d.ts +240 -0
- package/dist/mailbox-management.js +576 -0
- package/dist/mailbox-presence.d.ts +52 -0
- package/{src/mailbox-presence.ts → dist/mailbox-presence.js} +19 -30
- package/dist/mailbox-queue.d.ts +126 -0
- package/dist/mailbox-queue.js +214 -0
- package/dist/mailbox-sync.d.ts +93 -0
- package/dist/mailbox-sync.js +490 -0
- package/dist/mailbox-upstream.d.ts +38 -0
- package/{src/mailbox-upstream.ts → dist/mailbox-upstream.js} +37 -47
- package/dist/message-category.d.ts +51 -0
- package/{src/message-category.ts → dist/message-category.js} +28 -71
- package/dist/message-move.d.ts +285 -0
- package/dist/message-move.js +858 -0
- package/dist/message-parser.d.ts +14 -0
- package/dist/message-parser.js +17 -0
- package/{src/message-presence.ts → dist/message-presence.d.ts} +1 -13
- package/dist/message-presence.js +29 -0
- package/dist/message-read.d.ts +51 -0
- package/dist/message-read.js +31 -0
- package/dist/message-sync.d.ts +345 -0
- package/dist/message-sync.js +1358 -0
- package/dist/mime-walker.d.ts +102 -0
- package/dist/mime-walker.js +198 -0
- package/dist/organize-job.d.ts +20 -0
- package/dist/organize-job.js +37 -0
- package/dist/outbox-attachment-content.d.ts +37 -0
- package/dist/outbox-attachment-content.js +50 -0
- package/dist/outbox-attachment-filename.d.ts +19 -0
- package/dist/outbox-attachment-filename.js +64 -0
- package/dist/outbox-attachment.d.ts +148 -0
- package/dist/outbox-attachment.js +273 -0
- package/dist/outbox-queue.d.ts +73 -0
- package/dist/outbox-queue.js +284 -0
- package/{src/outbox-status.ts → dist/outbox-status.d.ts} +1 -6
- package/dist/outbox-status.js +18 -0
- package/dist/ownership.d.ts +24 -0
- package/dist/ownership.js +83 -0
- package/dist/placement-move-terminal.d.ts +67 -0
- package/dist/placement-move-terminal.js +88 -0
- package/dist/placement-move.d.ts +83 -0
- package/dist/placement-move.js +216 -0
- package/{src/placement-settled.ts → dist/placement-settled.d.ts} +19 -50
- package/dist/placement-settled.js +75 -0
- package/dist/quarantine.d.ts +95 -0
- package/dist/quarantine.js +131 -0
- package/dist/refusal.d.ts +31 -0
- package/dist/refusal.js +3 -0
- package/{src/restore-source-placement.ts → dist/restore-source-placement.d.ts} +29 -101
- package/dist/restore-source-placement.js +79 -0
- package/dist/search-text-backfill.d.ts +15 -0
- package/dist/search-text-backfill.js +33 -0
- package/dist/snippet.d.ts +61 -0
- package/dist/snippet.js +129 -0
- package/dist/spam-report.d.ts +86 -0
- package/dist/spam-report.js +241 -0
- package/dist/sync-warning.d.ts +21 -0
- package/dist/sync-warning.js +26 -0
- package/dist/sync-watermarks.d.ts +138 -0
- package/dist/sync-watermarks.js +205 -0
- package/dist/test-helpers/fake-imap.d.ts +151 -0
- package/dist/test-helpers/fake-imap.js +508 -0
- package/dist/test-helpers/folder-roles.d.ts +34 -0
- package/dist/test-helpers/folder-roles.js +47 -0
- package/dist/test-helpers/mime-tree-generator.d.ts +82 -0
- package/dist/test-helpers/mime-tree-generator.js +329 -0
- package/dist/test-helpers/test-store.d.ts +69 -0
- package/dist/test-helpers/test-store.js +193 -0
- package/dist/text/normalizer.d.ts +20 -0
- package/dist/text/normalizer.js +102 -0
- package/dist/thread-message-rows.d.ts +69 -0
- package/dist/thread-message-rows.js +40 -0
- package/dist/thread-root.d.ts +7 -0
- package/dist/thread-root.js +25 -0
- package/dist/types.d.ts +343 -0
- package/dist/types.js +19 -0
- package/package.json +86 -73
- package/src/account-credentials.ts +0 -210
- package/src/adversarial-mime.e2e.test.ts +0 -307
- package/src/attribute-mapper.test.ts +0 -104
- package/src/attribute-mapper.ts +0 -148
- package/src/body-parse.test.ts +0 -55
- package/src/body-part-mapper.property.test.ts +0 -354
- package/src/body-part-mapper.ts +0 -360
- package/src/body-sync-auto-read-writeonce.test.ts +0 -219
- package/src/body-sync-calendar-suggestion.test.ts +0 -433
- package/src/body-sync-category-denormalize.test.ts +0 -352
- package/src/body-sync-category-override.test.ts +0 -501
- package/src/body-sync-category-writeonce.test.ts +0 -234
- package/src/body-sync-filter.test.ts +0 -237
- package/src/body-sync-message-gone.test.ts +0 -139
- package/src/body-sync-placement-flags.test.ts +0 -347
- package/src/body-sync-placement-writeonce.test.ts +0 -337
- package/src/body-sync-quarantine.test.ts +0 -276
- package/src/body-sync-queue.test.ts +0 -124
- package/src/body-sync-queue.ts +0 -131
- package/src/body-sync-resync.test.ts +0 -605
- package/src/body-sync-terminal.test.ts +0 -310
- package/src/body-sync-terminal.ts +0 -176
- package/src/body-sync-unclassifiable-once.test.ts +0 -260
- package/src/body-sync-unsubscribed-auto-read.test.ts +0 -176
- package/src/body-sync.ts +0 -1970
- package/src/calendar-parts.ts +0 -41
- package/src/classification-backfill.test.ts +0 -615
- package/src/classification-backfill.ts +0 -363
- package/src/classify-message.test.ts +0 -205
- package/src/classify-message.ts +0 -116
- package/src/connection-factory.ts +0 -102
- package/src/connection-test.ts +0 -208
- package/src/credentials.test.ts +0 -181
- package/src/external-move.test.ts +0 -369
- package/src/external-move.ts +0 -272
- package/src/filters/anchor-drift.ts +0 -55
- package/src/filters/filter-config.test.ts +0 -229
- package/src/filters/filter-config.ts +0 -69
- package/src/filters/list-id.test.ts +0 -50
- package/src/filters/match.test.ts +0 -429
- package/src/filters/match.ts +0 -274
- package/src/filters/message-embedder.test.ts +0 -39
- package/src/filters/message-embedder.ts +0 -33
- package/src/filters/pipeline.test.ts +0 -330
- package/src/filters/pipeline.ts +0 -284
- package/src/flag-push-terminal.test.ts +0 -209
- package/src/flag-push.test.ts +0 -408
- package/src/flag-push.ts +0 -198
- package/src/flag-queue-stars.test.ts +0 -171
- package/src/flag-queue.ts +0 -509
- package/src/folder-placement.ts +0 -56
- package/src/heuristics/authenticationResults.test.ts +0 -189
- package/src/heuristics/authenticationResults.ts +0 -212
- package/src/heuristics/classifyByHeaders.test.ts +0 -889
- package/src/heuristics/classifyByHeaders.ts +0 -467
- package/src/heuristics/classifyPlacement.test.ts +0 -366
- package/src/heuristics/classifyPlacement.ts +0 -211
- package/src/heuristics/classifyRealMail.test.ts +0 -242
- package/src/heuristics/machineSenders.test.ts +0 -101
- package/src/heuristics/senderMismatch.test.ts +0 -346
- package/src/heuristics/senderMismatch.ts +0 -259
- package/src/imapflow-connect-retry.test.ts +0 -134
- package/src/imapflow-connection.e2e.test.ts +0 -335
- package/src/imapflow-connection.integ.test.ts +0 -316
- package/src/imapflow-connection.test.ts +0 -469
- package/src/imapflow-connection.ts +0 -1475
- package/src/index.ts +0 -350
- package/src/list-id-backfill.test.ts +0 -573
- package/src/list-id-backfill.ts +0 -274
- package/src/mailbox-cursor-rebuild.test.ts +0 -171
- package/src/mailbox-cursor-rebuild.ts +0 -146
- package/src/mailbox-cursor.test.ts +0 -249
- package/src/mailbox-delete-intent.test.ts +0 -246
- package/src/mailbox-management.test.ts +0 -356
- package/src/mailbox-management.ts +0 -839
- package/src/mailbox-presence.test.ts +0 -72
- package/src/mailbox-queue.ts +0 -415
- package/src/mailbox-rename-intent.test.ts +0 -389
- package/src/mailbox-rename-subtree.test.ts +0 -664
- package/src/mailbox-sync.test.ts +0 -848
- package/src/mailbox-sync.ts +0 -724
- package/src/message-delete-junk-reconcile.test.ts +0 -117
- package/src/message-delete-no-trash.test.ts +0 -245
- package/src/message-delete-unsettled-placement.test.ts +0 -396
- package/src/message-move-copy.test.ts +0 -562
- package/src/message-move-empty-trash.test.ts +0 -326
- package/src/message-move-same-mailbox.test.ts +0 -139
- package/src/message-move-unsettled-placement.test.ts +0 -378
- package/src/message-move.ts +0 -1348
- package/src/message-parser.ts +0 -26
- package/src/message-presence.test.ts +0 -50
- package/src/message-sync-address-spoof.test.ts +0 -293
- package/src/message-sync-category.test.ts +0 -142
- package/src/message-sync-changedsince.test.ts +0 -840
- package/src/message-sync-flags.test.ts +0 -158
- package/src/message-sync-junk-harvest.test.ts +0 -244
- package/src/message-sync-quarantine.test.ts +0 -416
- package/src/message-sync-repoint.test.ts +0 -419
- package/src/message-sync.ts +0 -1963
- package/src/mime-walker.test.ts +0 -311
- package/src/mime-walker.ts +0 -305
- package/src/outbox-attachment-content.test.ts +0 -153
- package/src/outbox-attachment-content.ts +0 -104
- package/src/outbox-attachment-filename.test.ts +0 -132
- package/src/outbox-attachment-filename.ts +0 -76
- package/src/outbox-attachment.test.ts +0 -738
- package/src/outbox-attachment.ts +0 -536
- package/src/outbox-failed-recovery.test.ts +0 -370
- package/src/outbox-queue-settled-row.test.ts +0 -140
- package/src/outbox-queue.test.ts +0 -291
- package/src/outbox-queue.ts +0 -508
- package/src/pass-through-unit-of-work.ts +0 -17
- package/src/placement-move-terminal.test.ts +0 -300
- package/src/placement-move-terminal.ts +0 -148
- package/src/placement-move-unsettled.test.ts +0 -275
- package/src/placement-move.ts +0 -336
- package/src/placement-settled.test.ts +0 -147
- package/src/placement-transition-race.test.ts +0 -482
- package/src/quarantine.test.ts +0 -191
- package/src/quarantine.ts +0 -228
- package/src/snippet.test.ts +0 -213
- package/src/snippet.ts +0 -152
- package/src/spam-report.test.ts +0 -801
- package/src/spam-report.ts +0 -357
- package/src/stale-message-reconcile.test.ts +0 -82
- package/src/stale-message-reconcile.ts +0 -55
- package/src/sync-watermarks.test.ts +0 -409
- package/src/sync-watermarks.ts +0 -319
- package/src/system-flag-wire-format.test.ts +0 -77
- package/src/test-helpers/folder-roles.ts +0 -66
- package/src/test-helpers/isolated-mailbox.ts +0 -44
- package/src/test-helpers/mailfuzz-connection.ts +0 -27
- package/src/test-helpers/mime-tree-generator.ts +0 -461
- package/src/text/normalizer.test.ts +0 -223
- package/src/text/normalizer.ts +0 -140
- package/src/thread-message-rows.ts +0 -77
- package/src/types/mailparser-augment.d.ts +0 -15
- package/src/types/natural-porter-stemmer.d.ts +0 -50
- package/src/types/stopword.d.ts +0 -69
- package/src/types.ts +0 -371
- package/test/fixtures/mime-adversarial-e2e/01-octet-stream-pdf.eml +0 -21
- package/test/fixtures/mime-adversarial-e2e/02-nested-related-cid-image.eml +0 -31
- package/test/fixtures/mime-adversarial-e2e/03-calendar-invite.eml +0 -33
- package/test/fixtures/mime-adversarial-e2e/04-forwarded-rfc822-with-attachments.eml +0 -42
- package/test/fixtures/mime-adversarial-e2e/05-tnef-winmail.eml +0 -25
- package/test/fixtures/mime-adversarial-e2e/06-8bit-non-ascii.eml +0 -15
- package/test/fixtures/mime-adversarial-e2e/07-quoted-printable-soft-breaks.eml +0 -17
- package/test/fixtures/mime-adversarial-e2e/08-alternative-empty-text.eml +0 -18
- package/tsconfig.json +0 -8
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { describe, it } from "node:test";
|
|
3
|
-
import type {
|
|
4
|
-
IAddressRepository,
|
|
5
|
-
IMailboxRepository,
|
|
6
|
-
IMailboxSpecialUseRepository,
|
|
7
|
-
IMessageRepository,
|
|
8
|
-
IThreadMessageRepository,
|
|
9
|
-
} from "@remit/data-ports";
|
|
10
|
-
import { type MessageMoveConfig, MessageMoveService } from "./message-move.js";
|
|
11
|
-
import { NO_JUNK_ROLES, trashRole } from "./test-helpers/folder-roles.js";
|
|
12
|
-
|
|
13
|
-
const ACCOUNT = "acc-1";
|
|
14
|
-
const ACCOUNT_CONFIG = "cfg-1";
|
|
15
|
-
const INBOX = "mbx-inbox";
|
|
16
|
-
const TRASH = "mbx-trash";
|
|
17
|
-
const MESSAGE_ID = "msg-1";
|
|
18
|
-
|
|
19
|
-
const buildWorld = (trashExists: boolean) => {
|
|
20
|
-
const reconciled: string[] = [];
|
|
21
|
-
const message = {
|
|
22
|
-
messageId: MESSAGE_ID,
|
|
23
|
-
mailboxId: INBOX,
|
|
24
|
-
uid: 337,
|
|
25
|
-
status: "active",
|
|
26
|
-
syncStatus: "synced",
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const messageService = {
|
|
30
|
-
get: async () => [message],
|
|
31
|
-
update: async (_id: string, patch: Record<string, unknown>) =>
|
|
32
|
-
Object.assign(message, patch),
|
|
33
|
-
transitionPlacement: async (
|
|
34
|
-
_id: string,
|
|
35
|
-
_expected: Record<string, unknown>,
|
|
36
|
-
patch: Record<string, unknown>,
|
|
37
|
-
) => Object.assign(message, patch),
|
|
38
|
-
} as unknown as IMessageRepository;
|
|
39
|
-
|
|
40
|
-
const threadMessageService = {
|
|
41
|
-
findAllByMessageId: async () => [],
|
|
42
|
-
getByMessageId: async () => ({
|
|
43
|
-
accountConfigId: ACCOUNT_CONFIG,
|
|
44
|
-
threadMessageId: "tm-1",
|
|
45
|
-
messageId: MESSAGE_ID,
|
|
46
|
-
mailboxId: INBOX,
|
|
47
|
-
}),
|
|
48
|
-
update: async () => {},
|
|
49
|
-
delete: async () => {},
|
|
50
|
-
} as unknown as IThreadMessageRepository;
|
|
51
|
-
|
|
52
|
-
const mailboxService = {
|
|
53
|
-
get: async () => [
|
|
54
|
-
{ mailboxId: INBOX, fullPath: "INBOX", accountId: ACCOUNT },
|
|
55
|
-
],
|
|
56
|
-
} as unknown as IMailboxRepository;
|
|
57
|
-
|
|
58
|
-
const trash = trashExists ? { mailboxId: TRASH, fullPath: "Trash" } : null;
|
|
59
|
-
|
|
60
|
-
const mailboxSpecialUseService = {
|
|
61
|
-
findTrashMailbox: async () => trash,
|
|
62
|
-
resolveTrashRole: async () => trashRole(trash),
|
|
63
|
-
resolveJunkRolesForConfig: async () => NO_JUNK_ROLES,
|
|
64
|
-
} as unknown as IMailboxSpecialUseRepository;
|
|
65
|
-
|
|
66
|
-
const addressService = {
|
|
67
|
-
reconcileJunkOnlyForMessage: async (messageId: string) => {
|
|
68
|
-
reconciled.push(`${messageId}@${message.mailboxId}`);
|
|
69
|
-
},
|
|
70
|
-
} as unknown as IAddressRepository;
|
|
71
|
-
|
|
72
|
-
const config: MessageMoveConfig = {
|
|
73
|
-
messageService,
|
|
74
|
-
mailboxService,
|
|
75
|
-
mailboxSpecialUseService,
|
|
76
|
-
threadMessageService,
|
|
77
|
-
addressService,
|
|
78
|
-
sqsQueueUrl: "http://localhost:9324/000000000000/remit-messages.fifo",
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const service = new MessageMoveService(config);
|
|
82
|
-
(
|
|
83
|
-
service as unknown as { enqueueEventsBatch: () => Promise<void> }
|
|
84
|
-
).enqueueEventsBatch = async () => {};
|
|
85
|
-
|
|
86
|
-
return { service, reconciled };
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
describe("deleting a message re-asks what its senders stand on", () => {
|
|
90
|
-
it("re-asks when the delete moves the message to Trash", async () => {
|
|
91
|
-
const { service, reconciled } = buildWorld(true);
|
|
92
|
-
|
|
93
|
-
await service.deleteMessages(ACCOUNT_CONFIG, [MESSAGE_ID], ACCOUNT);
|
|
94
|
-
|
|
95
|
-
assert.deepEqual(reconciled, [`${MESSAGE_ID}@${TRASH}`]);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it("asks nothing when the delete is permanent", async () => {
|
|
99
|
-
const { service, reconciled } = buildWorld(true);
|
|
100
|
-
|
|
101
|
-
await service.deleteMessages(ACCOUNT_CONFIG, [MESSAGE_ID], ACCOUNT, {
|
|
102
|
-
permanent: true,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
assert.deepEqual(reconciled, []);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it("asks nothing when the account has no Trash folder, because the delete is refused", async () => {
|
|
109
|
-
const { service, reconciled } = buildWorld(false);
|
|
110
|
-
|
|
111
|
-
await assert.rejects(() =>
|
|
112
|
-
service.deleteMessages(ACCOUNT_CONFIG, [MESSAGE_ID], ACCOUNT),
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
assert.deepEqual(reconciled, []);
|
|
116
|
-
});
|
|
117
|
-
});
|
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { describe, it } from "node:test";
|
|
3
|
-
import type {
|
|
4
|
-
IAddressRepository,
|
|
5
|
-
IMailboxRepository,
|
|
6
|
-
IMailboxSpecialUseRepository,
|
|
7
|
-
IMessageRepository,
|
|
8
|
-
IThreadMessageRepository,
|
|
9
|
-
} from "@remit/data-ports";
|
|
10
|
-
import type { RoleResolution } from "@remit/data-ports/folder-role";
|
|
11
|
-
import {
|
|
12
|
-
type MessageMoveConfig,
|
|
13
|
-
MessageMoveService,
|
|
14
|
-
NoTrashMailboxError,
|
|
15
|
-
StaleTrashAppointmentError,
|
|
16
|
-
UnconfirmedTrashMailboxError,
|
|
17
|
-
} from "./message-move.js";
|
|
18
|
-
import { NO_JUNK_ROLES } from "./test-helpers/folder-roles.js";
|
|
19
|
-
|
|
20
|
-
const ACCOUNT = "acc-1";
|
|
21
|
-
const ACCOUNT_CONFIG = "cfg-1";
|
|
22
|
-
const INBOX = "mbx-inbox";
|
|
23
|
-
const TRASH = "mbx-trash";
|
|
24
|
-
const MESSAGE_ID = "msg-1";
|
|
25
|
-
|
|
26
|
-
type TrashMailbox = { mailboxId: string; fullPath: string };
|
|
27
|
-
|
|
28
|
-
interface EnqueuedEvent {
|
|
29
|
-
operation: string;
|
|
30
|
-
destinationMailboxPath?: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const buildWorld = (
|
|
34
|
-
trashResolution: RoleResolution<TrashMailbox>,
|
|
35
|
-
startingMailboxId = INBOX,
|
|
36
|
-
) => {
|
|
37
|
-
const patches: Array<Record<string, unknown>> = [];
|
|
38
|
-
const events: EnqueuedEvent[] = [];
|
|
39
|
-
const threadMessageDeletes: string[] = [];
|
|
40
|
-
|
|
41
|
-
const message = {
|
|
42
|
-
messageId: MESSAGE_ID,
|
|
43
|
-
mailboxId: startingMailboxId,
|
|
44
|
-
uid: 337,
|
|
45
|
-
status: "active",
|
|
46
|
-
syncStatus: "synced",
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const messageService = {
|
|
50
|
-
get: async () => [message],
|
|
51
|
-
update: async (_id: string, patch: Record<string, unknown>) => {
|
|
52
|
-
patches.push(patch);
|
|
53
|
-
return Object.assign(message, patch);
|
|
54
|
-
},
|
|
55
|
-
transitionPlacement: async (
|
|
56
|
-
_id: string,
|
|
57
|
-
_expected: Record<string, unknown>,
|
|
58
|
-
patch: Record<string, unknown>,
|
|
59
|
-
) => {
|
|
60
|
-
patches.push(patch);
|
|
61
|
-
return Object.assign(message, patch);
|
|
62
|
-
},
|
|
63
|
-
} as unknown as IMessageRepository;
|
|
64
|
-
|
|
65
|
-
const threadMessageService = {
|
|
66
|
-
findAllByMessageId: async () => [],
|
|
67
|
-
getByMessageId: async () => ({
|
|
68
|
-
accountConfigId: ACCOUNT_CONFIG,
|
|
69
|
-
threadMessageId: "tm-1",
|
|
70
|
-
messageId: MESSAGE_ID,
|
|
71
|
-
mailboxId: startingMailboxId,
|
|
72
|
-
}),
|
|
73
|
-
update: async () => {},
|
|
74
|
-
delete: async (_cfg: string, id: string) => {
|
|
75
|
-
threadMessageDeletes.push(id);
|
|
76
|
-
},
|
|
77
|
-
} as unknown as IThreadMessageRepository;
|
|
78
|
-
|
|
79
|
-
const mailboxService = {
|
|
80
|
-
get: async () => [
|
|
81
|
-
{ mailboxId: INBOX, fullPath: "INBOX", accountId: ACCOUNT },
|
|
82
|
-
{ mailboxId: TRASH, fullPath: "INBOX/Trash", accountId: ACCOUNT },
|
|
83
|
-
],
|
|
84
|
-
} as unknown as IMailboxRepository;
|
|
85
|
-
|
|
86
|
-
const mailboxSpecialUseService = {
|
|
87
|
-
resolveTrashRole: async () => trashResolution,
|
|
88
|
-
resolveJunkRolesForConfig: async () => NO_JUNK_ROLES,
|
|
89
|
-
} as unknown as IMailboxSpecialUseRepository;
|
|
90
|
-
|
|
91
|
-
const addressService = {
|
|
92
|
-
reconcileJunkOnlyForMessage: async () => {},
|
|
93
|
-
} as unknown as IAddressRepository;
|
|
94
|
-
|
|
95
|
-
const config: MessageMoveConfig = {
|
|
96
|
-
messageService,
|
|
97
|
-
mailboxService,
|
|
98
|
-
mailboxSpecialUseService,
|
|
99
|
-
threadMessageService,
|
|
100
|
-
addressService,
|
|
101
|
-
sqsQueueUrl: "http://localhost:9324/000000000000/remit-messages.fifo",
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const service = new MessageMoveService(config);
|
|
105
|
-
(
|
|
106
|
-
service as unknown as {
|
|
107
|
-
enqueueEventsBatch: (batch: EnqueuedEvent[]) => Promise<void>;
|
|
108
|
-
}
|
|
109
|
-
).enqueueEventsBatch = async (batch) => {
|
|
110
|
-
events.push(...batch);
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
return { service, patches, events, message };
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const flaggedTrash: RoleResolution<TrashMailbox> = {
|
|
117
|
-
kind: "flagged",
|
|
118
|
-
mailbox: { mailboxId: TRASH, fullPath: "INBOX/Trash" },
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
describe("delete only expunges when it was asked to", () => {
|
|
122
|
-
it("moves to a Trash the account resolves under a nested path", async () => {
|
|
123
|
-
const { service, events, message } = buildWorld(flaggedTrash);
|
|
124
|
-
|
|
125
|
-
await service.deleteMessages(ACCOUNT_CONFIG, [MESSAGE_ID], ACCOUNT);
|
|
126
|
-
|
|
127
|
-
assert.deepEqual(
|
|
128
|
-
events.map((event) => event.operation),
|
|
129
|
-
["move_to_trash"],
|
|
130
|
-
);
|
|
131
|
-
assert.equal(events[0].destinationMailboxPath, "INBOX/Trash");
|
|
132
|
-
assert.equal(message.mailboxId, TRASH);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("refuses, and touches nothing, when no Trash resolves", async () => {
|
|
136
|
-
const { service, patches, events, message } = buildWorld({ kind: "none" });
|
|
137
|
-
|
|
138
|
-
await assert.rejects(
|
|
139
|
-
() => service.deleteMessages(ACCOUNT_CONFIG, [MESSAGE_ID], ACCOUNT),
|
|
140
|
-
(error: unknown) =>
|
|
141
|
-
error instanceof NoTrashMailboxError &&
|
|
142
|
-
error.statusCode === 409 &&
|
|
143
|
-
error.publicApiError?.details?.reason === "none" &&
|
|
144
|
-
error.message.includes("no Trash folder"),
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
assert.deepEqual(events, []);
|
|
148
|
-
assert.deepEqual(patches, []);
|
|
149
|
-
assert.equal(message.mailboxId, INBOX);
|
|
150
|
-
assert.equal(message.status, "active");
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it("refuses a stale appointment rather than filing into the fallback", async () => {
|
|
154
|
-
// #887 Done item 2: the user appointed a folder another client has since
|
|
155
|
-
// deleted. Silently filing 200 messages into the flagged folder overrides
|
|
156
|
-
// a choice they made and cannot see was lost.
|
|
157
|
-
const { service, patches, events, message } = buildWorld({
|
|
158
|
-
kind: "appointment_stale",
|
|
159
|
-
appointedMailboxId: "mbx-appointed-and-gone",
|
|
160
|
-
fallback: flaggedTrash,
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
await assert.rejects(
|
|
164
|
-
() => service.deleteMessages(ACCOUNT_CONFIG, [MESSAGE_ID], ACCOUNT),
|
|
165
|
-
(error: unknown) =>
|
|
166
|
-
error instanceof StaleTrashAppointmentError &&
|
|
167
|
-
error.statusCode === 409 &&
|
|
168
|
-
error.publicApiError?.details?.reason === "stale" &&
|
|
169
|
-
error.publicApiError?.details?.accountId === ACCOUNT,
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
assert.deepEqual(events, []);
|
|
173
|
-
assert.deepEqual(patches, []);
|
|
174
|
-
assert.equal(message.mailboxId, INBOX);
|
|
175
|
-
assert.equal(message.status, "active");
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it("files into a Trash that resolves by name alone", async () => {
|
|
179
|
-
// A name guess is enough to move mail somewhere retrievable; only the
|
|
180
|
-
// expunge demands more (D4).
|
|
181
|
-
const { service, events, message } = buildWorld({
|
|
182
|
-
kind: "proposed",
|
|
183
|
-
mailbox: { mailboxId: TRASH, fullPath: "Trash" },
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
await service.deleteMessages(ACCOUNT_CONFIG, [MESSAGE_ID], ACCOUNT);
|
|
187
|
-
|
|
188
|
-
assert.deepEqual(
|
|
189
|
-
events.map((event) => event.operation),
|
|
190
|
-
["move_to_trash"],
|
|
191
|
-
);
|
|
192
|
-
assert.equal(message.mailboxId, TRASH);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
it("expunges only when the caller asked for a permanent delete", async () => {
|
|
196
|
-
// fc685509: an explicit permanent delete never resolves Trash at all, so
|
|
197
|
-
// an account with none can still empty a message it selected.
|
|
198
|
-
const { service, events } = buildWorld({ kind: "none" });
|
|
199
|
-
|
|
200
|
-
await service.deleteMessages(ACCOUNT_CONFIG, [MESSAGE_ID], ACCOUNT, {
|
|
201
|
-
permanent: true,
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
assert.deepEqual(
|
|
205
|
-
events.map((event) => event.operation),
|
|
206
|
-
["permanent_delete"],
|
|
207
|
-
);
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it("refuses to expunge a message already inside a Trash that only resolves by name", async () => {
|
|
211
|
-
// #876: a message already sitting in the guessed folder used to fall
|
|
212
|
-
// straight through to an expunge, on the same name guess Empty Trash
|
|
213
|
-
// refuses to act on. Deleting it is exactly as unrecoverable, so it
|
|
214
|
-
// demands the same confirmed evidence — nobody, neither the user nor the
|
|
215
|
-
// server, ever said this folder is Trash.
|
|
216
|
-
const { service, patches, events, message } = buildWorld(
|
|
217
|
-
{ kind: "proposed", mailbox: { mailboxId: TRASH, fullPath: "Trash" } },
|
|
218
|
-
TRASH,
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
await assert.rejects(
|
|
222
|
-
() => service.deleteMessages(ACCOUNT_CONFIG, [MESSAGE_ID], ACCOUNT),
|
|
223
|
-
(error: unknown) =>
|
|
224
|
-
error instanceof UnconfirmedTrashMailboxError &&
|
|
225
|
-
error.statusCode === 409 &&
|
|
226
|
-
error.publicApiError?.details?.reason === "unconfirmed" &&
|
|
227
|
-
error.publicApiError?.details?.accountId === ACCOUNT,
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
assert.deepEqual(events, []);
|
|
231
|
-
assert.deepEqual(patches, []);
|
|
232
|
-
assert.equal(message.mailboxId, TRASH);
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
it("expunges a message already inside a confirmed Trash", async () => {
|
|
236
|
-
const { service, events } = buildWorld(flaggedTrash, TRASH);
|
|
237
|
-
|
|
238
|
-
await service.deleteMessages(ACCOUNT_CONFIG, [MESSAGE_ID], ACCOUNT);
|
|
239
|
-
|
|
240
|
-
assert.deepEqual(
|
|
241
|
-
events.map((event) => event.operation),
|
|
242
|
-
["permanent_delete"],
|
|
243
|
-
);
|
|
244
|
-
});
|
|
245
|
-
});
|