@remit/mailbox-service 0.0.110 → 0.0.112
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 +21 -6
- package/src/body-part-mapper.ts +51 -1
- package/src/body-sync-queue.test.ts +39 -99
- package/src/body-sync-terminal.test.ts +115 -277
- package/src/body-sync-terminal.ts +10 -12
- package/src/body-sync.test.ts +925 -0
- package/src/body-sync.ts +226 -200
- package/src/classification-backfill.test.ts +197 -527
- package/src/classify-message.test.ts +11 -74
- package/src/external-move.test.ts +102 -209
- package/src/external-move.ts +13 -0
- package/src/filter-operations.test.ts +319 -0
- package/src/filter-operations.ts +377 -0
- package/src/filter-update.test.ts +313 -0
- package/src/filters/filter-config.test.ts +55 -197
- package/src/filters/filter-config.ts +4 -39
- package/src/filters/match.test.ts +1 -38
- package/src/filters/match.ts +3 -52
- package/src/filters/pipeline.test.ts +158 -289
- package/src/filters/pipeline.ts +56 -170
- package/src/flag-push-terminal.ts +9 -11
- package/src/flag-push.test.ts +76 -372
- package/src/flag-queue.test.ts +197 -0
- package/src/folder-operations.test.ts +273 -0
- package/src/folder-operations.ts +217 -0
- package/src/forwarded-message.test.ts +122 -0
- package/src/imapflow-connect-retry.test.ts +76 -113
- package/src/imapflow-connection.test.ts +34 -0
- package/src/imapflow-connection.ts +19 -15
- package/src/index.ts +59 -12
- package/src/list-id-backfill.test.ts +133 -499
- package/src/mailbox-cursor.test.ts +81 -189
- package/src/mailbox-delete-intent.test.ts +78 -205
- package/src/mailbox-intent.ts +5 -3
- package/src/mailbox-management.test.ts +107 -220
- package/src/mailbox-management.ts +1 -2
- package/src/mailbox-presence.test.ts +36 -34
- package/src/mailbox-queue.ts +2 -20
- package/src/mailbox-rename-intent.test.ts +156 -325
- package/src/mailbox-rename-subtree.test.ts +205 -582
- package/src/mailbox-sync.test.ts +182 -744
- package/src/message-move.test.ts +726 -0
- package/src/message-move.ts +227 -57
- package/src/message-read.ts +87 -0
- package/src/message-save-retry.test.ts +90 -0
- package/src/message-sync-flags.test.ts +10 -1
- package/src/message-sync.test.ts +762 -0
- package/src/message-sync.ts +409 -239
- package/src/mime-walker.ts +16 -15
- package/src/organize-job.ts +93 -0
- package/src/outbox-attachment.test.ts +97 -209
- package/src/outbox-failed-recovery.test.ts +198 -269
- package/src/outbox-queue.test.ts +24 -0
- package/src/outbox-queue.ts +25 -8
- package/src/ownership.ts +140 -0
- package/src/placement-move-terminal.ts +9 -12
- package/src/placement-move.ts +33 -6
- package/src/placement-settled.ts +28 -4
- package/src/placement.test.ts +404 -0
- package/src/quarantine.test.ts +90 -148
- package/src/quarantine.ts +3 -2
- package/src/refusal.ts +29 -0
- package/src/restore-source-placement.ts +0 -4
- package/src/spam-report.test.ts +238 -710
- package/src/sync-warning.test.ts +213 -0
- package/src/sync-warning.ts +56 -0
- package/src/test-helpers/fake-imap.ts +690 -0
- package/src/test-helpers/test-queue.ts +56 -0
- package/src/test-helpers/test-store.ts +299 -0
- package/src/thread-root.test.ts +29 -0
- package/src/thread-root.ts +51 -0
- package/src/types/mailparser-augment.d.ts +8 -0
- package/src/types.ts +1 -1
- package/src/adversarial-mime.e2e.test.ts +0 -307
- 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-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-resync.test.ts +0 -605
- package/src/body-sync-unclassifiable-once.test.ts +0 -260
- package/src/body-sync-unsubscribed-auto-read.test.ts +0 -176
- package/src/filters/anchor-drift.ts +0 -55
- package/src/filters/message-embedder.test.ts +0 -39
- package/src/filters/message-embedder.ts +0 -33
- package/src/flag-push-terminal.test.ts +0 -209
- package/src/flag-queue-stars.test.ts +0 -171
- package/src/imapflow-connection.e2e.test.ts +0 -335
- package/src/imapflow-connection.integ.test.ts +0 -316
- 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-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-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/outbox-queue-settled-row.test.ts +0 -140
- package/src/pass-through-unit-of-work.ts +0 -17
- package/src/placement-move-terminal.test.ts +0 -300
- package/src/placement-move-unsettled.test.ts +0 -275
- package/src/placement-transition-race.test.ts +0 -482
- package/src/stale-message-reconcile.test.ts +0 -82
- package/src/stale-message-reconcile.ts +0 -55
- package/src/test-helpers/isolated-mailbox.ts +0 -44
- package/src/test-helpers/mailfuzz-connection.ts +0 -27
- 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
|
@@ -1,134 +1,97 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for ImapFlowConnection.connect() retry semantics.
|
|
3
|
-
*
|
|
4
|
-
* Verifies the retry policy without touching a real IMAP server:
|
|
5
|
-
* - Network errors (e.g. ECONNREFUSED) are retried with backoff before the
|
|
6
|
-
* classified MailConnectionError("network") is finally thrown.
|
|
7
|
-
* - Auth errors are thrown immediately and NEVER retried.
|
|
8
|
-
*
|
|
9
|
-
* The private `attemptConnect` and `sleep` instance methods are stubbed so the
|
|
10
|
-
* test exercises the loop logic directly and runs instantly.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
1
|
import assert from "node:assert/strict";
|
|
14
|
-
import {
|
|
2
|
+
import { createServer, type Server, type Socket } from "node:net";
|
|
3
|
+
import { after, describe, it } from "node:test";
|
|
15
4
|
import { ImapFlowConnection } from "./imapflow-connection.js";
|
|
16
5
|
import { MailConnectionError } from "./types.js";
|
|
17
6
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
port: 143,
|
|
21
|
-
user: "alice@example.com",
|
|
22
|
-
credentials: { kind: "password" as const, password: "s3cr3t" },
|
|
23
|
-
tls: false,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
type WithPrivates = {
|
|
27
|
-
attemptConnect: () => Promise<void>;
|
|
28
|
-
sleep: (ms: number) => Promise<void>;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const makeErrnoError = (code: string): Error => {
|
|
32
|
-
const err = new Error(`connect ${code}`);
|
|
33
|
-
return Object.assign(err, { code });
|
|
34
|
-
};
|
|
7
|
+
const servers: Server[] = [];
|
|
8
|
+
const sockets: Socket[] = [];
|
|
35
9
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
10
|
+
after(() => {
|
|
11
|
+
for (const socket of sockets) socket.destroy();
|
|
12
|
+
for (const server of servers) server.close();
|
|
13
|
+
});
|
|
40
14
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
15
|
+
const listen = (server: Server): Promise<number> =>
|
|
16
|
+
new Promise((resolve) => {
|
|
17
|
+
servers.push(server);
|
|
18
|
+
server.listen(0, "127.0.0.1", () => {
|
|
19
|
+
const address = server.address();
|
|
20
|
+
resolve(typeof address === "object" && address ? address.port : 0);
|
|
44
21
|
});
|
|
45
|
-
// Stub sleep so the backoff does not actually delay the test.
|
|
46
|
-
mock.method(priv, "sleep", async () => {});
|
|
47
|
-
|
|
48
|
-
await assert.rejects(
|
|
49
|
-
() => connection.connect(),
|
|
50
|
-
(error: unknown) => {
|
|
51
|
-
assert.ok(
|
|
52
|
-
error instanceof MailConnectionError,
|
|
53
|
-
"final error should be a MailConnectionError",
|
|
54
|
-
);
|
|
55
|
-
assert.equal(error.kind, "network");
|
|
56
|
-
// The host:port endpoint must appear in the message so a DNS /
|
|
57
|
-
// connect failure is self-describing in the logs (issue #835).
|
|
58
|
-
assert.match(error.message, /localhost:143/);
|
|
59
|
-
return true;
|
|
60
|
-
},
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
// 3 attempts total (the retry loop runs maxRetries times).
|
|
64
|
-
assert.equal(attempt.mock.callCount(), 3);
|
|
65
22
|
});
|
|
66
23
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
24
|
+
const refusingLogin = async (refusal: string) => {
|
|
25
|
+
const state = { connections: 0 };
|
|
26
|
+
const server = createServer((socket) => {
|
|
27
|
+
state.connections++;
|
|
28
|
+
sockets.push(socket);
|
|
29
|
+
socket.write("* OK [CAPABILITY IMAP4rev1] ready\r\n");
|
|
30
|
+
let buffered = "";
|
|
31
|
+
socket.on("data", (chunk) => {
|
|
32
|
+
buffered += chunk.toString();
|
|
33
|
+
let end = buffered.indexOf("\r\n");
|
|
34
|
+
while (end !== -1) {
|
|
35
|
+
const line = buffered.slice(0, end);
|
|
36
|
+
buffered = buffered.slice(end + 2);
|
|
37
|
+
const [tag, command] = line.split(" ");
|
|
38
|
+
const verb = command?.toUpperCase();
|
|
39
|
+
if (verb === "CAPABILITY") {
|
|
40
|
+
socket.write(`* CAPABILITY IMAP4rev1\r\n${tag} OK done\r\n`);
|
|
41
|
+
} else if (verb === "LOGIN") {
|
|
42
|
+
socket.write(`${tag} NO [AUTHENTICATIONFAILED] ${refusal}\r\n`);
|
|
43
|
+
} else if (verb === "LOGOUT") {
|
|
44
|
+
socket.end(`* BYE\r\n${tag} OK bye\r\n`);
|
|
45
|
+
} else {
|
|
46
|
+
socket.write(`${tag} BAD unknown\r\n`);
|
|
47
|
+
}
|
|
48
|
+
end = buffered.indexOf("\r\n");
|
|
76
49
|
}
|
|
77
|
-
// Second attempt succeeds.
|
|
78
50
|
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
await connection.connect();
|
|
82
|
-
|
|
83
|
-
assert.equal(attempt.mock.callCount(), 2);
|
|
51
|
+
socket.on("error", () => {});
|
|
84
52
|
});
|
|
53
|
+
return { port: await listen(server), state };
|
|
54
|
+
};
|
|
85
55
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
93
|
-
const sleep = mock.method(priv, "sleep", async () => {});
|
|
56
|
+
const closedPort = async (): Promise<number> => {
|
|
57
|
+
const server = createServer();
|
|
58
|
+
const port = await listen(server);
|
|
59
|
+
await new Promise((resolve) => server.close(resolve));
|
|
60
|
+
return port;
|
|
61
|
+
};
|
|
94
62
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
63
|
+
const connectTo = (port: number) =>
|
|
64
|
+
new ImapFlowConnection({
|
|
65
|
+
host: "127.0.0.1",
|
|
66
|
+
port,
|
|
67
|
+
user: "alice@example.com",
|
|
68
|
+
credentials: { kind: "password", password: "s3cr3t" },
|
|
69
|
+
tls: false,
|
|
70
|
+
}).connect();
|
|
103
71
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
72
|
+
describe("ImapFlowConnection.connect() retry policy", () => {
|
|
73
|
+
it("retries a refused connection, then names the endpoint in a network error", async () => {
|
|
74
|
+
const port = await closedPort();
|
|
75
|
+
|
|
76
|
+
await assert.rejects(connectTo(port), (error: unknown) => {
|
|
77
|
+
assert.ok(error instanceof MailConnectionError);
|
|
78
|
+
assert.equal(error.kind, "network");
|
|
79
|
+
assert.match(error.message, new RegExp(`127\\.0\\.0\\.1:${port}`));
|
|
80
|
+
return true;
|
|
81
|
+
});
|
|
107
82
|
});
|
|
108
83
|
|
|
109
|
-
it("carries the server's own
|
|
110
|
-
const
|
|
111
|
-
|
|
84
|
+
it("does not retry a refused login and carries the server's own words", async () => {
|
|
85
|
+
const { port, state } = await refusingLogin(
|
|
86
|
+
"LOGIN failed. SmtpClientAuthentication is disabled for the Tenant.",
|
|
87
|
+
);
|
|
112
88
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
authenticationFailed: true,
|
|
119
|
-
responseText:
|
|
120
|
-
"LOGIN failed. User is authenticated but not connected. SmtpClientAuthentication is disabled for the Tenant.",
|
|
121
|
-
});
|
|
89
|
+
await assert.rejects(connectTo(port), (error: unknown) => {
|
|
90
|
+
assert.ok(error instanceof MailConnectionError);
|
|
91
|
+
assert.equal(error.kind, "auth");
|
|
92
|
+
assert.match(error.message, /SmtpClientAuthentication is disabled/);
|
|
93
|
+
return true;
|
|
122
94
|
});
|
|
123
|
-
|
|
124
|
-
await assert.rejects(
|
|
125
|
-
() => connection.connect(),
|
|
126
|
-
(error: unknown) => {
|
|
127
|
-
assert.ok(error instanceof MailConnectionError);
|
|
128
|
-
assert.equal(error.kind, "auth");
|
|
129
|
-
assert.match(error.message, /SmtpClientAuthentication is disabled/);
|
|
130
|
-
return true;
|
|
131
|
-
},
|
|
132
|
-
);
|
|
95
|
+
assert.equal(state.connections, 1);
|
|
133
96
|
});
|
|
134
97
|
});
|
|
@@ -467,3 +467,37 @@ describe("ImapFlowConnection message envelopes (issue #72)", () => {
|
|
|
467
467
|
assert.equal(message?.envelope?.from[0]?.mailbox, "sender");
|
|
468
468
|
});
|
|
469
469
|
});
|
|
470
|
+
|
|
471
|
+
describe("ImapFlowConnection.fetchMessageBodies — a body the server no longer has", () => {
|
|
472
|
+
const fetchBodies = async (
|
|
473
|
+
rows: Array<Record<string, unknown>>,
|
|
474
|
+
): Promise<number[]> => {
|
|
475
|
+
const connection = buildConnectionWithClient({
|
|
476
|
+
mailbox: fakeMailbox("INBOX", 1),
|
|
477
|
+
mailboxOpen: async (path: string) => fakeMailbox(path, 1),
|
|
478
|
+
fetch: () =>
|
|
479
|
+
(async function* () {
|
|
480
|
+
for (const row of rows) yield row;
|
|
481
|
+
})(),
|
|
482
|
+
});
|
|
483
|
+
Object.assign(connection as unknown as Record<string, unknown>, {
|
|
484
|
+
currentMailbox: "INBOX",
|
|
485
|
+
});
|
|
486
|
+
const uids: number[] = [];
|
|
487
|
+
for await (const { uid, source } of connection.fetchMessageBodies([1, 2])) {
|
|
488
|
+
source.resume();
|
|
489
|
+
uids.push(uid);
|
|
490
|
+
}
|
|
491
|
+
return uids;
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
it("leaves out a row whose source is false instead of failing the batch", async () => {
|
|
495
|
+
assert.deepStrictEqual(
|
|
496
|
+
await fetchBodies([
|
|
497
|
+
{ uid: 1, source: false },
|
|
498
|
+
{ uid: 2, source: Buffer.from("Subject: x\r\n\r\nhi") },
|
|
499
|
+
]),
|
|
500
|
+
[2],
|
|
501
|
+
);
|
|
502
|
+
});
|
|
503
|
+
});
|
|
@@ -721,9 +721,9 @@ export class ImapFlowConnection {
|
|
|
721
721
|
* Fetch the full message body (RFC822 source) for a single message by UID.
|
|
722
722
|
*
|
|
723
723
|
* @param uid - The UID of the message to fetch
|
|
724
|
-
* @returns The raw message body
|
|
724
|
+
* @returns The raw message body, or null when the UID FETCH matched no message
|
|
725
725
|
*/
|
|
726
|
-
fetchMessageBody = async (uid: number): Promise<Buffer> => {
|
|
726
|
+
fetchMessageBody = async (uid: number): Promise<Buffer | null> => {
|
|
727
727
|
this.ensureConnected();
|
|
728
728
|
const { client } = this;
|
|
729
729
|
|
|
@@ -739,19 +739,22 @@ export class ImapFlowConnection {
|
|
|
739
739
|
uid: true,
|
|
740
740
|
});
|
|
741
741
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
742
|
+
if (result?.content) {
|
|
743
|
+
const chunks: Buffer[] = [];
|
|
744
|
+
for await (const chunk of result.content) {
|
|
745
|
+
chunks.push(chunk);
|
|
746
|
+
}
|
|
747
|
+
return Buffer.concat(chunks);
|
|
747
748
|
}
|
|
748
749
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
750
|
+
if (!client.usable || !client.mailbox) {
|
|
751
|
+
throw new MailConnectionError(
|
|
752
|
+
"network",
|
|
753
|
+
`IMAP connection lost while downloading message UID ${uid}`,
|
|
754
|
+
);
|
|
752
755
|
}
|
|
753
756
|
|
|
754
|
-
return
|
|
757
|
+
return null;
|
|
755
758
|
};
|
|
756
759
|
|
|
757
760
|
/**
|
|
@@ -802,10 +805,11 @@ export class ImapFlowConnection {
|
|
|
802
805
|
try {
|
|
803
806
|
for await (const msg of fetchIterator) {
|
|
804
807
|
// imapflow can yield a row with an undefined uid or no source on
|
|
805
|
-
// back-to-back FETCH calls
|
|
806
|
-
//
|
|
807
|
-
//
|
|
808
|
-
|
|
808
|
+
// back-to-back FETCH calls, and Dovecot answers `source: false` for a
|
|
809
|
+
// message another client expunged; skip it rather than crash the batch
|
|
810
|
+
// — the caller treats any UID it never sees as failed and re-enqueues
|
|
811
|
+
// it. See #408.
|
|
812
|
+
if (msg.uid == null || !msg.source) {
|
|
809
813
|
continue;
|
|
810
814
|
}
|
|
811
815
|
|
package/src/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ export {
|
|
|
27
27
|
export {
|
|
28
28
|
type BodySyncFolder,
|
|
29
29
|
type BodySyncLogger,
|
|
30
|
+
type BodySyncRoundFolder,
|
|
30
31
|
BodySyncService,
|
|
31
32
|
type ConnectionGetter,
|
|
32
33
|
extractSnippet,
|
|
@@ -81,16 +82,18 @@ export {
|
|
|
81
82
|
testSmtpConnection,
|
|
82
83
|
} from "./connection-test.js";
|
|
83
84
|
export {
|
|
84
|
-
type
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
type CreatedFilter,
|
|
86
|
+
createFilter,
|
|
87
|
+
type FilterPage,
|
|
88
|
+
type FilterPatch,
|
|
89
|
+
listFilters,
|
|
90
|
+
type NewFilter,
|
|
91
|
+
resolveFilterUpdate,
|
|
92
|
+
updateFilter,
|
|
93
|
+
} from "./filter-operations.js";
|
|
88
94
|
export { extractListId, normalizeListId } from "./filters/list-id.js";
|
|
89
95
|
export {
|
|
90
|
-
buildMatchText,
|
|
91
96
|
clauseMatches,
|
|
92
|
-
cosineSimilarity,
|
|
93
|
-
DEFAULT_SEMANTIC_MATCH_THRESHOLD,
|
|
94
97
|
type FilterMessage,
|
|
95
98
|
type LiteralClauseNarrowing,
|
|
96
99
|
literalClausesMatch,
|
|
@@ -103,7 +106,6 @@ export {
|
|
|
103
106
|
type FilterDecision,
|
|
104
107
|
type FilterLogger,
|
|
105
108
|
FilterPipeline,
|
|
106
|
-
type MessageEmbedder,
|
|
107
109
|
} from "./filters/pipeline.js";
|
|
108
110
|
export {
|
|
109
111
|
type FlagPushConfig,
|
|
@@ -126,6 +128,17 @@ export {
|
|
|
126
128
|
type UpdateFlagsInput,
|
|
127
129
|
type UpdateFlagsResult,
|
|
128
130
|
} from "./flag-queue.js";
|
|
131
|
+
export {
|
|
132
|
+
type CreateFolderDeps,
|
|
133
|
+
changeFolderPath,
|
|
134
|
+
createFolder,
|
|
135
|
+
type FolderPathChange,
|
|
136
|
+
type FolderPathDeps,
|
|
137
|
+
type FolderPathOutcome,
|
|
138
|
+
type NewFolder,
|
|
139
|
+
type NewFolderOutcome,
|
|
140
|
+
ownedFolder,
|
|
141
|
+
} from "./folder-operations.js";
|
|
129
142
|
export {
|
|
130
143
|
type FolderPlacementLookup,
|
|
131
144
|
resolveAccountFolderPlacements,
|
|
@@ -188,6 +201,7 @@ export {
|
|
|
188
201
|
type CursorRebuildSnapshot,
|
|
189
202
|
matchCursorRebuild,
|
|
190
203
|
} from "./mailbox-cursor-rebuild.js";
|
|
204
|
+
export { folderInFlight } from "./mailbox-intent.js";
|
|
191
205
|
export {
|
|
192
206
|
type CreateMailboxInput,
|
|
193
207
|
type DeleteMailboxInput,
|
|
@@ -244,12 +258,27 @@ export {
|
|
|
244
258
|
parseMessageContent,
|
|
245
259
|
} from "./message-parser.js";
|
|
246
260
|
export { isMessageGoneFromOpenMailbox } from "./message-presence.js";
|
|
261
|
+
export {
|
|
262
|
+
type BodyPartMaterializer,
|
|
263
|
+
type BodySyncCue,
|
|
264
|
+
type MaterializeLogger,
|
|
265
|
+
type MaterializeResult,
|
|
266
|
+
materializeBodyParts,
|
|
267
|
+
} from "./message-read.js";
|
|
247
268
|
export {
|
|
248
269
|
type ImapConnectionFactory,
|
|
249
270
|
MessageSyncService,
|
|
250
271
|
type SyncedMessage,
|
|
251
272
|
type SyncMessagesResult,
|
|
252
273
|
} from "./message-sync.js";
|
|
274
|
+
export {
|
|
275
|
+
type OrganizeJobDeps,
|
|
276
|
+
type OrganizeJobLogger,
|
|
277
|
+
type OrganizeJobOwner,
|
|
278
|
+
type OrganizeJobPredicate,
|
|
279
|
+
type OrganizeJobRequest,
|
|
280
|
+
queueOrganizeJob,
|
|
281
|
+
} from "./organize-job.js";
|
|
253
282
|
export {
|
|
254
283
|
type CompleteOutboxAttachmentInput,
|
|
255
284
|
type CompleteOutboxAttachmentOutcome,
|
|
@@ -275,6 +304,13 @@ export {
|
|
|
275
304
|
OutboxQueueService,
|
|
276
305
|
type UpdateDraftInput,
|
|
277
306
|
} from "./outbox-queue.js";
|
|
307
|
+
export {
|
|
308
|
+
folderInAccount,
|
|
309
|
+
type MessageOwnershipClient,
|
|
310
|
+
ownedAccount,
|
|
311
|
+
ownedMessages,
|
|
312
|
+
settledFolder,
|
|
313
|
+
} from "./ownership.js";
|
|
278
314
|
export {
|
|
279
315
|
type PlacementMoveConfig,
|
|
280
316
|
type PlacementMoveLogger,
|
|
@@ -293,6 +329,7 @@ export {
|
|
|
293
329
|
isPlacementUnsettled,
|
|
294
330
|
type PlacementBinding,
|
|
295
331
|
placementBindingOf,
|
|
332
|
+
uidMailboxIdOf,
|
|
296
333
|
} from "./placement-settled.js";
|
|
297
334
|
export {
|
|
298
335
|
type QuarantineContext,
|
|
@@ -304,6 +341,15 @@ export {
|
|
|
304
341
|
resolveMailboxRole,
|
|
305
342
|
shapeFromMessageData,
|
|
306
343
|
} from "./quarantine.js";
|
|
344
|
+
export {
|
|
345
|
+
type AccessMode,
|
|
346
|
+
accept,
|
|
347
|
+
invalid,
|
|
348
|
+
type Refusable,
|
|
349
|
+
type Refusal,
|
|
350
|
+
type Refused,
|
|
351
|
+
refuse,
|
|
352
|
+
} from "./refusal.js";
|
|
307
353
|
export {
|
|
308
354
|
type RestoreSourcePlacementDeps,
|
|
309
355
|
type RestoreSourcePlacementInput,
|
|
@@ -325,10 +371,11 @@ export {
|
|
|
325
371
|
SpamReportService,
|
|
326
372
|
} from "./spam-report.js";
|
|
327
373
|
export {
|
|
328
|
-
|
|
329
|
-
type
|
|
330
|
-
type
|
|
331
|
-
|
|
374
|
+
type ServerUids,
|
|
375
|
+
type SyncWarningContext,
|
|
376
|
+
type SyncWarningRound,
|
|
377
|
+
SyncWarningService,
|
|
378
|
+
} from "./sync-warning.js";
|
|
332
379
|
export {
|
|
333
380
|
buildThreadMessageMoveRevert,
|
|
334
381
|
buildThreadMessageTrashUpdate,
|