@remit/mailbox-service 2.0.3 → 2.1.0
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/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/message-read.d.ts +32 -0
- package/dist/message-read.js +45 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export { denormalizeMessageCategory, type MessageCategoryDenormalizeDeps, type M
|
|
|
41
41
|
export { type DeleteMessagesOutcome, type DeleteOptions, type MessageMoveConfig, type MessageMoveLogger, type MessageMoveQueueEvent, MessageMoveService, NoTrashMailboxError, requireTrashMailbox, StaleTrashAppointmentError, UnconfirmedTrashMailboxError, } from "./message-move.js";
|
|
42
42
|
export { type ParsedMessageContent, parseMessageContent, } from "./message-parser.js";
|
|
43
43
|
export { isMessageGoneFromOpenMailbox } from "./message-presence.js";
|
|
44
|
-
export { type BodyPartMaterializer, type BodySyncCue, type MaterializeLogger, type MaterializeResult, materializeBodyParts, } from "./message-read.js";
|
|
44
|
+
export { type BodyPartMaterializer, type BodyReadMiss, type BodyReadMissDeps, type BodyReadMissInput, type BodySyncCue, type MaterializeLogger, type MaterializeResult, materializeBodyParts, resolveBodyReadMiss, } from "./message-read.js";
|
|
45
45
|
export { type ImapConnectionFactory, MessageSyncService, type SyncedMessage, type SyncMessagesResult, } from "./message-sync.js";
|
|
46
46
|
export { type OrganizeJobDeps, type OrganizeJobLogger, type OrganizeJobOwner, type OrganizeJobPredicate, type OrganizeJobRequest, queueOrganizeJob, } from "./organize-job.js";
|
|
47
47
|
export { type CompleteOutboxAttachmentInput, type CompleteOutboxAttachmentOutcome, type MintOutboxAttachmentInput, type MintOutboxAttachmentOutcome, OUTBOX_ATTACHMENT_MAX_COUNT, OUTBOX_ATTACHMENT_MAX_TOTAL_BYTES, type OutboxAttachmentConfig, type OutboxAttachmentRejectionDetail, type OutboxAttachmentRejectionReasonValue, type OutboxAttachmentReservation, OutboxAttachmentService, } from "./outbox-attachment.js";
|
package/dist/index.js
CHANGED
|
@@ -44,7 +44,7 @@ export { denormalizeMessageCategory, } from "./message-category.js";
|
|
|
44
44
|
export { MessageMoveService, NoTrashMailboxError, requireTrashMailbox, StaleTrashAppointmentError, UnconfirmedTrashMailboxError, } from "./message-move.js";
|
|
45
45
|
export { parseMessageContent, } from "./message-parser.js";
|
|
46
46
|
export { isMessageGoneFromOpenMailbox } from "./message-presence.js";
|
|
47
|
-
export { materializeBodyParts, } from "./message-read.js";
|
|
47
|
+
export { materializeBodyParts, resolveBodyReadMiss, } from "./message-read.js";
|
|
48
48
|
export { MessageSyncService, } from "./message-sync.js";
|
|
49
49
|
export { queueOrganizeJob, } from "./organize-job.js";
|
|
50
50
|
export { OUTBOX_ATTACHMENT_MAX_COUNT, OUTBOX_ATTACHMENT_MAX_TOTAL_BYTES, OutboxAttachmentService, } from "./outbox-attachment.js";
|
package/dist/message-read.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { IEnvelopeRepository, IMailboxRepository, IMessageRepository } from "@remit/data-ports";
|
|
2
|
+
import { type StorageService } from "@remit/storage-service";
|
|
1
3
|
/**
|
|
2
4
|
* The slice of `BodySyncService` the read path needs to lazily materialize
|
|
3
5
|
* deferred per-part objects.
|
|
@@ -49,3 +51,33 @@ export declare const materializeBodyParts: (materializer: BodyPartMaterializer,
|
|
|
49
51
|
cue: BodySyncCue;
|
|
50
52
|
logger: MaterializeLogger;
|
|
51
53
|
}) => Promise<MaterializeResult>;
|
|
54
|
+
export type BodyReadMiss = "NotFound" | "Broken" | "Pending";
|
|
55
|
+
export interface BodyReadMissDeps {
|
|
56
|
+
message: Pick<IMessageRepository, "get">;
|
|
57
|
+
mailbox: Pick<IMailboxRepository, "get">;
|
|
58
|
+
envelope: Pick<IEnvelopeRepository, "listBodyParts">;
|
|
59
|
+
storage: Pick<StorageService, "bodyPartExists" | "deleteKeys">;
|
|
60
|
+
}
|
|
61
|
+
export interface BodyReadMissInput {
|
|
62
|
+
accountConfigId: string;
|
|
63
|
+
accountId: string;
|
|
64
|
+
messageId: string;
|
|
65
|
+
partPath: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* What a content read that found no object at a part key should answer. It
|
|
69
|
+
* never enqueues: the describe read path (`materializeBodyParts`) re-arms the
|
|
70
|
+
* body sync, and the client re-describes on every 202.
|
|
71
|
+
*
|
|
72
|
+
* - `NotFound` — the message, its mailbox under `accountId`, or a leaf at
|
|
73
|
+
* `partPath` does not exist; no retry can produce the object.
|
|
74
|
+
* - `Broken` — the body sync exhausted its retries against a message the
|
|
75
|
+
* server still holds (`isMessageBodySyncBroken`).
|
|
76
|
+
* - `Pending` — anything else; a retry after the next describe succeeds.
|
|
77
|
+
*
|
|
78
|
+
* A missing leaf under a present `.materialized` sentinel means the sentinel
|
|
79
|
+
* no longer vouches for its parts, and `ensureBodyPartsStored` would skip the
|
|
80
|
+
* message forever. The sentinel is dropped so the next describe materializes
|
|
81
|
+
* the parts again; that delete is the one write here.
|
|
82
|
+
*/
|
|
83
|
+
export declare const resolveBodyReadMiss: (deps: BodyReadMissDeps, { accountConfigId, accountId, messageId, partPath }: BodyReadMissInput) => Promise<BodyReadMiss>;
|
package/dist/message-read.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isEncapsulatedMessage } from "@remit/data-ports/message-parts";
|
|
2
|
+
import { buildBodyPartKey, isStorageNotFoundError, MATERIALIZED_SENTINEL_PART_PATH, MATERIALIZED_SENTINEL_V2_PART_PATH, } from "@remit/storage-service";
|
|
3
|
+
import { isMessageBodySyncBroken } from "./body-sync-terminal.js";
|
|
2
4
|
/**
|
|
3
5
|
* Materialize the deferred per-part storage objects for a message before any
|
|
4
6
|
* part is read. Distinguishes the two failure modes the body contract cares
|
|
@@ -29,3 +31,45 @@ export const materializeBodyParts = async (materializer, args) => {
|
|
|
29
31
|
return { ready: false };
|
|
30
32
|
}
|
|
31
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* What a content read that found no object at a part key should answer. It
|
|
36
|
+
* never enqueues: the describe read path (`materializeBodyParts`) re-arms the
|
|
37
|
+
* body sync, and the client re-describes on every 202.
|
|
38
|
+
*
|
|
39
|
+
* - `NotFound` — the message, its mailbox under `accountId`, or a leaf at
|
|
40
|
+
* `partPath` does not exist; no retry can produce the object.
|
|
41
|
+
* - `Broken` — the body sync exhausted its retries against a message the
|
|
42
|
+
* server still holds (`isMessageBodySyncBroken`).
|
|
43
|
+
* - `Pending` — anything else; a retry after the next describe succeeds.
|
|
44
|
+
*
|
|
45
|
+
* A missing leaf under a present `.materialized` sentinel means the sentinel
|
|
46
|
+
* no longer vouches for its parts, and `ensureBodyPartsStored` would skip the
|
|
47
|
+
* message forever. The sentinel is dropped so the next describe materializes
|
|
48
|
+
* the parts again; that delete is the one write here.
|
|
49
|
+
*/
|
|
50
|
+
export const resolveBodyReadMiss = async (deps, { accountConfigId, accountId, messageId, partPath }) => {
|
|
51
|
+
const [message] = await deps.message.get([messageId]);
|
|
52
|
+
if (!message)
|
|
53
|
+
return "NotFound";
|
|
54
|
+
const [mailbox] = await deps.mailbox.get(accountId, [message.mailboxId]);
|
|
55
|
+
if (!mailbox)
|
|
56
|
+
return "NotFound";
|
|
57
|
+
if (await isMessageBodySyncBroken(deps.storage, accountConfigId, accountId, messageId)) {
|
|
58
|
+
return "Broken";
|
|
59
|
+
}
|
|
60
|
+
const bodyParts = await deps.envelope.listBodyParts(messageId);
|
|
61
|
+
const leaf = bodyParts.find((part) => part.partPath === partPath && !part.isMultipart);
|
|
62
|
+
if (!leaf)
|
|
63
|
+
return "NotFound";
|
|
64
|
+
if (!message.bodyStorageKey)
|
|
65
|
+
return "Pending";
|
|
66
|
+
const sentinel = bodyParts.some(isEncapsulatedMessage)
|
|
67
|
+
? MATERIALIZED_SENTINEL_V2_PART_PATH
|
|
68
|
+
: MATERIALIZED_SENTINEL_PART_PATH;
|
|
69
|
+
if (await deps.storage.bodyPartExists(accountConfigId, accountId, messageId, sentinel)) {
|
|
70
|
+
await deps.storage.deleteKeys([
|
|
71
|
+
buildBodyPartKey(accountConfigId, accountId, messageId, sentinel),
|
|
72
|
+
]);
|
|
73
|
+
}
|
|
74
|
+
return "Pending";
|
|
75
|
+
};
|