@remit/data-ports 0.0.83 → 0.0.85

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.
Files changed (174) hide show
  1. package/dist/account-settings.d.ts +371 -0
  2. package/dist/account-settings.js +114 -0
  3. package/dist/conformance/account.d.ts +3 -0
  4. package/dist/conformance/account.js +118 -0
  5. package/dist/conformance/calendar-collection.d.ts +3 -0
  6. package/dist/conformance/calendar-collection.js +251 -0
  7. package/dist/conformance/calendar-event-index.d.ts +3 -0
  8. package/dist/conformance/calendar-event-index.js +114 -0
  9. package/dist/conformance/calendar-feed-token.d.ts +3 -0
  10. package/dist/conformance/calendar-feed-token.js +97 -0
  11. package/dist/conformance/calendar-object.d.ts +3 -0
  12. package/dist/conformance/calendar-object.js +156 -0
  13. package/dist/conformance/calendar-suggestion.d.ts +3 -0
  14. package/dist/conformance/calendar-suggestion.js +255 -0
  15. package/{src/conformance/harness.ts → dist/conformance/harness.d.ts} +4 -4
  16. package/dist/conformance/harness.js +1 -0
  17. package/dist/conformance/index.js +8 -0
  18. package/dist/conformance/label.d.ts +3 -0
  19. package/dist/conformance/label.js +92 -0
  20. package/dist/conformance/sender-signer-standing.d.ts +3 -0
  21. package/dist/conformance/sender-signer-standing.js +81 -0
  22. package/dist/display-name.d.ts +1 -0
  23. package/dist/display-name.js +26 -0
  24. package/dist/errors.d.ts +150 -0
  25. package/dist/errors.js +181 -0
  26. package/dist/filter-ttl.d.ts +7 -0
  27. package/{src/filter-ttl.ts → dist/filter-ttl.js} +8 -11
  28. package/dist/folder-role.d.ts +239 -0
  29. package/dist/folder-role.js +276 -0
  30. package/dist/id.d.ts +124 -0
  31. package/{src/id.ts → dist/id.js} +41 -127
  32. package/dist/index.d.ts +37 -0
  33. package/dist/index.js +5 -0
  34. package/dist/interfaces/account-config.d.ts +15 -0
  35. package/dist/interfaces/account-config.js +1 -0
  36. package/dist/interfaces/account-export-request.d.ts +10 -0
  37. package/dist/interfaces/account-export-request.js +1 -0
  38. package/dist/interfaces/account-setting.d.ts +8 -0
  39. package/dist/interfaces/account-setting.js +1 -0
  40. package/dist/interfaces/account.d.ts +29 -0
  41. package/dist/interfaces/account.js +1 -0
  42. package/dist/interfaces/address.d.ts +70 -0
  43. package/dist/interfaces/address.js +1 -0
  44. package/dist/interfaces/calendar-collection.d.ts +38 -0
  45. package/dist/interfaces/calendar-collection.js +1 -0
  46. package/dist/interfaces/calendar-event-index.d.ts +19 -0
  47. package/dist/interfaces/calendar-event-index.js +1 -0
  48. package/dist/interfaces/calendar-feed-token.d.ts +31 -0
  49. package/dist/interfaces/calendar-feed-token.js +1 -0
  50. package/dist/interfaces/calendar-object.d.ts +36 -0
  51. package/dist/interfaces/calendar-object.js +1 -0
  52. package/dist/interfaces/calendar-store.d.ts +93 -0
  53. package/dist/interfaces/calendar-store.js +1 -0
  54. package/dist/interfaces/calendar-suggestion.d.ts +62 -0
  55. package/dist/interfaces/calendar-suggestion.js +1 -0
  56. package/dist/interfaces/config-import.d.ts +8 -0
  57. package/dist/interfaces/config-import.js +1 -0
  58. package/dist/interfaces/envelope.d.ts +24 -0
  59. package/dist/interfaces/envelope.js +1 -0
  60. package/dist/interfaces/filter.d.ts +28 -0
  61. package/dist/interfaces/filter.js +1 -0
  62. package/dist/interfaces/label.d.ts +17 -0
  63. package/dist/interfaces/label.js +1 -0
  64. package/dist/interfaces/mailbox-lock.d.ts +12 -0
  65. package/dist/interfaces/mailbox-lock.js +1 -0
  66. package/dist/interfaces/mailbox-special-use.d.ts +54 -0
  67. package/dist/interfaces/mailbox-special-use.js +1 -0
  68. package/dist/interfaces/mailbox.d.ts +79 -0
  69. package/dist/interfaces/mailbox.js +1 -0
  70. package/dist/interfaces/message-flag-push.d.ts +9 -0
  71. package/dist/interfaces/message-flag-push.js +1 -0
  72. package/dist/interfaces/message-flag.d.ts +14 -0
  73. package/dist/interfaces/message-flag.js +1 -0
  74. package/dist/interfaces/message-label.d.ts +21 -0
  75. package/dist/interfaces/message-label.js +1 -0
  76. package/dist/interfaces/message-placement-move.d.ts +8 -0
  77. package/dist/interfaces/message-placement-move.js +1 -0
  78. package/dist/interfaces/message.d.ts +60 -0
  79. package/dist/interfaces/message.js +1 -0
  80. package/dist/interfaces/organize-job-request.d.ts +10 -0
  81. package/dist/interfaces/organize-job-request.js +1 -0
  82. package/dist/interfaces/outbox-attachment.d.ts +101 -0
  83. package/dist/interfaces/outbox-attachment.js +7 -0
  84. package/dist/interfaces/outbox-message.d.ts +70 -0
  85. package/dist/interfaces/outbox-message.js +20 -0
  86. package/dist/interfaces/quarantine.d.ts +20 -0
  87. package/dist/interfaces/quarantine.js +1 -0
  88. package/dist/interfaces/sender-signer-standing.d.ts +26 -0
  89. package/dist/interfaces/sender-signer-standing.js +1 -0
  90. package/dist/interfaces/sync-warning.d.ts +11 -0
  91. package/dist/interfaces/sync-warning.js +1 -0
  92. package/dist/interfaces/thread-message.d.ts +202 -0
  93. package/dist/interfaces/thread-message.js +1 -0
  94. package/dist/mailbox-name.d.ts +35 -0
  95. package/dist/mailbox-name.js +68 -0
  96. package/dist/message-parts.d.ts +22 -0
  97. package/dist/message-parts.js +18 -0
  98. package/dist/message-settlement.d.ts +35 -0
  99. package/{src/message-settlement.ts → dist/message-settlement.js} +5 -19
  100. package/dist/mutation-events.d.ts +19 -0
  101. package/{src/mutation-events.ts → dist/mutation-events.js} +2 -5
  102. package/dist/sender-mute.d.ts +26 -0
  103. package/{src/sender-mute.ts → dist/sender-mute.js} +12 -34
  104. package/dist/sync-warning-state.d.ts +3 -0
  105. package/dist/sync-warning-state.js +5 -0
  106. package/dist/types.d.ts +491 -0
  107. package/dist/types.js +1 -0
  108. package/dist/update-manifest.d.ts +24 -0
  109. package/dist/update-manifest.js +20 -0
  110. package/dist/virtual-copy.d.ts +8 -0
  111. package/{src/virtual-copy.ts → dist/virtual-copy.js} +10 -15
  112. package/dist/wellknown.d.ts +47 -0
  113. package/{src/wellknown.ts → dist/wellknown.js} +26 -49
  114. package/package.json +44 -79
  115. package/src/account-settings.ts +0 -194
  116. package/src/conformance/account.ts +0 -104
  117. package/src/conformance/calendar-collection.ts +0 -342
  118. package/src/conformance/calendar-event-index.ts +0 -203
  119. package/src/conformance/calendar-feed-token.ts +0 -148
  120. package/src/conformance/calendar-object.ts +0 -269
  121. package/src/conformance/calendar-suggestion.ts +0 -490
  122. package/src/conformance/label.ts +0 -136
  123. package/src/conformance/sender-signer-standing.ts +0 -117
  124. package/src/display-name.test.ts +0 -101
  125. package/src/display-name.ts +0 -40
  126. package/src/errors.ts +0 -244
  127. package/src/folder-role.test.ts +0 -422
  128. package/src/folder-role.ts +0 -447
  129. package/src/id.test.ts +0 -352
  130. package/src/index.ts +0 -170
  131. package/src/interfaces/account-config.ts +0 -25
  132. package/src/interfaces/account-export-request.ts +0 -21
  133. package/src/interfaces/account-setting.ts +0 -14
  134. package/src/interfaces/account.ts +0 -43
  135. package/src/interfaces/address.ts +0 -122
  136. package/src/interfaces/calendar-collection.ts +0 -60
  137. package/src/interfaces/calendar-event-index.ts +0 -34
  138. package/src/interfaces/calendar-feed-token.ts +0 -38
  139. package/src/interfaces/calendar-object.ts +0 -58
  140. package/src/interfaces/calendar-suggestion.ts +0 -93
  141. package/src/interfaces/calendar-unit-of-work.ts +0 -47
  142. package/src/interfaces/config-import.ts +0 -16
  143. package/src/interfaces/envelope.ts +0 -32
  144. package/src/interfaces/filter-anchor-transaction.ts +0 -23
  145. package/src/interfaces/filter-anchor.ts +0 -11
  146. package/src/interfaces/filter.ts +0 -41
  147. package/src/interfaces/label.ts +0 -30
  148. package/src/interfaces/mailbox-lock.ts +0 -32
  149. package/src/interfaces/mailbox-special-use.ts +0 -60
  150. package/src/interfaces/mailbox.ts +0 -115
  151. package/src/interfaces/message-flag-push.ts +0 -17
  152. package/src/interfaces/message-flag.ts +0 -15
  153. package/src/interfaces/message-label.ts +0 -25
  154. package/src/interfaces/message-placement-move.ts +0 -15
  155. package/src/interfaces/message.ts +0 -65
  156. package/src/interfaces/organize-job-request.ts +0 -19
  157. package/src/interfaces/outbox-attachment.ts +0 -132
  158. package/src/interfaces/outbox-message.ts +0 -106
  159. package/src/interfaces/quarantine.ts +0 -22
  160. package/src/interfaces/sender-signer-standing.ts +0 -37
  161. package/src/interfaces/thread-message.ts +0 -264
  162. package/src/interfaces/unit-of-work.ts +0 -28
  163. package/src/mailbox-name.test.ts +0 -106
  164. package/src/mailbox-name.ts +0 -90
  165. package/src/mailbox-state-doors.test.ts +0 -104
  166. package/src/message-placement-doors.test.ts +0 -100
  167. package/src/message-settlement.test.ts +0 -132
  168. package/src/sender-mute.test.ts +0 -76
  169. package/src/types.ts +0 -820
  170. package/src/update-manifest.test.ts +0 -130
  171. package/src/update-manifest.ts +0 -22
  172. package/src/virtual-copy.test.ts +0 -34
  173. package/tsconfig.json +0 -8
  174. /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
- }