@remit/mailbox-service 0.0.120 → 0.0.121
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/body-sync.js +1 -19
- package/dist/message-move.js +1 -4
- package/dist/message-sync.js +5 -9
- package/dist/test-helpers/test-store.js +0 -2
- package/package.json +1 -1
package/dist/body-sync.js
CHANGED
|
@@ -6,7 +6,7 @@ import { deriveAddressId, deriveBodyPartId } from "@remit/data-ports/id";
|
|
|
6
6
|
import { isEncapsulatedMessage } from "@remit/data-ports/message-parts";
|
|
7
7
|
import { isBulkSender } from "@remit/data-ports/wellknown";
|
|
8
8
|
import { FilterState, MessageClassificationState, PlacementAction, PlacementConfidence, QuarantineFailureStage, SenderTrust, SyncWarningStage, } from "@remit/domain-enums";
|
|
9
|
-
import { isStorageNotFoundError, } from "@remit/storage-service";
|
|
9
|
+
import { isStorageNotFoundError, MATERIALIZED_SENTINEL_PART_PATH, MATERIALIZED_SENTINEL_V2_PART_PATH, } from "@remit/storage-service";
|
|
10
10
|
import { Semaphore } from "async-mutex";
|
|
11
11
|
import { simpleParser } from "mailparser";
|
|
12
12
|
import pMap from "p-map";
|
|
@@ -42,24 +42,6 @@ export const isBodyPartDeferralEnabled = () => {
|
|
|
42
42
|
const normalized = raw.trim().toLowerCase();
|
|
43
43
|
return normalized !== "false" && normalized !== "0" && normalized !== "off";
|
|
44
44
|
};
|
|
45
|
-
/**
|
|
46
|
-
* Sentinel object written under a message's parts prefix once lazy
|
|
47
|
-
* materialization has stored EVERY leaf. The read path checks it first with a
|
|
48
|
-
* single HEAD and early-returns, skipping the body.eml GET, the MIME re-parse,
|
|
49
|
-
* and the per-leaf HEADs on every warm re-open.
|
|
50
|
-
*
|
|
51
|
-
* Deliberately an S3-only marker (no Message-row flag). A leading dot keeps it
|
|
52
|
-
* out of any real IMAP section path (those are dot-separated digits).
|
|
53
|
-
*/
|
|
54
|
-
const MATERIALIZED_SENTINEL_PART_PATH = ".materialized";
|
|
55
|
-
/**
|
|
56
|
-
* The sentinel for a message carrying a forwarded message. Those parts were
|
|
57
|
-
* once stored under a layout in which the forwarded message's root overwrote
|
|
58
|
-
* its own row, so a `.materialized` written then vouches for objects at the
|
|
59
|
-
* wrong paths. Its own name makes every such message materialize once more,
|
|
60
|
-
* overwriting what is there; no other message is touched.
|
|
61
|
-
*/
|
|
62
|
-
const MATERIALIZED_SENTINEL_V2_PART_PATH = ".materialized.2";
|
|
63
45
|
/**
|
|
64
46
|
* A mid-stream socket drop during the ranged body fetch surfaces as a typed
|
|
65
47
|
* `MailConnectionError` (the connection layer classifies imapflow's
|
package/dist/message-move.js
CHANGED
|
@@ -478,15 +478,13 @@ export class MessageMoveService {
|
|
|
478
478
|
// the copy at uid=0 with an undelivered event; upsert no-ops on the row
|
|
479
479
|
// and lets the event be re-enqueued below, keeping the operation
|
|
480
480
|
// idempotent and the copy re-drivable (issue #75).
|
|
481
|
-
const copyRow = await this.messageService.
|
|
481
|
+
const copyRow = await this.messageService.copyMessage(messageId, {
|
|
482
482
|
messageId: newMessageId,
|
|
483
483
|
mailboxId: destinationMailboxId,
|
|
484
484
|
uid: 0, // Will be updated by worker after IMAP COPY
|
|
485
485
|
sequenceNumber: 0, // Will be updated by worker
|
|
486
486
|
rfc822Size: sourceMessage.rfc822Size,
|
|
487
487
|
internalDate: sourceMessage.internalDate,
|
|
488
|
-
envelopeId: sourceMessage.envelopeId, // Share envelope with source
|
|
489
|
-
rootBodyPartId: sourceMessage.rootBodyPartId, // Share body parts with source
|
|
490
488
|
status: MessageStatus.moving,
|
|
491
489
|
syncStatus: MessageSyncStatus.pending,
|
|
492
490
|
bodyStorageKey: sourceMessage.bodyStorageKey,
|
|
@@ -502,7 +500,6 @@ export class MessageMoveService {
|
|
|
502
500
|
classificationState: sourceMessage.classificationState,
|
|
503
501
|
hasListUnsubscribe: sourceMessage.hasListUnsubscribe,
|
|
504
502
|
});
|
|
505
|
-
await this.messageService.copySearchText(messageId, newMessageId);
|
|
506
503
|
// Copy ThreadMessage entry
|
|
507
504
|
const sourceThreadMessage = await this.threadMessageService.getByMessageId(accountConfigId, messageId);
|
|
508
505
|
const copyListing = await this.threadMessageService.create({
|
package/dist/message-sync.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { storedDisplayName } from "@remit/data-ports/display-name";
|
|
2
|
-
import { deriveAddressId,
|
|
2
|
+
import { deriveAddressId, deriveCopyMessageId, deriveEnvelopeId, deriveMessageId, deriveMessageIdFromSource, deriveThreadId, isValidMessageId, wireMessageId, } from "@remit/data-ports/id";
|
|
3
3
|
import { AddressRole, MailboxCursorState, MessageKeywordFlag, MessageSystemFlag, StarColor, SyncWarningStage, } from "@remit/domain-enums";
|
|
4
4
|
import pMap from "p-map";
|
|
5
5
|
import { confirmDepartures, placementKey, sightingContestsPlacement, } from "./external-move.js";
|
|
6
6
|
import { guardMailboxCursor, isCursorRebuildNeeded } from "./mailbox-cursor.js";
|
|
7
7
|
import { matchCursorRebuild, } from "./mailbox-cursor-rebuild.js";
|
|
8
|
-
import {
|
|
8
|
+
import { walkMimeStructure } from "./mime-walker.js";
|
|
9
9
|
import { advanceChangeCursor, advanceUidWatermarks, dropAppliedPrefix, formatChangeCursor, hasChangeCursor, orderByModseq, parseChangeCursor, parseModseq, } from "./sync-watermarks.js";
|
|
10
10
|
import { messageReferencesOf, parentOf, threadRootOf } from "./thread-root.js";
|
|
11
11
|
const MESSAGE_SAVE_CONCURRENCY = 10;
|
|
@@ -495,10 +495,9 @@ export class MessageSyncService {
|
|
|
495
495
|
}
|
|
496
496
|
}, { concurrency: MESSAGE_SAVE_CONCURRENCY });
|
|
497
497
|
const stale = new Set(staleMessageIds);
|
|
498
|
-
await
|
|
499
|
-
|
|
500
|
-
uid: row.uid
|
|
501
|
-
}), { concurrency: MESSAGE_SAVE_CONCURRENCY });
|
|
498
|
+
await this.messageService.deleteManyIfPlacement(mailboxId, existingRows
|
|
499
|
+
.filter((row) => stale.has(row.messageId))
|
|
500
|
+
.map((row) => ({ messageId: row.messageId, uid: row.uid })));
|
|
502
501
|
const newMessages = newUids.length > 0 ? await this.fetchMessageBatch(newUids) : [];
|
|
503
502
|
const applicable = newMessages.filter(hasEnvelope);
|
|
504
503
|
const roles = await this.folderRolesFor(accountId, accountConfigId);
|
|
@@ -1033,7 +1032,6 @@ export class MessageSyncService {
|
|
|
1033
1032
|
const envelope = msg.envelope;
|
|
1034
1033
|
const messageId = messageIdForSighting(accountId, mailboxId, msg);
|
|
1035
1034
|
const envelopeId = deriveEnvelopeId(messageId);
|
|
1036
|
-
const rootBodyPartId = deriveBodyPartId(messageId, ROOT_PART_PATH);
|
|
1037
1035
|
const internalDateMs = msg.internalDate.getTime();
|
|
1038
1036
|
const { value: sentDate, usedFallback: dateFellBack } = parseHeaderDate(envelope.date, internalDateMs);
|
|
1039
1037
|
if (dateFellBack) {
|
|
@@ -1095,8 +1093,6 @@ export class MessageSyncService {
|
|
|
1095
1093
|
sequenceNumber: msg.seq,
|
|
1096
1094
|
rfc822Size: msg.size ?? 0,
|
|
1097
1095
|
internalDate: msg.internalDate.getTime(),
|
|
1098
|
-
envelopeId,
|
|
1099
|
-
rootBodyPartId,
|
|
1100
1096
|
});
|
|
1101
1097
|
// The server has just named this folder and this UID for a message the
|
|
1102
1098
|
// database holds under another folder. `upsertWithStatus` left the row
|
|
@@ -115,8 +115,6 @@ export const seedMessage = async (store, account, mailbox, uid, overrides = {})
|
|
|
115
115
|
sequenceNumber: uid,
|
|
116
116
|
rfc822Size: 100,
|
|
117
117
|
internalDate: 1_700_000_000_000 + uid,
|
|
118
|
-
envelopeId: randomUUID(),
|
|
119
|
-
rootBodyPartId: randomUUID(),
|
|
120
118
|
status: "active",
|
|
121
119
|
syncStatus: "synced",
|
|
122
120
|
...overrides.message,
|