@remit/data-ports 0.0.83 → 0.0.84
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/account-settings.d.ts +371 -0
- package/dist/account-settings.js +114 -0
- package/dist/conformance/account.d.ts +3 -0
- package/dist/conformance/account.js +118 -0
- package/dist/conformance/calendar-collection.d.ts +3 -0
- package/dist/conformance/calendar-collection.js +251 -0
- package/dist/conformance/calendar-event-index.d.ts +3 -0
- package/dist/conformance/calendar-event-index.js +114 -0
- package/dist/conformance/calendar-feed-token.d.ts +3 -0
- package/dist/conformance/calendar-feed-token.js +97 -0
- package/dist/conformance/calendar-object.d.ts +3 -0
- package/dist/conformance/calendar-object.js +156 -0
- package/dist/conformance/calendar-suggestion.d.ts +3 -0
- package/dist/conformance/calendar-suggestion.js +255 -0
- package/{src/conformance/harness.ts → dist/conformance/harness.d.ts} +4 -4
- package/dist/conformance/harness.js +1 -0
- package/dist/conformance/index.js +8 -0
- package/dist/conformance/label.d.ts +3 -0
- package/dist/conformance/label.js +92 -0
- package/dist/conformance/sender-signer-standing.d.ts +3 -0
- package/dist/conformance/sender-signer-standing.js +81 -0
- package/dist/display-name.d.ts +1 -0
- package/dist/display-name.js +26 -0
- package/dist/errors.d.ts +150 -0
- package/dist/errors.js +181 -0
- package/dist/filter-ttl.d.ts +7 -0
- package/{src/filter-ttl.ts → dist/filter-ttl.js} +8 -11
- package/dist/folder-role.d.ts +239 -0
- package/dist/folder-role.js +276 -0
- package/dist/id.d.ts +124 -0
- package/{src/id.ts → dist/id.js} +41 -127
- package/dist/index.d.ts +37 -0
- package/dist/index.js +5 -0
- package/dist/interfaces/account-config.d.ts +15 -0
- package/dist/interfaces/account-config.js +1 -0
- package/dist/interfaces/account-export-request.d.ts +10 -0
- package/dist/interfaces/account-export-request.js +1 -0
- package/dist/interfaces/account-setting.d.ts +7 -0
- package/dist/interfaces/account-setting.js +1 -0
- package/dist/interfaces/account.d.ts +29 -0
- package/dist/interfaces/account.js +1 -0
- package/dist/interfaces/address.d.ts +69 -0
- package/dist/interfaces/address.js +1 -0
- package/dist/interfaces/calendar-collection.d.ts +38 -0
- package/dist/interfaces/calendar-collection.js +1 -0
- package/dist/interfaces/calendar-event-index.d.ts +19 -0
- package/dist/interfaces/calendar-event-index.js +1 -0
- package/dist/interfaces/calendar-feed-token.d.ts +31 -0
- package/dist/interfaces/calendar-feed-token.js +1 -0
- package/dist/interfaces/calendar-object.d.ts +36 -0
- package/dist/interfaces/calendar-object.js +1 -0
- package/dist/interfaces/calendar-store.d.ts +93 -0
- package/dist/interfaces/calendar-store.js +1 -0
- package/dist/interfaces/calendar-suggestion.d.ts +62 -0
- package/dist/interfaces/calendar-suggestion.js +1 -0
- package/dist/interfaces/config-import.d.ts +8 -0
- package/dist/interfaces/config-import.js +1 -0
- package/dist/interfaces/envelope.d.ts +24 -0
- package/dist/interfaces/envelope.js +1 -0
- package/dist/interfaces/filter.d.ts +28 -0
- package/dist/interfaces/filter.js +1 -0
- package/dist/interfaces/label.d.ts +17 -0
- package/dist/interfaces/label.js +1 -0
- package/dist/interfaces/mailbox-lock.d.ts +12 -0
- package/dist/interfaces/mailbox-lock.js +1 -0
- package/dist/interfaces/mailbox-special-use.d.ts +54 -0
- package/dist/interfaces/mailbox-special-use.js +1 -0
- package/dist/interfaces/mailbox.d.ts +79 -0
- package/dist/interfaces/mailbox.js +1 -0
- package/dist/interfaces/message-flag-push.d.ts +9 -0
- package/dist/interfaces/message-flag-push.js +1 -0
- package/dist/interfaces/message-flag.d.ts +14 -0
- package/dist/interfaces/message-flag.js +1 -0
- package/dist/interfaces/message-label.d.ts +21 -0
- package/dist/interfaces/message-label.js +1 -0
- package/dist/interfaces/message-placement-move.d.ts +8 -0
- package/dist/interfaces/message-placement-move.js +1 -0
- package/dist/interfaces/message.d.ts +60 -0
- package/dist/interfaces/message.js +1 -0
- package/dist/interfaces/organize-job-request.d.ts +10 -0
- package/dist/interfaces/organize-job-request.js +1 -0
- package/dist/interfaces/outbox-attachment.d.ts +101 -0
- package/dist/interfaces/outbox-attachment.js +7 -0
- package/dist/interfaces/outbox-message.d.ts +70 -0
- package/dist/interfaces/outbox-message.js +20 -0
- package/dist/interfaces/quarantine.d.ts +20 -0
- package/dist/interfaces/quarantine.js +1 -0
- package/dist/interfaces/sender-signer-standing.d.ts +26 -0
- package/dist/interfaces/sender-signer-standing.js +1 -0
- package/dist/interfaces/sync-warning.d.ts +11 -0
- package/dist/interfaces/sync-warning.js +1 -0
- package/dist/interfaces/thread-message.d.ts +202 -0
- package/dist/interfaces/thread-message.js +1 -0
- package/dist/mailbox-name.d.ts +35 -0
- package/dist/mailbox-name.js +68 -0
- package/dist/message-parts.d.ts +22 -0
- package/dist/message-parts.js +18 -0
- package/dist/message-settlement.d.ts +35 -0
- package/{src/message-settlement.ts → dist/message-settlement.js} +5 -19
- package/dist/mutation-events.d.ts +19 -0
- package/{src/mutation-events.ts → dist/mutation-events.js} +2 -5
- package/dist/sender-mute.d.ts +26 -0
- package/{src/sender-mute.ts → dist/sender-mute.js} +12 -34
- package/dist/sync-warning-state.d.ts +3 -0
- package/dist/sync-warning-state.js +5 -0
- package/dist/types.d.ts +491 -0
- package/dist/types.js +1 -0
- package/dist/update-manifest.d.ts +24 -0
- package/dist/update-manifest.js +20 -0
- package/dist/virtual-copy.d.ts +8 -0
- package/{src/virtual-copy.ts → dist/virtual-copy.js} +10 -15
- package/dist/wellknown.d.ts +47 -0
- package/{src/wellknown.ts → dist/wellknown.js} +26 -49
- package/package.json +44 -79
- package/src/account-settings.ts +0 -194
- package/src/conformance/account.ts +0 -104
- package/src/conformance/calendar-collection.ts +0 -342
- package/src/conformance/calendar-event-index.ts +0 -203
- package/src/conformance/calendar-feed-token.ts +0 -148
- package/src/conformance/calendar-object.ts +0 -269
- package/src/conformance/calendar-suggestion.ts +0 -490
- package/src/conformance/label.ts +0 -136
- package/src/conformance/sender-signer-standing.ts +0 -117
- package/src/display-name.test.ts +0 -101
- package/src/display-name.ts +0 -40
- package/src/errors.ts +0 -244
- package/src/folder-role.test.ts +0 -422
- package/src/folder-role.ts +0 -447
- package/src/id.test.ts +0 -352
- package/src/index.ts +0 -170
- package/src/interfaces/account-config.ts +0 -25
- package/src/interfaces/account-export-request.ts +0 -21
- package/src/interfaces/account-setting.ts +0 -14
- package/src/interfaces/account.ts +0 -43
- package/src/interfaces/address.ts +0 -122
- package/src/interfaces/calendar-collection.ts +0 -60
- package/src/interfaces/calendar-event-index.ts +0 -34
- package/src/interfaces/calendar-feed-token.ts +0 -38
- package/src/interfaces/calendar-object.ts +0 -58
- package/src/interfaces/calendar-suggestion.ts +0 -93
- package/src/interfaces/calendar-unit-of-work.ts +0 -47
- package/src/interfaces/config-import.ts +0 -16
- package/src/interfaces/envelope.ts +0 -32
- package/src/interfaces/filter-anchor-transaction.ts +0 -23
- package/src/interfaces/filter-anchor.ts +0 -11
- package/src/interfaces/filter.ts +0 -41
- package/src/interfaces/label.ts +0 -30
- package/src/interfaces/mailbox-lock.ts +0 -32
- package/src/interfaces/mailbox-special-use.ts +0 -60
- package/src/interfaces/mailbox.ts +0 -115
- package/src/interfaces/message-flag-push.ts +0 -17
- package/src/interfaces/message-flag.ts +0 -15
- package/src/interfaces/message-label.ts +0 -25
- package/src/interfaces/message-placement-move.ts +0 -15
- package/src/interfaces/message.ts +0 -65
- package/src/interfaces/organize-job-request.ts +0 -19
- package/src/interfaces/outbox-attachment.ts +0 -132
- package/src/interfaces/outbox-message.ts +0 -106
- package/src/interfaces/quarantine.ts +0 -22
- package/src/interfaces/sender-signer-standing.ts +0 -37
- package/src/interfaces/thread-message.ts +0 -264
- package/src/interfaces/unit-of-work.ts +0 -28
- package/src/mailbox-name.test.ts +0 -106
- package/src/mailbox-name.ts +0 -90
- package/src/mailbox-state-doors.test.ts +0 -104
- package/src/message-placement-doors.test.ts +0 -100
- package/src/message-settlement.test.ts +0 -132
- package/src/sender-mute.test.ts +0 -76
- package/src/types.ts +0 -820
- package/src/update-manifest.test.ts +0 -130
- package/src/update-manifest.ts +0 -22
- package/src/virtual-copy.test.ts +0 -34
- package/tsconfig.json +0 -8
- /package/{src/conformance/index.ts → dist/conformance/index.d.ts} +0 -0
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import type { JunkRoleMailboxes, RoleResolution } from "../folder-role.js";
|
|
2
|
-
import type {
|
|
3
|
-
MailboxSpecialUseItem,
|
|
4
|
-
MailboxSpecialUseValue,
|
|
5
|
-
} from "../types.js";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Special-use entries, plus the per-role lookup every special-folder operation
|
|
9
|
-
* goes through. The `find<Role>Mailbox` reads answer "which folder holds this
|
|
10
|
-
* role for this account", in the one precedence order `resolveMailboxForRole`
|
|
11
|
-
* defines: the user's appointment first (RFC 032 exclusive-folder-appointment,
|
|
12
|
-
* #976), then the server's SPECIAL-USE flag, then a conventional name.
|
|
13
|
-
*/
|
|
14
|
-
export interface IMailboxSpecialUseRepository {
|
|
15
|
-
create(
|
|
16
|
-
mailboxId: string,
|
|
17
|
-
specialUse: MailboxSpecialUseValue,
|
|
18
|
-
): Promise<MailboxSpecialUseItem>;
|
|
19
|
-
createMany(
|
|
20
|
-
mailboxId: string,
|
|
21
|
-
specialUses: MailboxSpecialUseValue[],
|
|
22
|
-
): Promise<MailboxSpecialUseItem[]>;
|
|
23
|
-
listByMailboxId(mailboxId: string): Promise<MailboxSpecialUseItem[]>;
|
|
24
|
-
deleteByMailboxId(mailboxId: string): Promise<number>;
|
|
25
|
-
findInboxMailbox(
|
|
26
|
-
accountId: string,
|
|
27
|
-
): Promise<{ mailboxId: string; fullPath: string } | null>;
|
|
28
|
-
findSentMailbox(
|
|
29
|
-
accountId: string,
|
|
30
|
-
): Promise<{ mailboxId: string; fullPath: string } | null>;
|
|
31
|
-
findTrashMailbox(
|
|
32
|
-
accountId: string,
|
|
33
|
-
): Promise<{ mailboxId: string; fullPath: string } | null>;
|
|
34
|
-
/**
|
|
35
|
-
* Trash with the evidence attached, for the two verbs that weigh it: a
|
|
36
|
-
* delete files mail somewhere retrievable, an Empty Trash destroys it, and
|
|
37
|
-
* they refuse on different grounds. `null` cannot tell them apart — an
|
|
38
|
-
* appointment naming a folder that is gone is a different answer from no
|
|
39
|
-
* folder at all, and only this read distinguishes them.
|
|
40
|
-
*/
|
|
41
|
-
resolveTrashRole(
|
|
42
|
-
accountId: string,
|
|
43
|
-
): Promise<RoleResolution<{ mailboxId: string; fullPath: string }>>;
|
|
44
|
-
findArchiveMailbox(
|
|
45
|
-
accountId: string,
|
|
46
|
-
): Promise<{ mailboxId: string; fullPath: string } | null>;
|
|
47
|
-
findJunkMailbox(
|
|
48
|
-
accountId: string,
|
|
49
|
-
): Promise<{ mailboxId: string; fullPath: string } | null>;
|
|
50
|
-
/**
|
|
51
|
-
* Junk and Trash for every account under one config, as mailbox ids. The
|
|
52
|
-
* address book is keyed by config and an address carries sightings from all
|
|
53
|
-
* of them, so a predicate over an address must weigh every account's Junk —
|
|
54
|
-
* resolving only the account in hand withholds a sender on one and restores
|
|
55
|
-
* it on the next.
|
|
56
|
-
*/
|
|
57
|
-
resolveJunkRolesForConfig(
|
|
58
|
-
accountConfigId: string,
|
|
59
|
-
): Promise<JunkRoleMailboxes>;
|
|
60
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CreateMailboxInput,
|
|
3
|
-
CreateMailboxResult,
|
|
4
|
-
MailboxItem,
|
|
5
|
-
MailboxSubtreeTransitionIntent,
|
|
6
|
-
MailboxTransitionIntent,
|
|
7
|
-
ResultList,
|
|
8
|
-
UpdateMailboxInput,
|
|
9
|
-
} from "../types.js";
|
|
10
|
-
|
|
11
|
-
export interface IMailboxRepository {
|
|
12
|
-
create(input: CreateMailboxInput): Promise<CreateMailboxResult>;
|
|
13
|
-
get(accountId: string, mailboxId: string): Promise<MailboxItem>;
|
|
14
|
-
get(accountId: string, mailboxIds: string[]): Promise<MailboxItem[]>;
|
|
15
|
-
/**
|
|
16
|
-
* Resolve the owning accountId for a mailbox by its (globally unique) id,
|
|
17
|
-
* without a tenant scope. Returns only the owner id (no row content); null
|
|
18
|
-
* when the mailbox does not exist.
|
|
19
|
-
*
|
|
20
|
-
* The result is NOT a trusted tenant — it is derived from the row, so it must
|
|
21
|
-
* never be fed back as the scope of a request-facing read. It has two uses:
|
|
22
|
-
* pure system routing/indexing that has no tenant of its own (stream bridge,
|
|
23
|
-
* search indexer), and ownership bootstrap where a request-facing caller
|
|
24
|
-
* compares the resolved owner's accountConfigId against its OWN authenticated
|
|
25
|
-
* accountConfigId to decide the caller may proceed.
|
|
26
|
-
*/
|
|
27
|
-
resolveAccountId(mailboxId: string): Promise<string | null>;
|
|
28
|
-
update(
|
|
29
|
-
accountId: string,
|
|
30
|
-
mailboxId: string,
|
|
31
|
-
input: UpdateMailboxInput,
|
|
32
|
-
remove?: string[],
|
|
33
|
-
): Promise<MailboxItem>;
|
|
34
|
-
/**
|
|
35
|
-
* Move one folder's mutation state from the state the caller read to the
|
|
36
|
-
* state it decided on, as one conditional write
|
|
37
|
-
* (docs/architecture/folder-rename-and-delete.md D3). The only writer of
|
|
38
|
-
* `syncStatus` and `pendingPath` — so a folder state written without a
|
|
39
|
-
* predicate is a type error rather than a convention.
|
|
40
|
-
*
|
|
41
|
-
* The predicate names one of the six states, not one of the four enum
|
|
42
|
-
* values: `wherePendingPath` as a string requires equality, `null` requires
|
|
43
|
-
* the column to be NULL, and omitting it predicates on `syncStatus` alone.
|
|
44
|
-
* A create settle that leaves it out matches a row a rename has claimed and
|
|
45
|
-
* strands it `synced` with a target on it, which is the seventh combination
|
|
46
|
-
* the invariant forbids.
|
|
47
|
-
*
|
|
48
|
-
* Resolves with the written row when the predicate matched, and with `null`
|
|
49
|
-
* when it did not — the row is absent, or somebody else won. The loser
|
|
50
|
-
* re-reads and re-decides; it never blind-retries and never writes anyway.
|
|
51
|
-
*/
|
|
52
|
-
transition(
|
|
53
|
-
accountId: string,
|
|
54
|
-
mailboxId: string,
|
|
55
|
-
intent: MailboxTransitionIntent,
|
|
56
|
-
): Promise<MailboxItem | null>;
|
|
57
|
-
/**
|
|
58
|
-
* Record one intent across a folder and every descendant, all-or-nothing, in
|
|
59
|
-
* one transaction (D6). Each row's UPDATE carries the from-state predicate
|
|
60
|
-
* and the affected-row count is compared to the resolved subtree, so a
|
|
61
|
-
* concurrent single-row transition rolls the whole thing back rather than
|
|
62
|
-
* being missed by a prior read.
|
|
63
|
-
*
|
|
64
|
-
* Resolves with every written row, or with `null` when any row in the
|
|
65
|
-
* subtree was not in an accepted from-state — in which case nothing was
|
|
66
|
-
* written. The named folder comes first and its descendants follow, but a
|
|
67
|
-
* caller wanting one row should find it by `mailboxId` rather than lean on
|
|
68
|
-
* that. This serves the intent only: a settle is per-row (D15).
|
|
69
|
-
*/
|
|
70
|
-
transitionSubtree(
|
|
71
|
-
accountId: string,
|
|
72
|
-
mailboxId: string,
|
|
73
|
-
intent: MailboxSubtreeTransitionIntent,
|
|
74
|
-
): Promise<MailboxItem[] | null>;
|
|
75
|
-
delete(accountId: string, mailboxId: string): Promise<void>;
|
|
76
|
-
deleteMany(accountId: string, mailboxIds: string[]): Promise<void>;
|
|
77
|
-
/**
|
|
78
|
-
* Remove a folder along with the mail it holds (D8): the messages through
|
|
79
|
-
* `deleteMessageSubtree`, so the nine per-message child tables go and one
|
|
80
|
-
* `message.removed` outbox row per message clears the search index; then the
|
|
81
|
-
* mailbox's own child rows; then, last, the mailbox row itself.
|
|
82
|
-
*
|
|
83
|
-
* "Its own child rows" includes a `message_placement_move` marker naming this
|
|
84
|
-
* folder as a move's *destination*, not only as its source. The folder it
|
|
85
|
-
* points at is gone, so the move it records can never land, and leaving the
|
|
86
|
-
* marker behind holds a message elsewhere in the account unsettled forever.
|
|
87
|
-
*
|
|
88
|
-
* Ordered, batched and resumable rather than one transaction — the caller
|
|
89
|
-
* keeps the row `deleting` until this returns, so a redelivery re-enters and
|
|
90
|
-
* continues. `filter` rows bound to this mailbox are never touched: D16
|
|
91
|
-
* refuses the delete while any binding stands, so there is nothing to unbind
|
|
92
|
-
* and deleting a user's filters is not a folder delete's decision.
|
|
93
|
-
*/
|
|
94
|
-
deleteMailboxWithMail(accountId: string, mailboxId: string): Promise<void>;
|
|
95
|
-
listByAccount(
|
|
96
|
-
accountId: string,
|
|
97
|
-
options?: { limit?: number; continuationToken?: string },
|
|
98
|
-
): Promise<ResultList<MailboxItem>>;
|
|
99
|
-
listAllByAccount(accountId: string): Promise<MailboxItem[]>;
|
|
100
|
-
findByPath(accountId: string, fullPath: string): Promise<MailboxItem | null>;
|
|
101
|
-
getOrCreateByPath(
|
|
102
|
-
accountId: string,
|
|
103
|
-
fullPath: string,
|
|
104
|
-
defaults: Omit<CreateMailboxInput, "accountId" | "fullPath">,
|
|
105
|
-
): Promise<MailboxItem>;
|
|
106
|
-
findByPathPrefix(
|
|
107
|
-
accountId: string,
|
|
108
|
-
pathPrefix: string,
|
|
109
|
-
delimiter?: string,
|
|
110
|
-
): Promise<MailboxItem[]>;
|
|
111
|
-
findBySyncStatus(
|
|
112
|
-
accountId: string,
|
|
113
|
-
syncStatus: MailboxItem["syncStatus"],
|
|
114
|
-
): Promise<MailboxItem[]>;
|
|
115
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { MessageFlagPushItem, PutMessageFlagPushInput } from "../types.js";
|
|
2
|
-
|
|
3
|
-
export interface IMessageFlagPushRepository {
|
|
4
|
-
put(input: PutMessageFlagPushInput): Promise<MessageFlagPushItem>;
|
|
5
|
-
find(
|
|
6
|
-
messageId: string,
|
|
7
|
-
flagName: string,
|
|
8
|
-
): Promise<MessageFlagPushItem | null>;
|
|
9
|
-
updateState(
|
|
10
|
-
messageId: string,
|
|
11
|
-
flagName: string,
|
|
12
|
-
state: MessageFlagPushItem["state"],
|
|
13
|
-
): Promise<MessageFlagPushItem>;
|
|
14
|
-
delete(messageId: string, flagName: string): Promise<void>;
|
|
15
|
-
listByAccountId(accountId: string): Promise<MessageFlagPushItem[]>;
|
|
16
|
-
listByMailboxId(mailboxId: string): Promise<MessageFlagPushItem[]>;
|
|
17
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { CreateMessageFlagInput, MessageFlagItem } from "../types.js";
|
|
2
|
-
|
|
3
|
-
export interface IMessageFlagRepository {
|
|
4
|
-
create(input: CreateMessageFlagInput): Promise<MessageFlagItem>;
|
|
5
|
-
get(messageFlagId: string): Promise<MessageFlagItem>;
|
|
6
|
-
get(messageFlagIds: string[]): Promise<MessageFlagItem[]>;
|
|
7
|
-
delete(messageFlagId: string): Promise<void>;
|
|
8
|
-
deleteMany(messageFlagIds: string[]): Promise<void>;
|
|
9
|
-
getFlags(messageId: string): Promise<MessageFlagItem[]>;
|
|
10
|
-
hasFlag(messageId: string, flagName: string): Promise<boolean>;
|
|
11
|
-
addFlag(messageId: string, flagName: string): Promise<MessageFlagItem>;
|
|
12
|
-
removeFlag(messageId: string, flagName: string): Promise<void>;
|
|
13
|
-
addFlags(messageId: string, flagNames: string[]): Promise<void>;
|
|
14
|
-
removeFlags(messageId: string, flagNames: string[]): Promise<void>;
|
|
15
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import type { CreateMessageLabelInput, MessageLabelItem } from "../types.js";
|
|
2
|
-
|
|
3
|
-
export interface IMessageLabelRepository {
|
|
4
|
-
apply(input: CreateMessageLabelInput): Promise<MessageLabelItem>;
|
|
5
|
-
remove(messageId: string, labelId: string): Promise<void>;
|
|
6
|
-
listByMessageId(messageId: string): Promise<MessageLabelItem[]>;
|
|
7
|
-
/**
|
|
8
|
-
* Batch-fetch every MessageLabel row across a page of messages in one query
|
|
9
|
-
* — the read-time enrichment a thread listing needs (issue #26), mirroring
|
|
10
|
-
* the one-BatchGet-per-page contract `enrichThreadRows` already holds for
|
|
11
|
-
* Message/Address.
|
|
12
|
-
*/
|
|
13
|
-
listByMessageIds(messageIds: string[]): Promise<MessageLabelItem[]>;
|
|
14
|
-
listByLabelId(
|
|
15
|
-
accountConfigId: string,
|
|
16
|
-
labelId: string,
|
|
17
|
-
): Promise<MessageLabelItem[]>;
|
|
18
|
-
/**
|
|
19
|
-
* Delete every MessageLabel row for a label in one statement — the message
|
|
20
|
-
* side of a label delete's cascade (issue #26). A label delete cascades in
|
|
21
|
-
* both directions: this clears the applied-to-messages side, and the
|
|
22
|
-
* caller separately deletes any filter whose actionLabelId is this label.
|
|
23
|
-
*/
|
|
24
|
-
removeAllByLabelId(accountConfigId: string, labelId: string): Promise<void>;
|
|
25
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
MessagePlacementMoveItem,
|
|
3
|
-
PutMessagePlacementMoveInput,
|
|
4
|
-
} from "../types.js";
|
|
5
|
-
|
|
6
|
-
export interface IMessagePlacementMoveRepository {
|
|
7
|
-
put(input: PutMessagePlacementMoveInput): Promise<MessagePlacementMoveItem>;
|
|
8
|
-
find(messageId: string): Promise<MessagePlacementMoveItem | null>;
|
|
9
|
-
updateState(
|
|
10
|
-
messageId: string,
|
|
11
|
-
state: MessagePlacementMoveItem["state"],
|
|
12
|
-
): Promise<MessagePlacementMoveItem>;
|
|
13
|
-
delete(messageId: string): Promise<void>;
|
|
14
|
-
listByAccountId(accountId: string): Promise<MessagePlacementMoveItem[]>;
|
|
15
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CreateMessageInput,
|
|
3
|
-
MessageDescription,
|
|
4
|
-
MessageIdSource,
|
|
5
|
-
MessageItem,
|
|
6
|
-
PlacementPredicate,
|
|
7
|
-
PlacementTransitionInput,
|
|
8
|
-
ResultList,
|
|
9
|
-
UpdateMessageInput,
|
|
10
|
-
} from "../types.js";
|
|
11
|
-
|
|
12
|
-
export interface IMessageRepository {
|
|
13
|
-
create(input: CreateMessageInput): Promise<MessageItem>;
|
|
14
|
-
upsert(input: CreateMessageInput): Promise<MessageItem>;
|
|
15
|
-
upsertWithStatus(
|
|
16
|
-
input: CreateMessageInput,
|
|
17
|
-
): Promise<{ item: MessageItem; created: boolean }>;
|
|
18
|
-
get(messageId: string): Promise<MessageItem>;
|
|
19
|
-
get(messageIds: string[]): Promise<MessageItem[]>;
|
|
20
|
-
update(messageId: string, input: UpdateMessageInput): Promise<MessageItem>;
|
|
21
|
-
clearBodyStorageKey(messageId: string): Promise<MessageItem>;
|
|
22
|
-
clearSpamReport(messageId: string): Promise<MessageItem>;
|
|
23
|
-
delete(messageId: string): Promise<void>;
|
|
24
|
-
deleteMany(messageIds: string[]): Promise<void>;
|
|
25
|
-
/**
|
|
26
|
-
* Delete the row only while its placement still matches what the caller
|
|
27
|
-
* read (imap-mutations R3). Resolves `false` when the predicate did not
|
|
28
|
-
* match and nothing was deleted.
|
|
29
|
-
*/
|
|
30
|
-
deleteIfPlacement(
|
|
31
|
-
messageId: string,
|
|
32
|
-
expected: PlacementPredicate,
|
|
33
|
-
): Promise<boolean>;
|
|
34
|
-
listByMailbox(
|
|
35
|
-
mailboxId: string,
|
|
36
|
-
options?: { limit?: number; continuationToken?: string },
|
|
37
|
-
): Promise<ResultList<MessageItem>>;
|
|
38
|
-
listAllByMailbox(mailboxId: string): Promise<MessageItem[]>;
|
|
39
|
-
describe(messageId: string): Promise<MessageDescription>;
|
|
40
|
-
updateUid(
|
|
41
|
-
messageId: string,
|
|
42
|
-
newUid: number,
|
|
43
|
-
newMailboxId: string,
|
|
44
|
-
): Promise<MessageItem>;
|
|
45
|
-
/**
|
|
46
|
-
* Move the row's placement from the state the caller read to the state it
|
|
47
|
-
* decided on, as one conditional write (imap-mutations R3). The only writer
|
|
48
|
-
* of `mailboxId`, `status`, `syncStatus`, `abandonedMutation`,
|
|
49
|
-
* `originalMailboxId` and `originalUid`, apart from the settle in
|
|
50
|
-
* {@link updateUid} — so a placement written without a predicate is a type
|
|
51
|
-
* error rather than a convention.
|
|
52
|
-
*
|
|
53
|
-
* Resolves with the written row when the predicate matched, and with
|
|
54
|
-
* `undefined` when it did not — someone else won, or the row is gone. The
|
|
55
|
-
* loser re-reads and re-decides; it never blind-retries and never writes
|
|
56
|
-
* anyway.
|
|
57
|
-
*/
|
|
58
|
-
transitionPlacement(
|
|
59
|
-
messageId: string,
|
|
60
|
-
expected: PlacementPredicate,
|
|
61
|
-
next: PlacementTransitionInput,
|
|
62
|
-
): Promise<MessageItem | undefined>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export type { MessageIdSource };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CreateOrganizeJobRequestInput,
|
|
3
|
-
OrganizeJobRequestItem,
|
|
4
|
-
ResultList,
|
|
5
|
-
UpdateOrganizeJobRequestInput,
|
|
6
|
-
} from "../types.js";
|
|
7
|
-
|
|
8
|
-
export interface IOrganizeJobRequestRepository {
|
|
9
|
-
create(input: CreateOrganizeJobRequestInput): Promise<OrganizeJobRequestItem>;
|
|
10
|
-
get(organizeJobId: string): Promise<OrganizeJobRequestItem>;
|
|
11
|
-
update(
|
|
12
|
-
organizeJobId: string,
|
|
13
|
-
input: UpdateOrganizeJobRequestInput,
|
|
14
|
-
): Promise<OrganizeJobRequestItem>;
|
|
15
|
-
listByAccountConfig(
|
|
16
|
-
accountConfigId: string,
|
|
17
|
-
options?: { limit?: number; continuationToken?: string },
|
|
18
|
-
): Promise<ResultList<OrganizeJobRequestItem>>;
|
|
19
|
-
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import type { OutboxAttachmentItem } from "../types.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Whether an attachment is spoken for: uploaded and confirmed, or reserved and
|
|
5
|
-
* not yet lapsed. The cap counts these and nothing else. One definition, because
|
|
6
|
-
* the repository and the service both have to agree on it exactly.
|
|
7
|
-
*/
|
|
8
|
-
export const holdsRoom = (
|
|
9
|
-
item: OutboxAttachmentItem,
|
|
10
|
-
nowSeconds: number,
|
|
11
|
-
): boolean =>
|
|
12
|
-
item.state === "Stored" || item.reservationExpiresAt >= nowSeconds;
|
|
13
|
-
|
|
14
|
-
export interface CreateOutboxAttachmentInput {
|
|
15
|
-
outboxAttachmentId: string;
|
|
16
|
-
outboxMessageId: string;
|
|
17
|
-
accountId: string;
|
|
18
|
-
accountConfigId: string;
|
|
19
|
-
filename: string;
|
|
20
|
-
contentType: string;
|
|
21
|
-
sizeBytes: number;
|
|
22
|
-
storageKey: string;
|
|
23
|
-
reservationExpiresAt: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* The numbers the reservation must fit inside. They come from the caller — the
|
|
28
|
-
* cap is a business rule and belongs with the rest of them — but they are
|
|
29
|
-
* applied here, where the count and the insert can happen together.
|
|
30
|
-
*/
|
|
31
|
-
export interface OutboxAttachmentCap {
|
|
32
|
-
maxTotalBytes: number;
|
|
33
|
-
maxCount: number;
|
|
34
|
-
/** Unix seconds. A Pending row past its expiry stops holding room. */
|
|
35
|
-
nowSeconds: number;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export type ReserveOutboxAttachmentResult =
|
|
39
|
-
| { outcome: "Reserved"; item: OutboxAttachmentItem }
|
|
40
|
-
| { outcome: "OverByteCap"; usedBytes: number }
|
|
41
|
-
| { outcome: "OverCountCap"; usedBytes: number };
|
|
42
|
-
|
|
43
|
-
export interface IOutboxAttachmentRepository {
|
|
44
|
-
/**
|
|
45
|
-
* Claim room on a draft, or report why there is none.
|
|
46
|
-
*
|
|
47
|
-
* **The invariant an implementation owes its callers:** of two reservations
|
|
48
|
-
* for the same draft running concurrently, at most one may observe a total
|
|
49
|
-
* that does not include the other. Either one of them sees the other's row,
|
|
50
|
-
* or one of them fails. Both being told there was room is a breach, and the
|
|
51
|
-
* consequence is a message that cannot be sent — phase 4 builds a MIME body
|
|
52
|
-
* from these rows and the receiving server rejects it.
|
|
53
|
-
*
|
|
54
|
-
* A count-then-insert only satisfies that under serializable isolation or an
|
|
55
|
-
* external lock. **The drizzle/SQLite implementation gets it from the lock,
|
|
56
|
-
* not from the schema or the isolation level:** `runInTransaction` opens a
|
|
57
|
-
* unit with `BEGIN IMMEDIATE`, so it holds the file's write lock from before
|
|
58
|
-
* its first read, and the module-level write queue in `tx.ts` orders the
|
|
59
|
-
* units inside one process. Two writer processes against one SQLite file are
|
|
60
|
-
* ordered by that lock rather than over-admitting.
|
|
61
|
-
*
|
|
62
|
-
* **An adapter without serializable isolation must not do a
|
|
63
|
-
* read-then-write.** On DynamoDB in particular, a Query followed by a
|
|
64
|
-
* PutItem breaches this silently and is the failure mode that matters: it is
|
|
65
|
-
* the deployment that actually scales horizontally. Use a conditional write
|
|
66
|
-
* on a per-draft aggregate instead — an `UpdateItem` that adds the size and
|
|
67
|
-
* carries a `ConditionExpression` bounding the running total, decided on
|
|
68
|
-
* whether the condition held — and derive `usedBytes` for the rejection from
|
|
69
|
-
* the same item.
|
|
70
|
-
*
|
|
71
|
-
* Either way the caller supplies the limits: the cap is a business rule and
|
|
72
|
-
* lives with the rest of them. What is delegated here is only the atomicity.
|
|
73
|
-
*/
|
|
74
|
-
reserve(
|
|
75
|
-
input: CreateOutboxAttachmentInput,
|
|
76
|
-
cap: OutboxAttachmentCap,
|
|
77
|
-
): Promise<ReserveOutboxAttachmentResult>;
|
|
78
|
-
|
|
79
|
-
/** One attachment, scoped to its tenant. Throws NotFound when it is gone. */
|
|
80
|
-
get(
|
|
81
|
-
accountConfigId: string,
|
|
82
|
-
outboxAttachmentId: string,
|
|
83
|
-
): Promise<OutboxAttachmentItem>;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Everything a draft holds, lapsed reservations included. Callers that care
|
|
87
|
-
* about what is live filter on state and `reservationExpiresAt`.
|
|
88
|
-
*/
|
|
89
|
-
listByOutboxMessage(
|
|
90
|
-
accountConfigId: string,
|
|
91
|
-
outboxMessageId: string,
|
|
92
|
-
): Promise<OutboxAttachmentItem[]>;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Move a reservation to Stored at the size storage actually holds. Returns
|
|
96
|
-
* null when the row is gone or no longer Pending, so a caller can tell a
|
|
97
|
-
* lapsed reservation from a confirmed one without a second read.
|
|
98
|
-
*/
|
|
99
|
-
markStored(
|
|
100
|
-
accountConfigId: string,
|
|
101
|
-
outboxAttachmentId: string,
|
|
102
|
-
sizeBytes: number,
|
|
103
|
-
): Promise<OutboxAttachmentItem | null>;
|
|
104
|
-
|
|
105
|
-
/** Drop specific attachments from a draft. */
|
|
106
|
-
deleteMany(
|
|
107
|
-
accountConfigId: string,
|
|
108
|
-
outboxAttachmentIds: string[],
|
|
109
|
-
): Promise<void>;
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Drop the draft's reservations that lapsed without ever being confirmed, and
|
|
113
|
-
* report which ids went.
|
|
114
|
-
*
|
|
115
|
-
* A `Pending` row past its expiry already stops holding room, but until it is
|
|
116
|
-
* gone it still names an object — which is enough for the sweep to treat that
|
|
117
|
-
* object as accounted for and leave it. So the row has to go, and the sweep
|
|
118
|
-
* collects the bytes on the same pass. `complete` refuses a lapsed row, so
|
|
119
|
-
* nothing is racing this.
|
|
120
|
-
*/
|
|
121
|
-
deleteLapsedReservations(
|
|
122
|
-
accountConfigId: string,
|
|
123
|
-
outboxMessageId: string,
|
|
124
|
-
nowSeconds: number,
|
|
125
|
-
): Promise<string[]>;
|
|
126
|
-
|
|
127
|
-
/** Drop everything a draft holds, as part of retiring the draft. */
|
|
128
|
-
deleteByOutboxMessage(
|
|
129
|
-
accountConfigId: string,
|
|
130
|
-
outboxMessageId: string,
|
|
131
|
-
): Promise<void>;
|
|
132
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CreateOutboxMessageInput,
|
|
3
|
-
OutboxMessageItem,
|
|
4
|
-
ResultList,
|
|
5
|
-
UpdateOutboxMessageInput,
|
|
6
|
-
} from "../types.js";
|
|
7
|
-
|
|
8
|
-
/** `appendedUid` when no IMAP APPEND has been confirmed for the row. */
|
|
9
|
-
export const APPENDED_UID_NONE = 0;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* `appendedUid` when an APPEND was confirmed but the server named no uid for
|
|
13
|
-
* it. UIDPLUS is an extension; a server without it files the copy and reports
|
|
14
|
-
* nothing, and "filed" still has to be distinguishable from "not filed".
|
|
15
|
-
*/
|
|
16
|
-
export const APPENDED_UID_UNREPORTED = -1;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Whether the copy in Sent exists. One definition, because the handler deciding
|
|
20
|
-
* whether to APPEND and the repair deciding what a stranded row means both have
|
|
21
|
-
* to agree on it exactly.
|
|
22
|
-
*
|
|
23
|
-
* Only the two values that mean "filed" say so, rather than everything that is
|
|
24
|
-
* not `APPENDED_UID_NONE`. The two mistakes are not each other's equal: reading
|
|
25
|
-
* a filed row as unfiled files a second copy the user then deletes, and reading
|
|
26
|
-
* an unfiled row as filed drops the row of a delivered message that is in no
|
|
27
|
-
* folder — the disappearance the whole repair exists to prevent (#824).
|
|
28
|
-
*/
|
|
29
|
-
export const isSentCopyFiled = (
|
|
30
|
-
message: Pick<OutboxMessageItem, "appendedUid">,
|
|
31
|
-
): boolean =>
|
|
32
|
-
message.appendedUid > 0 || message.appendedUid === APPENDED_UID_UNREPORTED;
|
|
33
|
-
|
|
34
|
-
export interface IOutboxMessageRepository {
|
|
35
|
-
create(input: CreateOutboxMessageInput): Promise<OutboxMessageItem>;
|
|
36
|
-
/**
|
|
37
|
-
* `mode: "read"` (default) throws NotFoundError on a foreign message so a
|
|
38
|
-
* GET doesn't leak existence. `mode: "act"` throws ForbiddenError instead,
|
|
39
|
-
* for action verbs (PATCH/POST/DELETE) where the caller has already named
|
|
40
|
-
* the resource and the API contract says to explicitly deny rather than
|
|
41
|
-
* feign 404 — see assertAccountOwnership / assertMessagesOwned.
|
|
42
|
-
*/
|
|
43
|
-
get(
|
|
44
|
-
accountConfigId: string,
|
|
45
|
-
outboxMessageId: string,
|
|
46
|
-
mode?: "read" | "act",
|
|
47
|
-
): Promise<OutboxMessageItem>;
|
|
48
|
-
get(
|
|
49
|
-
accountConfigId: string,
|
|
50
|
-
outboxMessageIds: string[],
|
|
51
|
-
): Promise<OutboxMessageItem[]>;
|
|
52
|
-
update(
|
|
53
|
-
accountConfigId: string,
|
|
54
|
-
outboxMessageId: string,
|
|
55
|
-
input: UpdateOutboxMessageInput,
|
|
56
|
-
): Promise<OutboxMessageItem>;
|
|
57
|
-
updateStatus(
|
|
58
|
-
accountConfigId: string,
|
|
59
|
-
outboxMessageId: string,
|
|
60
|
-
status: OutboxMessageItem["status"],
|
|
61
|
-
): Promise<OutboxMessageItem>;
|
|
62
|
-
/**
|
|
63
|
-
* Write `input` only while the row still holds `expected`, and answer `null`
|
|
64
|
-
* when it does not.
|
|
65
|
-
*
|
|
66
|
-
* Every status transition is a read the caller decided on followed by a
|
|
67
|
-
* write, and the SMTP worker or a second request can move the row between
|
|
68
|
-
* the two. Naming the status that decision was made against turns the write
|
|
69
|
-
* into a compare-and-set: an edit no longer pulls a row back out of `queued`
|
|
70
|
-
* while its send event is on the wire, and a settle no longer overwrites a
|
|
71
|
-
* status the worker has already reached. `null` is the caller's to read —
|
|
72
|
-
* a conflict for an action the user asked for, and nothing to do for a
|
|
73
|
-
* settle that has been overtaken.
|
|
74
|
-
*/
|
|
75
|
-
updateIfStatus(
|
|
76
|
-
accountConfigId: string,
|
|
77
|
-
outboxMessageId: string,
|
|
78
|
-
expected: OutboxMessageItem["status"],
|
|
79
|
-
input: UpdateOutboxMessageInput,
|
|
80
|
-
): Promise<OutboxMessageItem | null>;
|
|
81
|
-
markSent(
|
|
82
|
-
accountConfigId: string,
|
|
83
|
-
outboxMessageId: string,
|
|
84
|
-
fields: { sentAt: number; smtpMessageId?: string },
|
|
85
|
-
): Promise<OutboxMessageItem>;
|
|
86
|
-
delete(accountConfigId: string, outboxMessageId: string): Promise<void>;
|
|
87
|
-
deleteMany(
|
|
88
|
-
accountConfigId: string,
|
|
89
|
-
outboxMessageIds: string[],
|
|
90
|
-
): Promise<void>;
|
|
91
|
-
listByAccount(
|
|
92
|
-
accountId: string,
|
|
93
|
-
options?: { limit?: number; continuationToken?: string },
|
|
94
|
-
): Promise<ResultList<OutboxMessageItem>>;
|
|
95
|
-
/**
|
|
96
|
-
* One keyset scan over several accounts, ordered globally by createdAt then
|
|
97
|
-
* outboxMessageId. The continuation token names a position in that single
|
|
98
|
-
* ordering rather than one position per account, so a second page stays
|
|
99
|
-
* coherent however the accounts' rows interleave.
|
|
100
|
-
*/
|
|
101
|
-
listByAccounts(
|
|
102
|
-
accountIds: string[],
|
|
103
|
-
options?: { limit?: number; continuationToken?: string },
|
|
104
|
-
): Promise<ResultList<OutboxMessageItem>>;
|
|
105
|
-
listQueued(accountId: string): Promise<OutboxMessageItem[]>;
|
|
106
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { QuarantineItem, QuarantineUpsertInput } from "../types.js";
|
|
2
|
-
|
|
3
|
-
export interface IQuarantineRepository {
|
|
4
|
-
/**
|
|
5
|
-
* Every quarantined message for one user, newest first. Unpaginated: the
|
|
6
|
-
* list is small by design, and it is read whole both by the settings
|
|
7
|
-
* surface and by a sync round that keeps it in memory.
|
|
8
|
-
*/
|
|
9
|
-
listByAccountConfigId(accountConfigId: string): Promise<QuarantineItem[]>;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Record a message the sync path could not apply.
|
|
13
|
-
*
|
|
14
|
-
* Idempotent on the message's identity: the row is keyed by an id derived
|
|
15
|
-
* from (accountId, mailboxId, uidValidity, uid), so quarantining the same
|
|
16
|
-
* message twice rewrites one row instead of accumulating. The derivation
|
|
17
|
-
* happens here rather than at the call site — see `QuarantineUpsertInput`.
|
|
18
|
-
*
|
|
19
|
-
* A cursor may only move past a message once this has resolved.
|
|
20
|
-
*/
|
|
21
|
-
upsert(input: QuarantineUpsertInput): Promise<void>;
|
|
22
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ObserveSenderSignerStandingInput,
|
|
3
|
-
SenderSignerStandingItem,
|
|
4
|
-
} from "../types.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Per-account record of how often one sender has been seen arriving under one
|
|
8
|
-
* DKIM signing identity.
|
|
9
|
-
*
|
|
10
|
-
* The authenticity derivation asks this port two things: whether a key already
|
|
11
|
-
* had standing when a message arrived, and — afterwards — that this message be
|
|
12
|
-
* counted. `get` answers the first and must not create anything; `observe`
|
|
13
|
-
* answers the second and is the only writer.
|
|
14
|
-
*/
|
|
15
|
-
export interface ISenderSignerStandingRepository {
|
|
16
|
-
/**
|
|
17
|
-
* Record one observation of a key, creating the row at `messageCount = 1`
|
|
18
|
-
* or incrementing an existing one.
|
|
19
|
-
*
|
|
20
|
-
* `firstSeenAt` is set once, on creation, and never moves — an
|
|
21
|
-
* implementation that rewrites it on the increment path erases the age the
|
|
22
|
-
* derivation reads standing from. `lastSeenAt` advances on every call.
|
|
23
|
-
*/
|
|
24
|
-
observe(
|
|
25
|
-
input: ObserveSenderSignerStandingInput,
|
|
26
|
-
): Promise<SenderSignerStandingItem>;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* The standing of one key. Throws the adapter's not-found error when the
|
|
30
|
-
* key has never been observed, and creates nothing.
|
|
31
|
-
*/
|
|
32
|
-
get(
|
|
33
|
-
accountConfigId: string,
|
|
34
|
-
senderKey: string,
|
|
35
|
-
signerDomain: string,
|
|
36
|
-
): Promise<SenderSignerStandingItem>;
|
|
37
|
-
}
|