@remit/drizzle-service 0.0.89 → 0.0.91
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
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
|
|
19
19
|
const DEDUPE = "0030_mailbox_path_dedupe";
|
|
20
20
|
const UNIQUE = "0031_mailbox_path_unique";
|
|
21
|
+
const MAILBOX_COLUMNS_ADDED_SINCE = ["0033_mailbox_sync_failure_reason"];
|
|
21
22
|
const ACCOUNT = "acct";
|
|
22
23
|
const CONFIG = "cfg";
|
|
23
24
|
|
|
@@ -27,6 +28,8 @@ const atPredecessor = (): Handle => {
|
|
|
27
28
|
const sqlite = new Database(":memory:");
|
|
28
29
|
for (const entry of migrationJournal()) {
|
|
29
30
|
if (entry.tag === DEDUPE) {
|
|
31
|
+
for (const tag of MAILBOX_COLUMNS_ADDED_SINCE)
|
|
32
|
+
applyMigration(sqlite, tag);
|
|
30
33
|
return {
|
|
31
34
|
sqlite,
|
|
32
35
|
db: drizzle(sqlite) as unknown as Db<Record<string, unknown>>,
|
|
@@ -203,6 +203,7 @@ describe("addresses standing only on mail in Junk", () => {
|
|
|
203
203
|
// `mailbox` is read through the repo, which selects every column the
|
|
204
204
|
// entity declares — including the rename target added after this DDL.
|
|
205
205
|
applyMigration(sqlite, "0028_mailbox_pending_path");
|
|
206
|
+
applyMigration(sqlite, "0033_mailbox_sync_failure_reason");
|
|
206
207
|
sqlite.exec(
|
|
207
208
|
readFileSync(
|
|
208
209
|
new URL(
|
package/src/repos/i4-account.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
UpdateAccountInput,
|
|
9
9
|
} from "@remit/data-ports";
|
|
10
10
|
import { AccountService, SyncPhase } from "@remit/domain-enums";
|
|
11
|
-
import { and, asc, eq, gt, inArray, or, sql } from "drizzle-orm";
|
|
11
|
+
import { and, asc, eq, gt, inArray, like, or, sql } from "drizzle-orm";
|
|
12
12
|
import type { Db } from "../db.js";
|
|
13
13
|
import { NotFoundError } from "../error.js";
|
|
14
14
|
import { randomId } from "../id.js";
|
|
@@ -291,6 +291,21 @@ export class AccountRepo implements IAccountRepository {
|
|
|
291
291
|
return rows.map(rowToAccount);
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
async listMailSourcesByAccountConfig(
|
|
295
|
+
accountConfigId: string,
|
|
296
|
+
): Promise<AccountItem[]> {
|
|
297
|
+
const rows = await this.db
|
|
298
|
+
.select()
|
|
299
|
+
.from(accountTable)
|
|
300
|
+
.where(
|
|
301
|
+
and(
|
|
302
|
+
eq(accountTable.accountConfigId, accountConfigId),
|
|
303
|
+
like(accountTable.syncedServices, `%"${AccountService.Mail}"%`),
|
|
304
|
+
),
|
|
305
|
+
);
|
|
306
|
+
return rows.map(rowToAccount);
|
|
307
|
+
}
|
|
308
|
+
|
|
294
309
|
async describe(accountId: string): Promise<AccountDescription> {
|
|
295
310
|
const [accounts, mailboxes] = await Promise.all([
|
|
296
311
|
this.db
|
|
@@ -154,6 +154,37 @@ describe("MailboxRepo (sqlite)", () => {
|
|
|
154
154
|
/UNIQUE constraint failed: mailbox\.account_id, mailbox\.full_path/,
|
|
155
155
|
);
|
|
156
156
|
});
|
|
157
|
+
|
|
158
|
+
test("syncFailureReason is written on failed and cleared by any other state", async () => {
|
|
159
|
+
const accountId = randomUUID();
|
|
160
|
+
const created = mailboxCreated(
|
|
161
|
+
await repo.create(makeMailboxInput(accountId, "Locked")),
|
|
162
|
+
);
|
|
163
|
+
assert.equal(created.syncFailureReason, "");
|
|
164
|
+
|
|
165
|
+
await repo.transition(accountId, created.mailboxId, {
|
|
166
|
+
from: [MailboxSyncStatus.synced],
|
|
167
|
+
to: MailboxSyncStatus.deleting,
|
|
168
|
+
set: { syncFailureReason: "ignored outside failed" },
|
|
169
|
+
});
|
|
170
|
+
assert.equal(
|
|
171
|
+
(await repo.get(accountId, created.mailboxId)).syncFailureReason,
|
|
172
|
+
"",
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const failed = await repo.transition(accountId, created.mailboxId, {
|
|
176
|
+
from: [MailboxSyncStatus.deleting],
|
|
177
|
+
to: MailboxSyncStatus.failed,
|
|
178
|
+
set: { syncFailureReason: "Permission denied" },
|
|
179
|
+
});
|
|
180
|
+
assert.equal(failed?.syncFailureReason, "Permission denied");
|
|
181
|
+
|
|
182
|
+
const dismissed = await repo.transition(accountId, created.mailboxId, {
|
|
183
|
+
from: [MailboxSyncStatus.failed],
|
|
184
|
+
to: MailboxSyncStatus.synced,
|
|
185
|
+
});
|
|
186
|
+
assert.equal(dismissed?.syncFailureReason, "");
|
|
187
|
+
});
|
|
157
188
|
});
|
|
158
189
|
|
|
159
190
|
/**
|
|
@@ -179,6 +210,7 @@ describe("MailboxRepo (sqlite, shipped migrations)", () => {
|
|
|
179
210
|
applyMigration(sqlite, "0027_mailbox_sync_status_total");
|
|
180
211
|
applyMigration(sqlite, "0028_mailbox_pending_path");
|
|
181
212
|
applyMigration(sqlite, "0031_mailbox_path_unique");
|
|
213
|
+
applyMigration(sqlite, "0033_mailbox_sync_failure_reason");
|
|
182
214
|
const db = drizzle(sqlite, { schema: { mailbox: mailboxTable } });
|
|
183
215
|
repo = new MailboxRepo(db as never);
|
|
184
216
|
close = async () => {
|
|
@@ -254,6 +286,25 @@ describe("MailboxRepo (sqlite, shipped migrations)", () => {
|
|
|
254
286
|
assert.equal(cleared?.pendingPath, undefined);
|
|
255
287
|
});
|
|
256
288
|
|
|
289
|
+
test("syncFailureReason round-trips on the shipped shape", async () => {
|
|
290
|
+
const accountId = randomUUID();
|
|
291
|
+
const created = mailboxCreated(
|
|
292
|
+
await repo.create(makeMailboxInput(accountId, "Held")),
|
|
293
|
+
);
|
|
294
|
+
assert.equal(created.syncFailureReason, "");
|
|
295
|
+
|
|
296
|
+
await repo.transition(accountId, created.mailboxId, {
|
|
297
|
+
from: [MailboxSyncStatus.synced],
|
|
298
|
+
to: MailboxSyncStatus.deleting,
|
|
299
|
+
});
|
|
300
|
+
const failed = await repo.transition(accountId, created.mailboxId, {
|
|
301
|
+
from: [MailboxSyncStatus.deleting],
|
|
302
|
+
to: MailboxSyncStatus.failed,
|
|
303
|
+
set: { syncFailureReason: "Permission denied" },
|
|
304
|
+
});
|
|
305
|
+
assert.equal(failed?.syncFailureReason, "Permission denied");
|
|
306
|
+
});
|
|
307
|
+
|
|
257
308
|
test("round-trips a cursor above 2^53 with its exact digits", async () => {
|
|
258
309
|
const accountId = randomUUID();
|
|
259
310
|
const modseq = "18446744073709551615";
|
package/src/repos/i4-mailbox.ts
CHANGED
|
@@ -92,6 +92,7 @@ const transitionSet = (
|
|
|
92
92
|
? { pendingPath: write.pendingPath }
|
|
93
93
|
: {}
|
|
94
94
|
: { pendingPath: null }),
|
|
95
|
+
syncFailureReason: to === "failed" ? (write?.syncFailureReason ?? "") : "",
|
|
95
96
|
updatedAt: Date.now(),
|
|
96
97
|
});
|
|
97
98
|
|
|
@@ -119,6 +120,7 @@ export function rowToMailbox(
|
|
|
119
120
|
parentMailboxId: row.parentMailboxId,
|
|
120
121
|
syncStatus: row.syncStatus as MailboxItem["syncStatus"],
|
|
121
122
|
...(row.pendingPath !== null ? { pendingPath: row.pendingPath } : {}),
|
|
123
|
+
syncFailureReason: row.syncFailureReason,
|
|
122
124
|
cursorState: (row.cursorState as MailboxItem["cursorState"]) ?? undefined,
|
|
123
125
|
specialUse: (row.specialUse as MailboxItem["specialUse"]) ?? undefined,
|
|
124
126
|
createdAt: row.createdAt,
|