@remit/imap-worker 0.0.88 → 0.0.89
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 +6 -6
- package/src/cli.ts +7 -0
- package/src/credential-less-sync-fence.test.ts +5 -9
- package/src/e2e-processor-shim.ts +2 -2
- package/src/emit.test.ts +24 -59
- package/src/emit.ts +50 -73
- package/src/events.ts +1 -19
- package/src/handlers/delete-account-objects.test.ts +25 -14
- package/src/handlers/delete-account-objects.ts +2 -11
- package/src/handlers/placement-push.sqlite.test.ts +1 -1
- package/src/handlers/probe-message-id.sqlite.test.ts +2 -4
- package/src/handlers/sync-mailboxes.ts +2 -2
- package/src/handlers/sync-message-body.ts +14 -18
- package/src/index.ts +6 -0
- package/src/mail-sync-selection.sqlite.test.ts +14 -13
- package/src/pending-sync.sqlite.test.ts +27 -28
- package/src/processor.ts +0 -8
- package/src/queues.ts +49 -0
- package/src/scheduler/attachment-sweep.sqlite.test.ts +1 -0
- package/src/scheduler/half-deleted-accounts.sqlite.test.ts +20 -27
- package/src/scheduler/handler.ts +8 -6
- package/src/scheduler/run-tick.sqlite.test.ts +6 -14
- package/src/scheduler/run-tick.ts +10 -14
- package/src/scheduler/runner.ts +18 -10
- package/src/stranded-placement.sqlite.test.ts +4 -5
- package/src/test-helpers/test-world.ts +40 -11
- package/src/processor.test.ts +0 -58
|
@@ -5,17 +5,23 @@ import { tmpdir } from "node:os";
|
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import {
|
|
7
7
|
_resetForTest,
|
|
8
|
-
getClient,
|
|
9
8
|
type RemitClient,
|
|
10
9
|
setClient,
|
|
11
10
|
} from "@remit/backend/client";
|
|
11
|
+
import { composeSqliteClient } from "@remit/backend/compose-sqlite";
|
|
12
|
+
import { buildSharedDeps } from "@remit/backend/shared-deps";
|
|
12
13
|
import type {
|
|
13
14
|
AccountItem,
|
|
14
15
|
MailboxItem,
|
|
15
16
|
MailboxSpecialUseValue,
|
|
16
17
|
MessageItem,
|
|
17
18
|
OutboxMessageItem,
|
|
19
|
+
QueueProducer,
|
|
18
20
|
} from "@remit/data-ports";
|
|
21
|
+
import {
|
|
22
|
+
type RecordingQueue,
|
|
23
|
+
recordingQueue,
|
|
24
|
+
} from "@remit/data-ports/recording-queue";
|
|
19
25
|
import {
|
|
20
26
|
AccountAuthType,
|
|
21
27
|
ConnectionState,
|
|
@@ -28,13 +34,10 @@ import {
|
|
|
28
34
|
eml,
|
|
29
35
|
FakeImapServer,
|
|
30
36
|
} from "@remit/mailbox-service/test-helpers/fake-imap";
|
|
31
|
-
import {
|
|
32
|
-
captureQueue,
|
|
33
|
-
type QueueCapture,
|
|
34
|
-
} from "@remit/mailbox-service/test-helpers/test-queue";
|
|
35
37
|
import { serializeEncryptedPayload } from "@remit/secrets-service";
|
|
36
38
|
import type { createConnectionScopeWithCredentials } from "../connection-scope.js";
|
|
37
39
|
import { syncMessages } from "../handlers/sync-messages.js";
|
|
40
|
+
import { setWorkerQueues } from "../queues.js";
|
|
38
41
|
|
|
39
42
|
export interface LogLine {
|
|
40
43
|
level: string;
|
|
@@ -93,6 +96,7 @@ export interface SeededMessage {
|
|
|
93
96
|
*/
|
|
94
97
|
export const openStore = async (): Promise<{
|
|
95
98
|
client: RemitClient;
|
|
99
|
+
bindWorkerQueues: () => void;
|
|
96
100
|
world: (accountConfigId?: string) => Promise<World>;
|
|
97
101
|
close: () => void;
|
|
98
102
|
}> => {
|
|
@@ -103,12 +107,38 @@ export const openStore = async (): Promise<{
|
|
|
103
107
|
process.env.BETTER_AUTH_URL = "https://mail.example.com";
|
|
104
108
|
process.env.BETTER_AUTH_SECRET = "a-signing-secret-of-at-least-32-characters";
|
|
105
109
|
_resetForTest();
|
|
106
|
-
|
|
110
|
+
let current = recordingQueue();
|
|
111
|
+
const queue: QueueProducer<unknown> = {
|
|
112
|
+
send: (message) => current.send(message),
|
|
113
|
+
sendBatch: (messages) => current.sendBatch(messages),
|
|
114
|
+
};
|
|
115
|
+
const client = await composeSqliteClient(
|
|
116
|
+
buildSharedDeps({
|
|
117
|
+
sync: queue,
|
|
118
|
+
accountFanout: queue,
|
|
119
|
+
smtp: queue,
|
|
120
|
+
messageManagement: queue,
|
|
121
|
+
body: queue,
|
|
122
|
+
}),
|
|
123
|
+
);
|
|
107
124
|
setClient(client);
|
|
125
|
+
const bindWorkerQueues = (): void =>
|
|
126
|
+
setWorkerQueues({
|
|
127
|
+
mailboxes: queue,
|
|
128
|
+
messages: queue,
|
|
129
|
+
flags: queue,
|
|
130
|
+
body: queue,
|
|
131
|
+
mailboxManagement: queue,
|
|
132
|
+
messageManagement: queue,
|
|
133
|
+
});
|
|
134
|
+
bindWorkerQueues();
|
|
108
135
|
return {
|
|
109
136
|
client,
|
|
110
|
-
|
|
111
|
-
|
|
137
|
+
bindWorkerQueues,
|
|
138
|
+
world: (accountConfigId = `cfg-${randomUUID()}`) => {
|
|
139
|
+
current = recordingQueue();
|
|
140
|
+
return createWorld(client, current, accountConfigId);
|
|
141
|
+
},
|
|
112
142
|
close: () => {
|
|
113
143
|
_resetForTest();
|
|
114
144
|
rmSync(directory, { recursive: true, force: true });
|
|
@@ -135,7 +165,7 @@ export interface World {
|
|
|
135
165
|
) => Promise<Array<{ mailboxId: string; uid?: number; isDeleted: boolean }>>;
|
|
136
166
|
queued: () => Array<Record<string, unknown>>;
|
|
137
167
|
refuseSends: (error: Error | undefined) => void;
|
|
138
|
-
queue:
|
|
168
|
+
queue: RecordingQueue;
|
|
139
169
|
draft: (
|
|
140
170
|
attachment?: Buffer,
|
|
141
171
|
) => Promise<{ outbox: OutboxMessageItem; attachmentId?: string }>;
|
|
@@ -145,10 +175,9 @@ export interface World {
|
|
|
145
175
|
|
|
146
176
|
const createWorld = async (
|
|
147
177
|
client: RemitClient,
|
|
178
|
+
queue: RecordingQueue,
|
|
148
179
|
accountConfigId: string,
|
|
149
180
|
): Promise<World> => {
|
|
150
|
-
const queue = captureQueue();
|
|
151
|
-
|
|
152
181
|
const imap = new FakeImapServer();
|
|
153
182
|
const logs: LogLine[] = [];
|
|
154
183
|
const password = await client.secrets.encrypt("app-password");
|
package/src/processor.test.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { describe, it } from "node:test";
|
|
3
|
-
import type { Logger } from "@remit/logger";
|
|
4
|
-
import type { ImapWorkerStopEvent } from "./events.js";
|
|
5
|
-
import { processEvent } from "./processor.js";
|
|
6
|
-
|
|
7
|
-
interface CapturedLogEntry {
|
|
8
|
-
args: unknown[];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const createCapturingLogger = (): {
|
|
12
|
-
log: Logger;
|
|
13
|
-
infoCalls: CapturedLogEntry[];
|
|
14
|
-
} => {
|
|
15
|
-
const infoCalls: CapturedLogEntry[] = [];
|
|
16
|
-
const noop = () => {};
|
|
17
|
-
const log = {
|
|
18
|
-
info: (...args: unknown[]) => infoCalls.push({ args }),
|
|
19
|
-
warn: noop,
|
|
20
|
-
error: noop,
|
|
21
|
-
debug: noop,
|
|
22
|
-
fatal: noop,
|
|
23
|
-
trace: noop,
|
|
24
|
-
child: () => log,
|
|
25
|
-
} as unknown as Logger;
|
|
26
|
-
return { log, infoCalls };
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
describe("processEvent — IMAP_WORKER_STOP", () => {
|
|
30
|
-
it("returns undefined and logs the stop signal — tombstone fence on the account row already halts work", async () => {
|
|
31
|
-
const event: ImapWorkerStopEvent = {
|
|
32
|
-
type: "IMAP_WORKER_STOP",
|
|
33
|
-
accountConfigId: "acfg_alice_replay_safe_test_id",
|
|
34
|
-
accountId: "acct_alice_replay_safe_test_id",
|
|
35
|
-
};
|
|
36
|
-
const { log, infoCalls } = createCapturingLogger();
|
|
37
|
-
|
|
38
|
-
const result = await processEvent(event, log);
|
|
39
|
-
|
|
40
|
-
assert.equal(result, undefined);
|
|
41
|
-
const matched = infoCalls.find((c) => {
|
|
42
|
-
const [meta, msg] = c.args;
|
|
43
|
-
return (
|
|
44
|
-
typeof msg === "string" &&
|
|
45
|
-
msg === "Imap worker stop signal received" &&
|
|
46
|
-
typeof meta === "object" &&
|
|
47
|
-
meta !== null &&
|
|
48
|
-
(meta as { accountConfigId?: string }).accountConfigId ===
|
|
49
|
-
event.accountConfigId &&
|
|
50
|
-
(meta as { accountId?: string }).accountId === event.accountId
|
|
51
|
-
);
|
|
52
|
-
});
|
|
53
|
-
assert.ok(
|
|
54
|
-
matched,
|
|
55
|
-
"processor must log the cascade-contract stop signal with both ids",
|
|
56
|
-
);
|
|
57
|
-
});
|
|
58
|
-
});
|