@rapidmx/web-client 0.21.0 → 0.23.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.
Files changed (897) hide show
  1. package/README.md +48 -14
  2. package/apps/admin/_layout.tsx +2 -2
  3. package/apps/admin/audit-log/index.tsx +4 -4
  4. package/apps/admin/branding/index.tsx +3 -3
  5. package/apps/admin/data-requests/index.tsx +8 -8
  6. package/apps/admin/distribution-lists/[uid].tsx +3 -3
  7. package/apps/admin/distribution-lists/index.tsx +4 -4
  8. package/apps/admin/distribution-lists/new/index.tsx +5 -5
  9. package/apps/admin/domains/[uid].tsx +6 -6
  10. package/apps/admin/domains/index.tsx +4 -4
  11. package/apps/admin/domains/new/index.tsx +5 -5
  12. package/apps/admin/encryption-policy/index.tsx +1 -1
  13. package/apps/admin/escrow-scopes/[uid].tsx +7 -7
  14. package/apps/admin/escrow-scopes/index.tsx +4 -4
  15. package/apps/admin/escrow-scopes/new/index.tsx +5 -5
  16. package/apps/admin/index.tsx +6 -6
  17. package/apps/admin/ingest-queue/index.tsx +4 -4
  18. package/apps/admin/mailbox-policy/index.tsx +1 -1
  19. package/apps/admin/mailboxes/[uid].tsx +5 -5
  20. package/apps/admin/quarantine/index.tsx +5 -5
  21. package/apps/admin/retention-policy/index.tsx +3 -3
  22. package/apps/admin/signing-certificates/index.tsx +5 -5
  23. package/apps/admin/transport-rules/[uid].tsx +5 -5
  24. package/apps/admin/transport-rules/_transportRuleConfig.tsx +3 -3
  25. package/apps/admin/transport-rules/index.tsx +4 -4
  26. package/apps/admin/transport-rules/new/index.tsx +5 -5
  27. package/apps/escrow/_layout.tsx +1 -1
  28. package/apps/escrow/audit-log/index.tsx +4 -4
  29. package/apps/escrow/index.tsx +4 -4
  30. package/apps/escrow/matters/[uid].tsx +10 -10
  31. package/apps/escrow/matters/new/index.tsx +6 -6
  32. package/apps/shared/appearance/AppearanceForm.tsx +3 -3
  33. package/apps/shared/appearance/AppearanceHead.tsx +1 -1
  34. package/apps/shared/appearance/AppearanceProvider.tsx +3 -3
  35. package/apps/shared/appearance/appearanceCache.ts +1 -1
  36. package/apps/shared/appearance/appearanceContext.ts +1 -1
  37. package/apps/shared/appearance/theme.ts +1 -1
  38. package/apps/shared/auth/adminAccess.ts +1 -1
  39. package/apps/shared/calendar/bookingPlugin.ts +1 -1
  40. package/apps/shared/calendar/calendarLiveUpdates.ts +1 -1
  41. package/apps/shared/calendar/calendarReminders.ts +1 -1
  42. package/apps/shared/calendar/useCalendarReminders.ts +1 -1
  43. package/apps/shared/components/admin/diagnostics/DiagnosticsManager.tsx +1 -1
  44. package/apps/shared/components/admin/diagnostics/InstalledPlugins.tsx +2 -2
  45. package/apps/shared/components/admin/diagnostics/LogsPanel.tsx +2 -2
  46. package/apps/shared/components/admin/diagnostics/PackagesTable.tsx +1 -1
  47. package/apps/shared/components/admin/diagnostics/RuntimePanel.tsx +1 -1
  48. package/apps/shared/components/admin/diagnostics/SystemPanel.tsx +2 -2
  49. package/apps/shared/components/admin/diagnostics/VersionsPanel.tsx +1 -1
  50. package/apps/shared/components/admin/diagnostics/diagnosticsApi.ts +1 -1
  51. package/apps/shared/components/admin/diagnostics/format.ts +1 -1
  52. package/apps/shared/components/admin/diagnostics/logClient.ts +1 -1
  53. package/apps/shared/components/admin/distributionLists/MemberListCard.tsx +4 -4
  54. package/apps/shared/components/admin/elevation.ts +1 -1
  55. package/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.tsx +3 -3
  56. package/apps/shared/components/admin/layout/AdminShell.tsx +8 -8
  57. package/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.tsx +6 -6
  58. package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +10 -8
  59. package/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.tsx +4 -4
  60. package/apps/shared/components/admin/mailboxes/MailboxTable.tsx +1 -1
  61. package/apps/shared/components/admin/mailboxes/ResourceSettingsCard.tsx +19 -14
  62. package/apps/shared/components/admin/mailboxes/ShareAccessCard.tsx +5 -5
  63. package/apps/shared/components/admin/settings/BrandingForm.tsx +5 -5
  64. package/apps/shared/components/admin/settings/DomainDnsSetup.tsx +5 -5
  65. package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +4 -4
  66. package/apps/shared/components/admin/settings/LoadedSettingsForm.tsx +2 -2
  67. package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +32 -27
  68. package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +4 -4
  69. package/apps/shared/components/admin/settings/PluginsManager.tsx +5 -5
  70. package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +5 -5
  71. package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +7 -7
  72. package/apps/shared/components/admin/setup/SetupWizard.tsx +28 -24
  73. package/apps/shared/components/admin/signOut.ts +1 -1
  74. package/apps/shared/components/admin/usePagedList.tsx +2 -2
  75. package/apps/shared/components/calendar/AppointmentQuickForm.tsx +3 -3
  76. package/apps/shared/components/calendar/CalendarListSidebar.tsx +3 -3
  77. package/apps/shared/components/calendar/DescriptionEditor.tsx +1 -1
  78. package/apps/shared/components/calendar/EventDescriptionView.tsx +1 -1
  79. package/apps/shared/components/calendar/EventDetails.tsx +16 -14
  80. package/apps/shared/components/calendar/EventEditor.tsx +54 -39
  81. package/apps/shared/components/calendar/EventExpandedForm.tsx +3 -3
  82. package/apps/shared/components/calendar/EventFormParts.tsx +2 -2
  83. package/apps/shared/components/calendar/EventModal.tsx +5 -5
  84. package/apps/shared/components/calendar/EventQuickForm.tsx +3 -3
  85. package/apps/shared/components/calendar/EventShell.tsx +1 -1
  86. package/apps/shared/components/calendar/FindATime.tsx +6 -4
  87. package/apps/shared/components/calendar/GuestInput.tsx +2 -2
  88. package/apps/shared/components/calendar/MonthView.tsx +2 -2
  89. package/apps/shared/components/calendar/QuickCreateFaces.tsx +1 -1
  90. package/apps/shared/components/calendar/QuickFaceFrame.tsx +1 -1
  91. package/apps/shared/components/calendar/RecurrenceEditor.tsx +2 -2
  92. package/apps/shared/components/calendar/RequestChangeForm.tsx +8 -6
  93. package/apps/shared/components/calendar/ResourcePicker.tsx +7 -5
  94. package/apps/shared/components/calendar/SplitDayView.tsx +1 -1
  95. package/apps/shared/components/calendar/TaskQuickForm.tsx +23 -18
  96. package/apps/shared/components/calendar/TimeGridView.tsx +5 -3
  97. package/apps/shared/components/calendar/allDay.ts +2 -2
  98. package/apps/shared/components/calendar/eventDialogFields.ts +3 -3
  99. package/apps/shared/components/calendar/eventForm.ts +3 -3
  100. package/apps/shared/components/calendar/eventFormat.ts +3 -3
  101. package/apps/shared/components/calendar/findTimeGrid.ts +2 -2
  102. package/apps/shared/components/calendar/layout/CalendarShell.tsx +11 -9
  103. package/apps/shared/components/contacts/ContactDetailPane.tsx +4 -4
  104. package/apps/shared/components/contacts/ContactForm.tsx +27 -17
  105. package/apps/shared/components/contacts/ContactsSidebar.tsx +7 -5
  106. package/apps/shared/components/contacts/KeyChangeReview.tsx +5 -5
  107. package/apps/shared/components/contacts/contactKeys.ts +3 -3
  108. package/apps/shared/components/contacts/layout/ContactsShell.tsx +9 -7
  109. package/apps/shared/components/escrow/layout/EscrowShell.tsx +6 -6
  110. package/apps/shared/components/forms/StringListField.tsx +1 -1
  111. package/apps/shared/components/layout/AppShell.tsx +12 -10
  112. package/apps/shared/components/layout/BrandingChrome.tsx +1 -1
  113. package/apps/shared/components/layout/KeyEnrollmentGate.tsx +9 -9
  114. package/apps/shared/components/layout/MailboxProvisioning.tsx +8 -6
  115. package/apps/shared/components/layout/RecoveryCodeUnlock.tsx +9 -9
  116. package/apps/shared/components/layout/ThemeSwitch.tsx +1 -1
  117. package/apps/shared/components/layout/UnlockPromptProvider.tsx +6 -6
  118. package/apps/shared/components/layout/UserMenu.tsx +6 -4
  119. package/apps/shared/components/mail/ConversationList.tsx +25 -10
  120. package/apps/shared/components/mail/ConversationThreadPane.tsx +33 -17
  121. package/apps/shared/components/mail/InviteCard.tsx +11 -9
  122. package/apps/shared/components/mail/LazyReadingPane.tsx +2 -2
  123. package/apps/shared/components/mail/MailAddress.tsx +1 -1
  124. package/apps/shared/components/mail/MailListToolbar.tsx +2 -2
  125. package/apps/shared/components/mail/MailSelectionBar.tsx +2 -2
  126. package/apps/shared/components/mail/MenuButton.tsx +1 -1
  127. package/apps/shared/components/mail/MessageDetailPane.tsx +69 -48
  128. package/apps/shared/components/mail/MoveToFolderDialog.tsx +8 -6
  129. package/apps/shared/components/mail/OutboxRowStatus.tsx +1 -1
  130. package/apps/shared/components/mail/PermanentDeleteDialog.tsx +2 -2
  131. package/apps/shared/components/mail/compose/ComposeContext.tsx +14 -3
  132. package/apps/shared/components/mail/compose/ComposeWindow.tsx +34 -30
  133. package/apps/shared/components/mail/compose/ComposeWindowPlaceholder.tsx +4 -4
  134. package/apps/shared/components/mail/compose/EmojiPicker.tsx +2 -2
  135. package/apps/shared/components/mail/compose/GifPicker.tsx +3 -3
  136. package/apps/shared/components/mail/compose/RecipientInput.tsx +1 -1
  137. package/apps/shared/components/mail/compose/ScheduleSendPicker.tsx +1 -1
  138. package/apps/shared/components/mail/compose/encryptionRequirement.ts +2 -2
  139. package/apps/shared/components/mail/compose/quotedBody.ts +5 -5
  140. package/apps/shared/components/mail/compose/recipients.ts +1 -1
  141. package/apps/shared/components/mail/invite/InviteRowChip.tsx +10 -14
  142. package/apps/shared/components/mail/invite/InviteRsvpPopover.tsx +11 -9
  143. package/apps/shared/components/mail/invite/InviteTimeline.tsx +1 -1
  144. package/apps/shared/components/mail/invite/ProposeTimeForm.tsx +2 -2
  145. package/apps/shared/components/mail/invite/inviteFormat.ts +2 -2
  146. package/apps/shared/components/mail/invite/inviteStore.ts +14 -6
  147. package/apps/shared/components/mail/labelMenu.tsx +9 -7
  148. package/apps/shared/components/mail/layout/MailShell.tsx +4 -4
  149. package/apps/shared/components/mail/listPreferences.ts +2 -2
  150. package/apps/shared/components/mail/pinnedSigners.ts +45 -19
  151. package/apps/shared/components/mail/reading/EncryptedBody.tsx +2 -2
  152. package/apps/shared/components/mail/reading/MessageBody.tsx +6 -6
  153. package/apps/shared/components/mail/reading/MessageCard.tsx +3 -3
  154. package/apps/shared/components/mail/reading/MessageSourceDialog.tsx +3 -3
  155. package/apps/shared/components/mail/reading/PendingMessageCard.tsx +1 -1
  156. package/apps/shared/components/mail/reading/bodyContent.ts +3 -3
  157. package/apps/shared/components/mail/reading/bodyHtml.ts +1 -1
  158. package/apps/shared/components/mail/reading/conversationPrint.ts +76 -0
  159. package/apps/shared/components/mail/reading/messageExport.ts +1 -1
  160. package/apps/shared/components/mail/reading/printMessage.ts +46 -9
  161. package/apps/shared/components/mail/reading/useMessageActions.ts +28 -21
  162. package/apps/shared/components/mail/unreadStyle.tsx +1 -1
  163. package/apps/shared/components/mail/verificationSeals.ts +16 -12
  164. package/apps/shared/components/mail/writableMailboxes.ts +14 -7
  165. package/apps/shared/components/rules/RuleBuilder.tsx +1 -1
  166. package/apps/shared/components/settings/SigningCertificateCard.tsx +4 -4
  167. package/apps/shared/components/settings/layout/SettingsShell.tsx +8 -6
  168. package/apps/shared/components/sharing/PrincipalListField.tsx +1 -1
  169. package/apps/shared/components/sharing/PrincipalPicker.tsx +1 -1
  170. package/apps/shared/components/sharing/PrincipalResolver.tsx +4 -4
  171. package/apps/shared/components/tasks/TasksSidebar.tsx +7 -5
  172. package/apps/shared/components/tasks/layout/TasksShell.tsx +9 -7
  173. package/apps/shared/keyboard/ShortcutsDialog.tsx +1 -1
  174. package/apps/shared/keyboard/keymap.ts +1 -0
  175. package/apps/shared/mail/decryptedMessages.ts +116 -0
  176. package/apps/shared/mail/findWellKnownFolderUid.ts +6 -4
  177. package/apps/shared/mail/folderCounts.ts +8 -4
  178. package/apps/shared/mail/folderOfType.ts +5 -3
  179. package/apps/shared/mail/folderTree.ts +1 -1
  180. package/apps/shared/mail/listSnapshots.ts +2 -2
  181. package/apps/shared/mail/messageReadState.ts +6 -5
  182. package/apps/shared/mail/newMailNotifications.ts +2 -2
  183. package/apps/shared/mail/outbox/composeBridge.ts +2 -2
  184. package/apps/shared/mail/outbox/outboxState.ts +1 -1
  185. package/apps/shared/mail/outbox/outgoingReplies.ts +2 -2
  186. package/apps/shared/mail/outbox/sendDecision.ts +2 -2
  187. package/apps/shared/mail/outbox/sendJob.ts +40 -35
  188. package/apps/shared/mail/outbox/sendOutcomes.ts +20 -15
  189. package/apps/shared/mail/outbox/useOutboxStatus.ts +5 -3
  190. package/apps/shared/mail/permanentDelete.ts +8 -7
  191. package/apps/shared/mail/primaryMailbox.ts +1 -1
  192. package/apps/shared/mail/reportNotices.ts +1 -1
  193. package/apps/shared/mail/senderBlocking.ts +36 -20
  194. package/apps/shared/mail/useMailConnection.ts +12 -10
  195. package/apps/shared/mail/useMailLiveUpdates.ts +3 -3
  196. package/apps/shared/mail/useMailboxUpdateAccess.ts +35 -11
  197. package/apps/shared/mail/useMarkMessageRead.ts +14 -7
  198. package/apps/shared/mail/useNewMailNotifications.ts +1 -1
  199. package/apps/shared/mail/usePermanentDelete.tsx +5 -3
  200. package/apps/shared/navigation/pageTitle.ts +1 -1
  201. package/apps/shared/notifications/NotificationCenter.tsx +1 -1
  202. package/apps/shared/notifications/NotificationHistoryDialog.tsx +2 -2
  203. package/apps/shared/notifications/apiErrors.ts +2 -2
  204. package/apps/shared/notifications/pushStatus.ts +1 -1
  205. package/apps/shared/notifications/systemErrors.ts +1 -1
  206. package/apps/shared/search/LocalIndexLifecycle.tsx +18 -12
  207. package/apps/shared/search/crossMailboxSearch.ts +3 -3
  208. package/apps/shared/search/localIndexBuilder.ts +24 -12
  209. package/apps/shared/search/localIndexKey.ts +1 -1
  210. package/apps/shared/search/localIndexRpcClient.ts +150 -30
  211. package/apps/shared/search/localIndexTransport.ts +84 -0
  212. package/apps/shared/search/localIndexWorker.ts +1 -1
  213. package/apps/shared/search/searchTier2.ts +3 -3
  214. package/apps/shared/signing/enrollmentTracker.ts +3 -3
  215. package/apps/shared/signing/enrollmentView.ts +1 -1
  216. package/apps/shared/signing/signingInfo.ts +1 -1
  217. package/apps/shared/signing/useSigningEnrollmentWatcher.ts +6 -4
  218. package/apps/shared/styles/app.css +14 -23
  219. package/apps/www/_layout.tsx +2 -2
  220. package/apps/www/calendar/index.tsx +20 -18
  221. package/apps/www/contacts/[uid].tsx +8 -6
  222. package/apps/www/contacts/index.tsx +19 -17
  223. package/apps/www/index.tsx +68 -48
  224. package/apps/www/messages/[uid].tsx +11 -9
  225. package/apps/www/settings/auto-reply/index.tsx +6 -4
  226. package/apps/www/settings/blocked-senders/index.tsx +9 -7
  227. package/apps/www/settings/encryption/index.tsx +38 -32
  228. package/apps/www/settings/filters/[uid].tsx +19 -14
  229. package/apps/www/settings/filters/_mailFilterRuleConfig.tsx +2 -2
  230. package/apps/www/settings/filters/index.tsx +4 -4
  231. package/apps/www/settings/filters/new/index.tsx +10 -8
  232. package/apps/www/settings/labels/index.tsx +12 -10
  233. package/apps/www/settings/privacy/index.tsx +18 -14
  234. package/apps/www/settings/profile/index.tsx +16 -11
  235. package/apps/www/settings/read-receipts/index.tsx +17 -12
  236. package/apps/www/settings/sharing/index.tsx +6 -6
  237. package/apps/www/settings/signatures/[uid].tsx +5 -5
  238. package/apps/www/settings/signatures/index.tsx +4 -4
  239. package/apps/www/settings/signatures/new/index.tsx +4 -4
  240. package/apps/www/settings/signatures/signatureDefaults.ts +1 -1
  241. package/apps/www/tasks/index.tsx +28 -23
  242. package/dist/apps/admin/_layout.d.ts +1 -1
  243. package/dist/apps/admin/_layout.js +1 -1
  244. package/dist/apps/admin/audit-log/index.d.ts +1 -1
  245. package/dist/apps/admin/audit-log/index.js +4 -4
  246. package/dist/apps/admin/branding/index.js +3 -3
  247. package/dist/apps/admin/data-requests/index.js +8 -8
  248. package/dist/apps/admin/distribution-lists/[uid].js +3 -3
  249. package/dist/apps/admin/distribution-lists/index.js +4 -4
  250. package/dist/apps/admin/distribution-lists/new/index.js +5 -5
  251. package/dist/apps/admin/domains/[uid].js +6 -6
  252. package/dist/apps/admin/domains/index.js +4 -4
  253. package/dist/apps/admin/domains/new/index.js +5 -5
  254. package/dist/apps/admin/encryption-policy/index.js +1 -1
  255. package/dist/apps/admin/escrow-scopes/[uid].d.ts +1 -1
  256. package/dist/apps/admin/escrow-scopes/[uid].js +7 -7
  257. package/dist/apps/admin/escrow-scopes/index.js +4 -4
  258. package/dist/apps/admin/escrow-scopes/new/index.js +5 -5
  259. package/dist/apps/admin/index.js +6 -6
  260. package/dist/apps/admin/ingest-queue/index.js +4 -4
  261. package/dist/apps/admin/mailbox-policy/index.js +1 -1
  262. package/dist/apps/admin/mailboxes/[uid].js +5 -5
  263. package/dist/apps/admin/quarantine/index.js +5 -5
  264. package/dist/apps/admin/retention-policy/index.js +3 -3
  265. package/dist/apps/admin/signing-certificates/index.js +5 -5
  266. package/dist/apps/admin/transport-rules/[uid].js +5 -5
  267. package/dist/apps/admin/transport-rules/_transportRuleConfig.d.ts +1 -1
  268. package/dist/apps/admin/transport-rules/_transportRuleConfig.js +2 -2
  269. package/dist/apps/admin/transport-rules/index.js +4 -4
  270. package/dist/apps/admin/transport-rules/new/index.js +5 -5
  271. package/dist/apps/escrow/_layout.d.ts +1 -1
  272. package/dist/apps/escrow/audit-log/index.d.ts +1 -1
  273. package/dist/apps/escrow/audit-log/index.js +4 -4
  274. package/dist/apps/escrow/index.js +4 -4
  275. package/dist/apps/escrow/matters/[uid].js +10 -10
  276. package/dist/apps/escrow/matters/new/index.js +6 -6
  277. package/dist/apps/shared/appearance/AppearanceForm.js +3 -3
  278. package/dist/apps/shared/appearance/AppearanceHead.js +1 -1
  279. package/dist/apps/shared/appearance/AppearanceProvider.d.ts +1 -1
  280. package/dist/apps/shared/appearance/AppearanceProvider.js +3 -3
  281. package/dist/apps/shared/appearance/appearanceCache.d.ts +1 -1
  282. package/dist/apps/shared/appearance/appearanceCache.js +1 -1
  283. package/dist/apps/shared/appearance/appearanceContext.d.ts +1 -1
  284. package/dist/apps/shared/appearance/theme.d.ts +1 -1
  285. package/dist/apps/shared/auth/adminAccess.js +1 -1
  286. package/dist/apps/shared/calendar/bookingPlugin.js +1 -1
  287. package/dist/apps/shared/calendar/calendarLiveUpdates.d.ts +1 -1
  288. package/dist/apps/shared/calendar/calendarReminders.d.ts +1 -1
  289. package/dist/apps/shared/calendar/useCalendarReminders.js +1 -1
  290. package/dist/apps/shared/components/admin/diagnostics/DiagnosticsManager.js +1 -1
  291. package/dist/apps/shared/components/admin/diagnostics/InstalledPlugins.d.ts +1 -1
  292. package/dist/apps/shared/components/admin/diagnostics/InstalledPlugins.js +2 -2
  293. package/dist/apps/shared/components/admin/diagnostics/LogsPanel.js +2 -2
  294. package/dist/apps/shared/components/admin/diagnostics/PackagesTable.js +1 -1
  295. package/dist/apps/shared/components/admin/diagnostics/RuntimePanel.js +1 -1
  296. package/dist/apps/shared/components/admin/diagnostics/SystemPanel.js +2 -2
  297. package/dist/apps/shared/components/admin/diagnostics/VersionsPanel.js +1 -1
  298. package/dist/apps/shared/components/admin/diagnostics/diagnosticsApi.js +1 -1
  299. package/dist/apps/shared/components/admin/diagnostics/format.js +1 -1
  300. package/dist/apps/shared/components/admin/diagnostics/logClient.js +1 -1
  301. package/dist/apps/shared/components/admin/distributionLists/MemberListCard.d.ts +1 -1
  302. package/dist/apps/shared/components/admin/distributionLists/MemberListCard.js +4 -4
  303. package/dist/apps/shared/components/admin/elevation.js +1 -1
  304. package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.js +3 -3
  305. package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +1 -1
  306. package/dist/apps/shared/components/admin/layout/AdminShell.js +7 -7
  307. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.d.ts +1 -1
  308. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.js +6 -6
  309. package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.d.ts +1 -1
  310. package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.js +10 -8
  311. package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.js +4 -4
  312. package/dist/apps/shared/components/admin/mailboxes/MailboxTable.d.ts +1 -1
  313. package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.d.ts +1 -1
  314. package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.js +7 -5
  315. package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.js +5 -5
  316. package/dist/apps/shared/components/admin/settings/BrandingForm.d.ts +1 -1
  317. package/dist/apps/shared/components/admin/settings/BrandingForm.js +5 -5
  318. package/dist/apps/shared/components/admin/settings/DomainDnsSetup.d.ts +1 -1
  319. package/dist/apps/shared/components/admin/settings/DomainDnsSetup.js +5 -5
  320. package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.d.ts +1 -1
  321. package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.js +4 -4
  322. package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.js +2 -2
  323. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.d.ts +1 -1
  324. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +14 -12
  325. package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.d.ts +1 -1
  326. package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.js +4 -4
  327. package/dist/apps/shared/components/admin/settings/PluginsManager.js +5 -5
  328. package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.d.ts +1 -1
  329. package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.js +5 -5
  330. package/dist/apps/shared/components/admin/setup/EscrowSetupStep.js +7 -7
  331. package/dist/apps/shared/components/admin/setup/SetupWizard.d.ts +4 -4
  332. package/dist/apps/shared/components/admin/setup/SetupWizard.js +27 -23
  333. package/dist/apps/shared/components/admin/signOut.js +1 -1
  334. package/dist/apps/shared/components/admin/usePagedList.js +2 -2
  335. package/dist/apps/shared/components/calendar/AppointmentQuickForm.js +3 -3
  336. package/dist/apps/shared/components/calendar/CalendarListSidebar.d.ts +1 -1
  337. package/dist/apps/shared/components/calendar/CalendarListSidebar.js +2 -2
  338. package/dist/apps/shared/components/calendar/DescriptionEditor.js +1 -1
  339. package/dist/apps/shared/components/calendar/EventDescriptionView.js +1 -1
  340. package/dist/apps/shared/components/calendar/EventDetails.d.ts +2 -2
  341. package/dist/apps/shared/components/calendar/EventDetails.js +16 -14
  342. package/dist/apps/shared/components/calendar/EventEditor.d.ts +2 -2
  343. package/dist/apps/shared/components/calendar/EventEditor.js +22 -20
  344. package/dist/apps/shared/components/calendar/EventExpandedForm.js +2 -2
  345. package/dist/apps/shared/components/calendar/EventFormParts.d.ts +1 -1
  346. package/dist/apps/shared/components/calendar/EventFormParts.js +1 -1
  347. package/dist/apps/shared/components/calendar/EventModal.d.ts +2 -2
  348. package/dist/apps/shared/components/calendar/EventModal.js +3 -3
  349. package/dist/apps/shared/components/calendar/EventQuickForm.js +3 -3
  350. package/dist/apps/shared/components/calendar/EventShell.js +1 -1
  351. package/dist/apps/shared/components/calendar/FindATime.js +6 -4
  352. package/dist/apps/shared/components/calendar/GuestInput.d.ts +2 -2
  353. package/dist/apps/shared/components/calendar/MonthView.d.ts +1 -1
  354. package/dist/apps/shared/components/calendar/MonthView.js +1 -1
  355. package/dist/apps/shared/components/calendar/QuickCreateFaces.js +1 -1
  356. package/dist/apps/shared/components/calendar/QuickFaceFrame.js +1 -1
  357. package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +1 -1
  358. package/dist/apps/shared/components/calendar/RecurrenceEditor.js +1 -1
  359. package/dist/apps/shared/components/calendar/RequestChangeForm.js +8 -6
  360. package/dist/apps/shared/components/calendar/ResourcePicker.d.ts +1 -1
  361. package/dist/apps/shared/components/calendar/ResourcePicker.js +7 -5
  362. package/dist/apps/shared/components/calendar/SplitDayView.d.ts +1 -1
  363. package/dist/apps/shared/components/calendar/TaskQuickForm.d.ts +1 -1
  364. package/dist/apps/shared/components/calendar/TaskQuickForm.js +9 -7
  365. package/dist/apps/shared/components/calendar/TimeGridView.d.ts +1 -1
  366. package/dist/apps/shared/components/calendar/TimeGridView.js +2 -2
  367. package/dist/apps/shared/components/calendar/allDay.d.ts +2 -2
  368. package/dist/apps/shared/components/calendar/allDay.js +1 -1
  369. package/dist/apps/shared/components/calendar/eventDialogFields.d.ts +2 -2
  370. package/dist/apps/shared/components/calendar/eventDialogFields.js +2 -2
  371. package/dist/apps/shared/components/calendar/eventForm.d.ts +3 -3
  372. package/dist/apps/shared/components/calendar/eventFormat.d.ts +1 -1
  373. package/dist/apps/shared/components/calendar/eventFormat.js +2 -2
  374. package/dist/apps/shared/components/calendar/findTimeGrid.d.ts +1 -1
  375. package/dist/apps/shared/components/calendar/findTimeGrid.js +1 -1
  376. package/dist/apps/shared/components/calendar/layout/CalendarShell.d.ts +1 -1
  377. package/dist/apps/shared/components/calendar/layout/CalendarShell.js +11 -9
  378. package/dist/apps/shared/components/contacts/ContactDetailPane.d.ts +1 -1
  379. package/dist/apps/shared/components/contacts/ContactDetailPane.js +2 -2
  380. package/dist/apps/shared/components/contacts/ContactForm.d.ts +2 -2
  381. package/dist/apps/shared/components/contacts/ContactForm.js +12 -8
  382. package/dist/apps/shared/components/contacts/ContactsSidebar.d.ts +1 -1
  383. package/dist/apps/shared/components/contacts/ContactsSidebar.js +7 -5
  384. package/dist/apps/shared/components/contacts/KeyChangeReview.d.ts +1 -1
  385. package/dist/apps/shared/components/contacts/KeyChangeReview.js +5 -5
  386. package/dist/apps/shared/components/contacts/contactKeys.d.ts +2 -2
  387. package/dist/apps/shared/components/contacts/contactKeys.js +2 -2
  388. package/dist/apps/shared/components/contacts/layout/ContactsShell.d.ts +1 -1
  389. package/dist/apps/shared/components/contacts/layout/ContactsShell.js +9 -7
  390. package/dist/apps/shared/components/escrow/layout/EscrowShell.js +6 -6
  391. package/dist/apps/shared/components/forms/StringListField.js +1 -1
  392. package/dist/apps/shared/components/layout/AppShell.d.ts +2 -2
  393. package/dist/apps/shared/components/layout/AppShell.js +11 -9
  394. package/dist/apps/shared/components/layout/BrandingChrome.d.ts +1 -1
  395. package/dist/apps/shared/components/layout/KeyEnrollmentGate.d.ts +1 -1
  396. package/dist/apps/shared/components/layout/KeyEnrollmentGate.js +9 -9
  397. package/dist/apps/shared/components/layout/MailboxProvisioning.js +8 -6
  398. package/dist/apps/shared/components/layout/RecoveryCodeUnlock.d.ts +1 -1
  399. package/dist/apps/shared/components/layout/RecoveryCodeUnlock.js +9 -9
  400. package/dist/apps/shared/components/layout/UnlockPromptProvider.d.ts +2 -2
  401. package/dist/apps/shared/components/layout/UnlockPromptProvider.js +5 -5
  402. package/dist/apps/shared/components/layout/UserMenu.js +6 -4
  403. package/dist/apps/shared/components/mail/ConversationList.d.ts +2 -2
  404. package/dist/apps/shared/components/mail/ConversationList.js +23 -8
  405. package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +3 -3
  406. package/dist/apps/shared/components/mail/ConversationThreadPane.js +19 -13
  407. package/dist/apps/shared/components/mail/InviteCard.js +10 -8
  408. package/dist/apps/shared/components/mail/LazyReadingPane.js +2 -2
  409. package/dist/apps/shared/components/mail/MailAddress.d.ts +1 -1
  410. package/dist/apps/shared/components/mail/MailAddress.js +1 -1
  411. package/dist/apps/shared/components/mail/MailListToolbar.d.ts +2 -2
  412. package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +2 -2
  413. package/dist/apps/shared/components/mail/MenuButton.js +1 -1
  414. package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +3 -3
  415. package/dist/apps/shared/components/mail/MessageDetailPane.js +61 -46
  416. package/dist/apps/shared/components/mail/MoveToFolderDialog.d.ts +1 -1
  417. package/dist/apps/shared/components/mail/MoveToFolderDialog.js +8 -6
  418. package/dist/apps/shared/components/mail/OutboxRowStatus.d.ts +1 -1
  419. package/dist/apps/shared/components/mail/PermanentDeleteDialog.js +2 -2
  420. package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +10 -1
  421. package/dist/apps/shared/components/mail/compose/ComposeContext.js +4 -2
  422. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +34 -30
  423. package/dist/apps/shared/components/mail/compose/ComposeWindowPlaceholder.js +4 -4
  424. package/dist/apps/shared/components/mail/compose/EmojiPicker.js +2 -2
  425. package/dist/apps/shared/components/mail/compose/GifPicker.js +3 -3
  426. package/dist/apps/shared/components/mail/compose/RecipientInput.d.ts +1 -1
  427. package/dist/apps/shared/components/mail/compose/RecipientInput.js +1 -1
  428. package/dist/apps/shared/components/mail/compose/ScheduleSendPicker.js +1 -1
  429. package/dist/apps/shared/components/mail/compose/encryptionRequirement.d.ts +2 -2
  430. package/dist/apps/shared/components/mail/compose/encryptionRequirement.js +1 -1
  431. package/dist/apps/shared/components/mail/compose/quotedBody.d.ts +3 -3
  432. package/dist/apps/shared/components/mail/compose/quotedBody.js +3 -3
  433. package/dist/apps/shared/components/mail/compose/recipients.d.ts +1 -1
  434. package/dist/apps/shared/components/mail/invite/InviteRowChip.d.ts +3 -3
  435. package/dist/apps/shared/components/mail/invite/InviteRowChip.js +7 -9
  436. package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.d.ts +2 -2
  437. package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.js +11 -9
  438. package/dist/apps/shared/components/mail/invite/InviteTimeline.d.ts +1 -1
  439. package/dist/apps/shared/components/mail/invite/ProposeTimeForm.d.ts +1 -1
  440. package/dist/apps/shared/components/mail/invite/ProposeTimeForm.js +1 -1
  441. package/dist/apps/shared/components/mail/invite/inviteFormat.d.ts +2 -2
  442. package/dist/apps/shared/components/mail/invite/inviteStore.d.ts +9 -3
  443. package/dist/apps/shared/components/mail/invite/inviteStore.js +13 -6
  444. package/dist/apps/shared/components/mail/labelMenu.d.ts +1 -1
  445. package/dist/apps/shared/components/mail/labelMenu.js +9 -7
  446. package/dist/apps/shared/components/mail/layout/MailShell.d.ts +1 -1
  447. package/dist/apps/shared/components/mail/layout/MailShell.js +3 -3
  448. package/dist/apps/shared/components/mail/listPreferences.d.ts +2 -2
  449. package/dist/apps/shared/components/mail/listPreferences.js +1 -1
  450. package/dist/apps/shared/components/mail/pinnedSigners.d.ts +12 -5
  451. package/dist/apps/shared/components/mail/pinnedSigners.js +37 -18
  452. package/dist/apps/shared/components/mail/reading/EncryptedBody.js +2 -2
  453. package/dist/apps/shared/components/mail/reading/MessageBody.d.ts +2 -2
  454. package/dist/apps/shared/components/mail/reading/MessageBody.js +4 -4
  455. package/dist/apps/shared/components/mail/reading/MessageCard.d.ts +1 -1
  456. package/dist/apps/shared/components/mail/reading/MessageCard.js +2 -2
  457. package/dist/apps/shared/components/mail/reading/MessageSourceDialog.js +3 -3
  458. package/dist/apps/shared/components/mail/reading/PendingMessageCard.js +1 -1
  459. package/dist/apps/shared/components/mail/reading/bodyContent.d.ts +2 -2
  460. package/dist/apps/shared/components/mail/reading/bodyContent.js +2 -2
  461. package/dist/apps/shared/components/mail/reading/bodyHtml.js +1 -1
  462. package/dist/apps/shared/components/mail/reading/conversationPrint.d.ts +15 -0
  463. package/dist/apps/shared/components/mail/reading/conversationPrint.js +69 -0
  464. package/dist/apps/shared/components/mail/reading/messageExport.js +1 -1
  465. package/dist/apps/shared/components/mail/reading/printMessage.d.ts +9 -3
  466. package/dist/apps/shared/components/mail/reading/printMessage.js +33 -6
  467. package/dist/apps/shared/components/mail/reading/useMessageActions.d.ts +1 -1
  468. package/dist/apps/shared/components/mail/reading/useMessageActions.js +18 -16
  469. package/dist/apps/shared/components/mail/unreadStyle.d.ts +1 -1
  470. package/dist/apps/shared/components/mail/verificationSeals.d.ts +27 -6
  471. package/dist/apps/shared/components/mail/verificationSeals.js +15 -11
  472. package/dist/apps/shared/components/mail/writableMailboxes.d.ts +8 -3
  473. package/dist/apps/shared/components/mail/writableMailboxes.js +12 -6
  474. package/dist/apps/shared/components/rules/RuleBuilder.js +1 -1
  475. package/dist/apps/shared/components/settings/SigningCertificateCard.d.ts +1 -1
  476. package/dist/apps/shared/components/settings/SigningCertificateCard.js +3 -3
  477. package/dist/apps/shared/components/settings/layout/SettingsShell.d.ts +1 -1
  478. package/dist/apps/shared/components/settings/layout/SettingsShell.js +8 -6
  479. package/dist/apps/shared/components/sharing/PrincipalListField.d.ts +1 -1
  480. package/dist/apps/shared/components/sharing/PrincipalPicker.d.ts +1 -1
  481. package/dist/apps/shared/components/sharing/PrincipalPicker.js +1 -1
  482. package/dist/apps/shared/components/sharing/PrincipalResolver.d.ts +1 -1
  483. package/dist/apps/shared/components/sharing/PrincipalResolver.js +3 -3
  484. package/dist/apps/shared/components/tasks/TasksSidebar.d.ts +1 -1
  485. package/dist/apps/shared/components/tasks/TasksSidebar.js +7 -5
  486. package/dist/apps/shared/components/tasks/layout/TasksShell.d.ts +1 -1
  487. package/dist/apps/shared/components/tasks/layout/TasksShell.js +9 -7
  488. package/dist/apps/shared/keyboard/ShortcutsDialog.js +1 -1
  489. package/dist/apps/shared/keyboard/keymap.d.ts +6 -0
  490. package/dist/apps/shared/keyboard/keymap.js +1 -0
  491. package/dist/apps/shared/mail/decryptedMessages.d.ts +27 -0
  492. package/dist/apps/shared/mail/decryptedMessages.js +97 -0
  493. package/dist/apps/shared/mail/findWellKnownFolderUid.d.ts +5 -3
  494. package/dist/apps/shared/mail/findWellKnownFolderUid.js +5 -4
  495. package/dist/apps/shared/mail/folderCounts.d.ts +1 -1
  496. package/dist/apps/shared/mail/folderCounts.js +6 -4
  497. package/dist/apps/shared/mail/folderOfType.d.ts +3 -2
  498. package/dist/apps/shared/mail/folderOfType.js +4 -4
  499. package/dist/apps/shared/mail/folderTree.d.ts +1 -1
  500. package/dist/apps/shared/mail/listSnapshots.d.ts +2 -2
  501. package/dist/apps/shared/mail/messageReadState.d.ts +4 -3
  502. package/dist/apps/shared/mail/messageReadState.js +5 -5
  503. package/dist/apps/shared/mail/newMailNotifications.d.ts +1 -1
  504. package/dist/apps/shared/mail/newMailNotifications.js +1 -1
  505. package/dist/apps/shared/mail/outbox/composeBridge.d.ts +2 -2
  506. package/dist/apps/shared/mail/outbox/outboxState.d.ts +1 -1
  507. package/dist/apps/shared/mail/outbox/outgoingReplies.d.ts +2 -2
  508. package/dist/apps/shared/mail/outbox/sendDecision.d.ts +2 -2
  509. package/dist/apps/shared/mail/outbox/sendDecision.js +1 -1
  510. package/dist/apps/shared/mail/outbox/sendJob.d.ts +10 -6
  511. package/dist/apps/shared/mail/outbox/sendJob.js +39 -35
  512. package/dist/apps/shared/mail/outbox/sendOutcomes.d.ts +6 -3
  513. package/dist/apps/shared/mail/outbox/sendOutcomes.js +19 -15
  514. package/dist/apps/shared/mail/outbox/useOutboxStatus.js +5 -3
  515. package/dist/apps/shared/mail/permanentDelete.d.ts +4 -3
  516. package/dist/apps/shared/mail/permanentDelete.js +8 -8
  517. package/dist/apps/shared/mail/primaryMailbox.d.ts +1 -1
  518. package/dist/apps/shared/mail/primaryMailbox.js +1 -1
  519. package/dist/apps/shared/mail/reportNotices.d.ts +1 -1
  520. package/dist/apps/shared/mail/senderBlocking.d.ts +5 -4
  521. package/dist/apps/shared/mail/senderBlocking.js +19 -16
  522. package/dist/apps/shared/mail/useMailConnection.d.ts +1 -1
  523. package/dist/apps/shared/mail/useMailConnection.js +12 -10
  524. package/dist/apps/shared/mail/useMailLiveUpdates.d.ts +2 -2
  525. package/dist/apps/shared/mail/useMailLiveUpdates.js +2 -2
  526. package/dist/apps/shared/mail/useMailboxUpdateAccess.d.ts +3 -2
  527. package/dist/apps/shared/mail/useMailboxUpdateAccess.js +31 -10
  528. package/dist/apps/shared/mail/useMarkMessageRead.d.ts +1 -1
  529. package/dist/apps/shared/mail/useMarkMessageRead.js +5 -3
  530. package/dist/apps/shared/mail/useNewMailNotifications.d.ts +1 -1
  531. package/dist/apps/shared/mail/usePermanentDelete.d.ts +1 -1
  532. package/dist/apps/shared/mail/usePermanentDelete.js +4 -2
  533. package/dist/apps/shared/navigation/pageTitle.d.ts +1 -1
  534. package/dist/apps/shared/notifications/NotificationCenter.js +1 -1
  535. package/dist/apps/shared/notifications/NotificationHistoryDialog.js +2 -2
  536. package/dist/apps/shared/notifications/apiErrors.js +2 -2
  537. package/dist/apps/shared/notifications/pushStatus.js +1 -1
  538. package/dist/apps/shared/notifications/systemErrors.js +1 -1
  539. package/dist/apps/shared/search/LocalIndexLifecycle.d.ts +2 -2
  540. package/dist/apps/shared/search/LocalIndexLifecycle.js +15 -10
  541. package/dist/apps/shared/search/crossMailboxSearch.d.ts +1 -1
  542. package/dist/apps/shared/search/crossMailboxSearch.js +2 -2
  543. package/dist/apps/shared/search/localIndexBuilder.d.ts +4 -3
  544. package/dist/apps/shared/search/localIndexBuilder.js +15 -12
  545. package/dist/apps/shared/search/localIndexKey.js +1 -1
  546. package/dist/apps/shared/search/localIndexRpcClient.d.ts +43 -31
  547. package/dist/apps/shared/search/localIndexRpcClient.js +113 -20
  548. package/dist/apps/shared/search/localIndexTransport.d.ts +77 -0
  549. package/dist/apps/shared/search/localIndexTransport.js +1 -0
  550. package/dist/apps/shared/search/localIndexWorker.d.ts +1 -1
  551. package/dist/apps/shared/search/searchTier2.d.ts +3 -3
  552. package/dist/apps/shared/signing/enrollmentTracker.d.ts +1 -1
  553. package/dist/apps/shared/signing/enrollmentTracker.js +3 -3
  554. package/dist/apps/shared/signing/enrollmentView.d.ts +1 -1
  555. package/dist/apps/shared/signing/signingInfo.d.ts +1 -1
  556. package/dist/apps/shared/signing/signingInfo.js +1 -1
  557. package/dist/apps/shared/signing/useSigningEnrollmentWatcher.d.ts +1 -1
  558. package/dist/apps/shared/signing/useSigningEnrollmentWatcher.js +5 -3
  559. package/dist/apps/shared/styles/app.css +14 -23
  560. package/dist/apps/www/_layout.d.ts +1 -1
  561. package/dist/apps/www/_layout.js +1 -1
  562. package/dist/apps/www/calendar/index.d.ts +1 -1
  563. package/dist/apps/www/calendar/index.js +20 -18
  564. package/dist/apps/www/contacts/[uid].d.ts +1 -1
  565. package/dist/apps/www/contacts/[uid].js +8 -6
  566. package/dist/apps/www/contacts/index.d.ts +1 -1
  567. package/dist/apps/www/contacts/index.js +19 -17
  568. package/dist/apps/www/index.d.ts +1 -1
  569. package/dist/apps/www/index.js +64 -50
  570. package/dist/apps/www/messages/[uid].d.ts +1 -1
  571. package/dist/apps/www/messages/[uid].js +11 -9
  572. package/dist/apps/www/settings/appearance/index.d.ts +1 -1
  573. package/dist/apps/www/settings/auto-reply/index.d.ts +1 -1
  574. package/dist/apps/www/settings/auto-reply/index.js +6 -4
  575. package/dist/apps/www/settings/blocked-senders/index.d.ts +1 -1
  576. package/dist/apps/www/settings/blocked-senders/index.js +6 -4
  577. package/dist/apps/www/settings/encryption/index.d.ts +1 -1
  578. package/dist/apps/www/settings/encryption/index.js +31 -29
  579. package/dist/apps/www/settings/filters/[uid].d.ts +1 -1
  580. package/dist/apps/www/settings/filters/[uid].js +11 -9
  581. package/dist/apps/www/settings/filters/_mailFilterRuleConfig.d.ts +2 -2
  582. package/dist/apps/www/settings/filters/index.d.ts +1 -1
  583. package/dist/apps/www/settings/filters/index.js +4 -4
  584. package/dist/apps/www/settings/filters/new/index.d.ts +1 -1
  585. package/dist/apps/www/settings/filters/new/index.js +10 -8
  586. package/dist/apps/www/settings/labels/index.d.ts +1 -1
  587. package/dist/apps/www/settings/labels/index.js +12 -10
  588. package/dist/apps/www/settings/privacy/index.d.ts +1 -1
  589. package/dist/apps/www/settings/privacy/index.js +18 -14
  590. package/dist/apps/www/settings/profile/index.d.ts +1 -1
  591. package/dist/apps/www/settings/profile/index.js +7 -5
  592. package/dist/apps/www/settings/read-receipts/index.d.ts +1 -1
  593. package/dist/apps/www/settings/read-receipts/index.js +5 -3
  594. package/dist/apps/www/settings/sharing/index.d.ts +1 -1
  595. package/dist/apps/www/settings/sharing/index.js +6 -6
  596. package/dist/apps/www/settings/signatures/[uid].d.ts +1 -1
  597. package/dist/apps/www/settings/signatures/[uid].js +5 -5
  598. package/dist/apps/www/settings/signatures/index.d.ts +1 -1
  599. package/dist/apps/www/settings/signatures/index.js +4 -4
  600. package/dist/apps/www/settings/signatures/new/index.d.ts +1 -1
  601. package/dist/apps/www/settings/signatures/new/index.js +4 -4
  602. package/dist/apps/www/settings/signatures/signatureDefaults.d.ts +1 -1
  603. package/dist/apps/www/settings/signatures/signatureDefaults.js +1 -1
  604. package/dist/apps/www/tasks/index.d.ts +1 -1
  605. package/dist/apps/www/tasks/index.js +17 -15
  606. package/dist/lib/admin/auditLogApi.d.ts +32 -0
  607. package/dist/lib/admin/auditLogApi.js +27 -0
  608. package/dist/lib/admin/distributionListsApi.d.ts +47 -0
  609. package/dist/lib/admin/distributionListsApi.js +34 -0
  610. package/dist/lib/admin/domainsApi.d.ts +75 -0
  611. package/dist/lib/admin/domainsApi.js +44 -0
  612. package/dist/lib/admin/escrowAccessRequestsApi.d.ts +79 -0
  613. package/dist/lib/admin/escrowAccessRequestsApi.js +46 -0
  614. package/dist/lib/admin/escrowAuditLogApi.d.ts +66 -0
  615. package/dist/lib/admin/escrowAuditLogApi.js +31 -0
  616. package/dist/lib/admin/escrowScopesApi.d.ts +78 -0
  617. package/dist/lib/admin/escrowScopesApi.js +50 -0
  618. package/dist/lib/admin/leftoverMailboxApi.d.ts +73 -0
  619. package/dist/lib/admin/leftoverMailboxApi.js +67 -0
  620. package/dist/lib/admin/mailboxPolicyApi.d.ts +27 -0
  621. package/dist/lib/admin/mailboxPolicyApi.js +21 -0
  622. package/dist/lib/admin/matterExportApi.d.ts +40 -0
  623. package/dist/lib/admin/matterExportApi.js +39 -0
  624. package/dist/lib/admin/matterSearchApi.d.ts +20 -0
  625. package/dist/lib/admin/matterSearchApi.js +27 -0
  626. package/dist/lib/admin/mattersApi.d.ts +56 -0
  627. package/dist/lib/admin/mattersApi.js +40 -0
  628. package/dist/lib/admin/pluginsApi.d.ts +265 -0
  629. package/dist/lib/admin/pluginsApi.js +102 -0
  630. package/dist/lib/admin/retentionPolicyApi.d.ts +32 -0
  631. package/dist/lib/admin/retentionPolicyApi.js +29 -0
  632. package/dist/lib/admin/setupApi.d.ts +23 -0
  633. package/dist/lib/admin/setupApi.js +26 -0
  634. package/dist/lib/admin/transportRulesApi.d.ts +66 -0
  635. package/dist/lib/admin/transportRulesApi.js +43 -0
  636. package/dist/lib/appearance/preferencesApi.d.ts +128 -0
  637. package/dist/lib/appearance/preferencesApi.js +257 -0
  638. package/dist/lib/auth/profileApi.d.ts +33 -0
  639. package/dist/lib/auth/profileApi.js +52 -0
  640. package/dist/lib/auth/session.d.ts +70 -0
  641. package/dist/lib/auth/session.js +210 -0
  642. package/dist/lib/branding/brandingApi.d.ts +47 -0
  643. package/dist/lib/branding/brandingApi.js +61 -0
  644. package/dist/lib/branding/useBranding.d.ts +23 -0
  645. package/dist/lib/branding/useBranding.js +65 -0
  646. package/dist/lib/calendar/calendarApi.d.ts +230 -0
  647. package/dist/lib/calendar/calendarApi.js +106 -0
  648. package/dist/lib/calendar/calendarColors.d.ts +18 -0
  649. package/dist/lib/calendar/calendarColors.js +39 -0
  650. package/dist/lib/calendar/calendarDragIds.d.ts +42 -0
  651. package/dist/lib/calendar/calendarDragIds.js +92 -0
  652. package/dist/lib/calendar/calendarMutations.d.ts +68 -0
  653. package/dist/lib/calendar/calendarMutations.js +190 -0
  654. package/dist/lib/calendar/eventDescription.d.ts +43 -0
  655. package/dist/lib/calendar/eventDescription.js +195 -0
  656. package/dist/lib/calendar/freeBusyApi.d.ts +100 -0
  657. package/dist/lib/calendar/freeBusyApi.js +119 -0
  658. package/dist/lib/calendar/inviteApi.d.ts +121 -0
  659. package/dist/lib/calendar/inviteApi.js +54 -0
  660. package/dist/lib/calendar/recurrence.d.ts +60 -0
  661. package/dist/lib/calendar/recurrence.js +225 -0
  662. package/dist/lib/components/avatar/ContactAvatar.d.ts +8 -0
  663. package/dist/lib/components/avatar/ContactAvatar.js +26 -0
  664. package/dist/lib/components/buttons/Button.d.ts +9 -0
  665. package/dist/lib/components/buttons/Button.js +14 -0
  666. package/dist/lib/components/buttons/CopyButton.d.ts +18 -0
  667. package/dist/lib/components/buttons/CopyButton.js +14 -0
  668. package/dist/lib/components/feedback/Alert.d.ts +4 -0
  669. package/dist/lib/components/feedback/Alert.js +4 -0
  670. package/dist/lib/components/feedback/Skeleton.d.ts +21 -0
  671. package/dist/lib/components/feedback/Skeleton.js +14 -0
  672. package/dist/lib/components/forms/FormField.d.ts +8 -0
  673. package/dist/lib/components/forms/FormField.js +5 -0
  674. package/dist/lib/components/navigation/BottomTabBar.d.ts +27 -0
  675. package/dist/lib/components/navigation/BottomTabBar.js +32 -0
  676. package/dist/lib/components/overlays/Drawer.d.ts +20 -0
  677. package/dist/lib/components/overlays/Drawer.js +27 -0
  678. package/dist/lib/components/overlays/Modal.d.ts +17 -0
  679. package/dist/lib/components/overlays/Modal.js +25 -0
  680. package/dist/lib/components/overlays/PopoverPortal.d.ts +23 -0
  681. package/dist/lib/components/overlays/PopoverPortal.js +53 -0
  682. package/dist/lib/components/overlays/overlayStack.d.ts +31 -0
  683. package/dist/lib/components/overlays/overlayStack.js +143 -0
  684. package/dist/lib/components/pickers/MiniDatePicker.d.ts +13 -0
  685. package/dist/lib/components/pickers/MiniDatePicker.js +42 -0
  686. package/dist/lib/contacts/contactsApi.d.ts +174 -0
  687. package/dist/lib/contacts/contactsApi.js +139 -0
  688. package/dist/lib/contacts/vcard.d.ts +23 -0
  689. package/dist/lib/contacts/vcard.js +179 -0
  690. package/dist/lib/crypto/composeSecurity.d.ts +67 -0
  691. package/dist/lib/crypto/composeSecurity.js +93 -0
  692. package/dist/lib/crypto/encoding.d.ts +9 -0
  693. package/dist/lib/crypto/encoding.js +32 -0
  694. package/dist/lib/crypto/escrowKeys.d.ts +25 -0
  695. package/dist/lib/crypto/escrowKeys.js +59 -0
  696. package/dist/lib/crypto/idleTimeout.d.ts +16 -0
  697. package/dist/lib/crypto/idleTimeout.js +47 -0
  698. package/dist/lib/crypto/keySession.d.ts +159 -0
  699. package/dist/lib/crypto/keySession.js +367 -0
  700. package/dist/lib/crypto/keys.d.ts +50 -0
  701. package/dist/lib/crypto/keys.js +89 -0
  702. package/dist/lib/crypto/keyvaultApi.d.ts +394 -0
  703. package/dist/lib/crypto/keyvaultApi.js +350 -0
  704. package/dist/lib/crypto/masterKey.d.ts +59 -0
  705. package/dist/lib/crypto/masterKey.js +104 -0
  706. package/dist/lib/crypto/masterKeyWraps.d.ts +108 -0
  707. package/dist/lib/crypto/masterKeyWraps.js +228 -0
  708. package/dist/lib/crypto/messageSecurity.d.ts +248 -0
  709. package/dist/lib/crypto/messageSecurity.js +367 -0
  710. package/dist/lib/crypto/mime.d.ts +143 -0
  711. package/dist/lib/crypto/mime.js +504 -0
  712. package/dist/lib/crypto/passkeyUnlock.d.ts +20 -0
  713. package/dist/lib/crypto/passkeyUnlock.js +79 -0
  714. package/dist/lib/crypto/passwordUnlock.d.ts +39 -0
  715. package/dist/lib/crypto/passwordUnlock.js +73 -0
  716. package/dist/lib/crypto/recoveryCode.d.ts +28 -0
  717. package/dist/lib/crypto/recoveryCode.js +86 -0
  718. package/dist/lib/crypto/signingProviderApi.d.ts +95 -0
  719. package/dist/lib/crypto/signingProviderApi.js +60 -0
  720. package/dist/lib/crypto/smime.d.ts +128 -0
  721. package/dist/lib/crypto/smime.js +402 -0
  722. package/dist/lib/crypto/smimeMessage.d.ts +132 -0
  723. package/dist/lib/crypto/smimeMessage.js +341 -0
  724. package/dist/lib/crypto/useIdleKeyTimeout.d.ts +10 -0
  725. package/dist/lib/crypto/useIdleKeyTimeout.js +163 -0
  726. package/dist/lib/crypto/verificationSeal.d.ts +56 -0
  727. package/dist/lib/crypto/verificationSeal.js +220 -0
  728. package/dist/lib/mail/compose/composeQuoting.d.ts +88 -0
  729. package/dist/lib/mail/compose/composeQuoting.js +204 -0
  730. package/dist/lib/mail/compose/emojiData.d.ts +9 -0
  731. package/dist/lib/mail/compose/emojiData.js +18 -0
  732. package/dist/lib/mail/compose/giphyApi.d.ts +17 -0
  733. package/dist/lib/mail/compose/giphyApi.js +20 -0
  734. package/dist/lib/mail/conversationsApi.d.ts +80 -0
  735. package/dist/lib/mail/conversationsApi.js +44 -0
  736. package/dist/lib/mail/dataExportApi.d.ts +50 -0
  737. package/dist/lib/mail/dataExportApi.js +40 -0
  738. package/dist/lib/mail/directoryApi.d.ts +49 -0
  739. package/dist/lib/mail/directoryApi.js +101 -0
  740. package/dist/lib/mail/erasureRequestApi.d.ts +45 -0
  741. package/dist/lib/mail/erasureRequestApi.js +43 -0
  742. package/dist/lib/mail/flaggedMessages.d.ts +22 -0
  743. package/dist/lib/mail/flaggedMessages.js +73 -0
  744. package/dist/lib/mail/focusedInboxOverridesApi.d.ts +37 -0
  745. package/dist/lib/mail/focusedInboxOverridesApi.js +34 -0
  746. package/dist/lib/mail/labelsApi.d.ts +47 -0
  747. package/dist/lib/mail/labelsApi.js +38 -0
  748. package/dist/lib/mail/mailAddress.d.ts +27 -0
  749. package/dist/lib/mail/mailAddress.js +54 -0
  750. package/dist/lib/mail/mailApi.d.ts +850 -0
  751. package/dist/lib/mail/mailApi.js +602 -0
  752. package/dist/lib/mail/mailDetailHooks.d.ts +10 -0
  753. package/dist/lib/mail/mailDetailHooks.js +53 -0
  754. package/dist/lib/mail/mailFilterRulesApi.d.ts +76 -0
  755. package/dist/lib/mail/mailFilterRulesApi.js +45 -0
  756. package/dist/lib/mail/mailSignaturesApi.d.ts +49 -0
  757. package/dist/lib/mail/mailSignaturesApi.js +42 -0
  758. package/dist/lib/mail/mailboxAccessApi.d.ts +74 -0
  759. package/dist/lib/mail/mailboxAccessApi.js +56 -0
  760. package/dist/lib/mail/mailboxImportApi.d.ts +53 -0
  761. package/dist/lib/mail/mailboxImportApi.js +51 -0
  762. package/dist/lib/mail/messageBodySanitizer.d.ts +16 -0
  763. package/dist/lib/mail/messageBodySanitizer.js +118 -0
  764. package/dist/lib/mail/pushClient.d.ts +106 -0
  765. package/dist/lib/mail/pushClient.js +317 -0
  766. package/dist/lib/mail/sendEvents.d.ts +33 -0
  767. package/dist/lib/mail/sendEvents.js +44 -0
  768. package/dist/lib/mail/sendFailure.d.ts +16 -0
  769. package/dist/lib/mail/sendFailure.js +86 -0
  770. package/dist/lib/mail/senderListsApi.d.ts +69 -0
  771. package/dist/lib/mail/senderListsApi.js +126 -0
  772. package/dist/lib/search/queryGrammar.d.ts +51 -0
  773. package/dist/lib/search/queryGrammar.js +111 -0
  774. package/dist/lib/search/searchApi.d.ts +100 -0
  775. package/dist/lib/search/searchApi.js +107 -0
  776. package/dist/lib/search/searchScoring.d.ts +34 -0
  777. package/dist/lib/search/searchScoring.js +44 -0
  778. package/dist/lib/search/searchTier3.d.ts +64 -0
  779. package/dist/lib/search/searchTier3.js +335 -0
  780. package/dist/lib/tasks/tasksApi.d.ts +85 -0
  781. package/dist/lib/tasks/tasksApi.js +55 -0
  782. package/dist/lib/util/api.d.ts +160 -0
  783. package/dist/lib/util/api.js +251 -0
  784. package/dist/lib/util/apiClientContext.d.ts +7 -0
  785. package/dist/lib/util/apiClientContext.js +32 -0
  786. package/dist/lib/util/apiQuery.d.ts +32 -0
  787. package/dist/lib/util/apiQuery.js +42 -0
  788. package/dist/lib/util/clipboard.d.ts +7 -0
  789. package/dist/lib/util/clipboard.js +56 -0
  790. package/dist/lib/util/dateInput.d.ts +6 -0
  791. package/dist/lib/util/dateInput.js +14 -0
  792. package/dist/lib/util/timeZone.d.ts +12 -0
  793. package/dist/lib/util/timeZone.js +32 -0
  794. package/dist/lib/util/useCopyToClipboard.d.ts +12 -0
  795. package/dist/lib/util/useCopyToClipboard.js +34 -0
  796. package/dist/lib/util/useIsMobile.d.ts +10 -0
  797. package/dist/lib/util/useIsMobile.js +29 -0
  798. package/dist/lib/videoconf/videoMeetingsApi.d.ts +116 -0
  799. package/dist/lib/videoconf/videoMeetingsApi.js +49 -0
  800. package/lib/admin/auditLogApi.ts +48 -0
  801. package/lib/admin/distributionListsApi.ts +77 -0
  802. package/lib/admin/domainsApi.ts +113 -0
  803. package/lib/admin/escrowAccessRequestsApi.ts +110 -0
  804. package/lib/admin/escrowAuditLogApi.ts +101 -0
  805. package/lib/admin/escrowScopesApi.ts +112 -0
  806. package/lib/admin/leftoverMailboxApi.ts +120 -0
  807. package/lib/admin/mailboxPolicyApi.ts +38 -0
  808. package/lib/admin/matterExportApi.ts +62 -0
  809. package/lib/admin/matterSearchApi.ts +35 -0
  810. package/lib/admin/mattersApi.ts +86 -0
  811. package/lib/admin/pluginsApi.ts +339 -0
  812. package/lib/admin/retentionPolicyApi.ts +46 -0
  813. package/lib/admin/setupApi.ts +40 -0
  814. package/lib/admin/transportRulesApi.ts +106 -0
  815. package/lib/appearance/preferencesApi.ts +335 -0
  816. package/lib/auth/profileApi.ts +77 -0
  817. package/lib/auth/session.ts +238 -0
  818. package/lib/branding/brandingApi.ts +97 -0
  819. package/lib/branding/useBranding.ts +81 -0
  820. package/lib/calendar/calendarApi.ts +309 -0
  821. package/lib/calendar/calendarColors.ts +45 -0
  822. package/lib/calendar/calendarDragIds.ts +112 -0
  823. package/lib/calendar/calendarMutations.ts +236 -0
  824. package/lib/calendar/eventDescription.ts +211 -0
  825. package/lib/calendar/freeBusyApi.ts +197 -0
  826. package/lib/calendar/inviteApi.ts +154 -0
  827. package/lib/calendar/recurrence.ts +285 -0
  828. package/lib/components/avatar/ContactAvatar.tsx +47 -0
  829. package/lib/components/buttons/Button.tsx +40 -0
  830. package/lib/components/buttons/CopyButton.tsx +45 -0
  831. package/lib/components/feedback/Alert.tsx +13 -0
  832. package/lib/components/feedback/Skeleton.tsx +38 -0
  833. package/lib/components/forms/FormField.tsx +23 -0
  834. package/lib/components/navigation/BottomTabBar.tsx +66 -0
  835. package/lib/components/overlays/Drawer.tsx +72 -0
  836. package/lib/components/overlays/Modal.tsx +64 -0
  837. package/lib/components/overlays/PopoverPortal.tsx +74 -0
  838. package/lib/components/overlays/overlayStack.ts +165 -0
  839. package/lib/components/pickers/MiniDatePicker.tsx +90 -0
  840. package/lib/contacts/contactsApi.ts +289 -0
  841. package/lib/contacts/vcard.ts +197 -0
  842. package/lib/crypto/composeSecurity.ts +140 -0
  843. package/lib/crypto/encoding.ts +36 -0
  844. package/lib/crypto/escrowKeys.ts +74 -0
  845. package/lib/crypto/idleTimeout.ts +49 -0
  846. package/lib/crypto/keySession.ts +483 -0
  847. package/lib/crypto/keys.ts +105 -0
  848. package/lib/crypto/keyvaultApi.ts +674 -0
  849. package/lib/crypto/masterKey.ts +134 -0
  850. package/lib/crypto/masterKeyWraps.ts +269 -0
  851. package/lib/crypto/messageSecurity.ts +600 -0
  852. package/lib/crypto/mime.ts +568 -0
  853. package/lib/crypto/passkeyUnlock.ts +103 -0
  854. package/lib/crypto/passwordUnlock.ts +98 -0
  855. package/lib/crypto/recoveryCode.ts +93 -0
  856. package/lib/crypto/signingProviderApi.ts +135 -0
  857. package/lib/crypto/smime.ts +459 -0
  858. package/lib/crypto/smimeMessage.ts +491 -0
  859. package/lib/crypto/useIdleKeyTimeout.ts +176 -0
  860. package/lib/crypto/verificationSeal.ts +288 -0
  861. package/lib/mail/compose/composeQuoting.ts +243 -0
  862. package/lib/mail/compose/emojiData.ts +34 -0
  863. package/lib/mail/compose/giphyApi.ts +31 -0
  864. package/lib/mail/conversationsApi.ts +123 -0
  865. package/lib/mail/dataExportApi.ts +73 -0
  866. package/lib/mail/directoryApi.ts +161 -0
  867. package/lib/mail/erasureRequestApi.ts +71 -0
  868. package/lib/mail/flaggedMessages.ts +80 -0
  869. package/lib/mail/focusedInboxOverridesApi.ts +64 -0
  870. package/lib/mail/labelsApi.ts +71 -0
  871. package/lib/mail/mailAddress.ts +76 -0
  872. package/lib/mail/mailApi.ts +1286 -0
  873. package/lib/mail/mailDetailHooks.ts +57 -0
  874. package/lib/mail/mailFilterRulesApi.ts +116 -0
  875. package/lib/mail/mailSignaturesApi.ts +84 -0
  876. package/lib/mail/mailboxAccessApi.ts +106 -0
  877. package/lib/mail/mailboxImportApi.ts +87 -0
  878. package/lib/mail/messageBodySanitizer.ts +129 -0
  879. package/lib/mail/pushClient.ts +375 -0
  880. package/lib/mail/sendEvents.ts +72 -0
  881. package/lib/mail/sendFailure.ts +98 -0
  882. package/lib/mail/senderListsApi.ts +161 -0
  883. package/lib/search/queryGrammar.ts +179 -0
  884. package/lib/search/searchApi.ts +199 -0
  885. package/lib/search/searchScoring.ts +46 -0
  886. package/lib/search/searchTier3.ts +406 -0
  887. package/lib/tasks/tasksApi.ts +128 -0
  888. package/lib/util/api.ts +318 -0
  889. package/lib/util/apiClientContext.ts +35 -0
  890. package/lib/util/apiQuery.ts +61 -0
  891. package/lib/util/clipboard.ts +55 -0
  892. package/lib/util/dateInput.ts +15 -0
  893. package/lib/util/timeZone.ts +33 -0
  894. package/lib/util/useCopyToClipboard.ts +48 -0
  895. package/lib/util/useIsMobile.ts +34 -0
  896. package/lib/videoconf/videoMeetingsApi.ts +144 -0
  897. package/package.json +10 -4
@@ -0,0 +1,220 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * Verification seals: a client-side record that a message's signature verified when it was first opened, so later key
7
+ * events (a signer key replaced beyond the retained previous keys, a deleted contact, expiry, a later compromise
8
+ * revocation) don't make it look untrusted. See `messageSecurity.ts`'s `evaluateMessageSecurityWithSeal()` for how a
9
+ * seal is used.
10
+ *
11
+ * A seal is an HMAC-SHA256 over the verification result, keyed by a per-mailbox key HKDF-derived from the unlocked
12
+ * master key - so the server, which stores it as the opaque `Message.verificationSeal` (`mailApi.ts`'s
13
+ * `setMessageVerificationSeal()`), can't forge or alter one. The seal key is derived on each call (the same way
14
+ * web-client's local search index key is: `hkdfDerive()` with a fixed salt and a mailbox-bound label), imported as a
15
+ * non-extractable `CryptoKey`, its raw bytes zeroed at once, and never cached or persisted - there is nothing to destroy
16
+ * beyond the master key `keySession.ts`'s `destroyUnlockedKeys()` already zeroes. A destroyed `UnlockedKeys` object
17
+ * throws `KeysLockedError` (checked on entry and again after the derivation awaits).
18
+ *
19
+ * **Format (v1).** `v1.<base64url(JSON payload)>.<base64url(32-byte HMAC-SHA256 tag)>`, where the payload is
20
+ * `{ "v": 1, "mb": mailboxUid, "id": messageUid, "g": masterKeyGeneration, "h": rawSha256, "fp": signerFingerprint,
21
+ * "st": state, "t": verifiedAt }` (`h`/`fp` lowercased hex). The tag is not computed over the JSON text: it covers a canonical encoding of the fields
22
+ * (see `canonicalBytes()`), so the JSON's own formatting carries no meaning. Every character is in restapi's allowed
23
+ * `[A-Za-z0-9+/=_.:-]`, and a seal is at most `MAX_VERIFICATION_SEAL_LENGTH` (2048) characters.
24
+ *
25
+ * **Master key rotation.** A seal is bound to the vault's `masterKeyGeneration` (`keyvaultApi.ts`'s
26
+ * `KeyVault.masterKeyGeneration`): the generation is MAC-covered, and `openVerificationSeal()` refuses a seal for a
27
+ * generation other than the expected one. Seals are deliberately not carried across a `rekey()`: a seal from an older
28
+ * generation never opens under the new master key (its MAC fails too), so a rotation after a suspected compromise can't
29
+ * bless seals that someone holding the old master key could have written. Such a message shows its live result until its
30
+ * next successful live verification, when `evaluateMessageSecurityWithSeal()` re-seals it lazily under the current
31
+ * generation (the server replaces a stored seal only for a newer, current generation).
32
+ */
33
+ import { fromBase64Url, toBase64Url } from "./encoding.js";
34
+ import { KeysLockedError, hkdfDerive } from "./masterKey.js";
35
+ import { binaryStringToBytes } from "./mime.js";
36
+ /** The longest seal restapi stores (`Message.verificationSeal`). */
37
+ export const MAX_VERIFICATION_SEAL_LENGTH = 2048;
38
+ /** The characters restapi allows in a seal. */
39
+ export const VERIFICATION_SEAL_CHARSET = /^[A-Za-z0-9+/=_.:-]*$/;
40
+ /** The HKDF label the seal key is derived under (suffixed with `:<mailboxUid>`). */
41
+ export const VERIFICATION_SEAL_HKDF_LABEL = "rapidmx:verification-seal:v1";
42
+ /** Fixed, non-secret HKDF salt: the master key is already uniformly random (see web-client's `localIndexKey.ts`). */
43
+ const FIXED_SALT = new TextEncoder().encode("rapidmx-verification-seal-v1");
44
+ const SEAL_VERSION = "v1";
45
+ const TAG_LENGTH_BYTES = 32;
46
+ const SHA256_HEX = /^[0-9a-f]{64}$/;
47
+ const SEALED_STATES = ["signed_verified", "encrypted_verified"];
48
+ /** SHA-256 (lowercase hex) of a message's raw MIME, as `evaluateMessageSecurity()` receives it: a binary string
49
+ * (`mailApi.ts`'s `getMessageRawContent()`, one code unit per byte) or the bytes themselves. A string that can't be a
50
+ * binary string (a code unit above 0xFF) is hashed as its UTF-8 encoding, like `mime.ts`'s `binaryStringToBytes()`. */
51
+ export async function rawMimeSha256(raw) {
52
+ const bytes = typeof raw === "string" ? binaryStringToBytes(raw) : raw;
53
+ const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
54
+ return [...digest].map((byte) => byte.toString(16).padStart(2, "0")).join("");
55
+ }
56
+ function assertNotDestroyed(unlocked) {
57
+ if (unlocked.destroyed) {
58
+ throw new KeysLockedError();
59
+ }
60
+ }
61
+ /** Derives the mailbox's seal key and imports it as a non-extractable HMAC key, zeroing the raw bytes. Throws
62
+ * `KeysLockedError` for destroyed or zeroed key material. */
63
+ async function importSealKey(mailboxUid, unlocked) {
64
+ assertNotDestroyed(unlocked);
65
+ const raw = await hkdfDerive(unlocked.masterKey, FIXED_SALT, `${VERIFICATION_SEAL_HKDF_LABEL}:${mailboxUid}`);
66
+ try {
67
+ const key = await crypto.subtle.importKey("raw", raw, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
68
+ // Locked while deriving: the derivation may have copied the master key before it was zeroed.
69
+ assertNotDestroyed(unlocked);
70
+ return key;
71
+ }
72
+ finally {
73
+ raw.fill(0);
74
+ }
75
+ }
76
+ /** Length-prefixed (4-byte big-endian) UTF-8 fields, so no two field lists encode alike. */
77
+ function canonicalBytes(fields) {
78
+ const encoded = fields.map((field) => new TextEncoder().encode(field));
79
+ const out = new Uint8Array(encoded.reduce((total, bytes) => total + 4 + bytes.length, 0));
80
+ const view = new DataView(out.buffer);
81
+ let offset = 0;
82
+ for (const bytes of encoded) {
83
+ view.setUint32(offset, bytes.length);
84
+ out.set(bytes, offset + 4);
85
+ offset += 4 + bytes.length;
86
+ }
87
+ return out;
88
+ }
89
+ async function computeTag(key, fields) {
90
+ const data = canonicalBytes([
91
+ SEAL_VERSION,
92
+ fields.mailboxUid,
93
+ fields.messageUid,
94
+ String(fields.masterKeyGeneration),
95
+ fields.rawSha256,
96
+ fields.signerFingerprint,
97
+ fields.state,
98
+ String(fields.verifiedAt),
99
+ ]);
100
+ return new Uint8Array(await crypto.subtle.sign("HMAC", key, data));
101
+ }
102
+ /** Compares every byte whatever the first difference (callers only pass 32-byte tags; a length difference still fails). */
103
+ function constantTimeEqual(a, b) {
104
+ let diff = a.length ^ b.length;
105
+ for (let i = 0; i < a.length; i++) {
106
+ diff |= a[i] ^ b[i];
107
+ }
108
+ return diff === 0;
109
+ }
110
+ /** A non-negative safe integer - a `verifiedAt` or a `masterKeyGeneration`. */
111
+ function isValidTimestamp(value) {
112
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
113
+ }
114
+ /**
115
+ * Seals a verification result for `mailboxUid`'s message `input.messageUid` - see this module's doc comment for the
116
+ * format. Throws `KeysLockedError` for destroyed keys, and a plain `Error` for input that can't be sealed: empty uids or
117
+ * fingerprint, a `rawSha256` that isn't 64 hex digits, an unknown `state`, a `verifiedAt` or `masterKeyGeneration` that isn't a non-negative
118
+ * integer, or a seal that would exceed `MAX_VERIFICATION_SEAL_LENGTH` (very long uids).
119
+ */
120
+ export async function buildVerificationSeal(mailboxUid, unlocked, input) {
121
+ const fields = {
122
+ mailboxUid,
123
+ messageUid: input.messageUid,
124
+ rawSha256: typeof input.rawSha256 === "string" ? input.rawSha256.toLowerCase() : "",
125
+ signerFingerprint: typeof input.signerFingerprint === "string" ? input.signerFingerprint.toLowerCase() : "",
126
+ state: input.state,
127
+ verifiedAt: input.verifiedAt,
128
+ masterKeyGeneration: input.masterKeyGeneration,
129
+ };
130
+ if (!mailboxUid || !fields.messageUid || !fields.signerFingerprint) {
131
+ throw new Error("A verification seal needs a mailbox uid, message uid and signer fingerprint.");
132
+ }
133
+ if (!SHA256_HEX.test(fields.rawSha256)) {
134
+ throw new Error("A verification seal's rawSha256 must be a hex SHA-256 digest.");
135
+ }
136
+ if (!SEALED_STATES.includes(fields.state) || !isValidTimestamp(fields.verifiedAt) || !isValidTimestamp(fields.masterKeyGeneration)) {
137
+ throw new Error("A verification seal needs a verified state and non-negative integer verifiedAt and masterKeyGeneration.");
138
+ }
139
+ const key = await importSealKey(mailboxUid, unlocked);
140
+ const payload = { v: 1, mb: fields.mailboxUid, id: fields.messageUid, g: fields.masterKeyGeneration, h: fields.rawSha256, fp: fields.signerFingerprint, st: fields.state, t: fields.verifiedAt };
141
+ const payloadText = toBase64Url(new TextEncoder().encode(JSON.stringify(payload)));
142
+ const seal = `${SEAL_VERSION}.${payloadText}.${toBase64Url(await computeTag(key, fields))}`;
143
+ if (seal.length > MAX_VERIFICATION_SEAL_LENGTH) {
144
+ throw new Error(`A verification seal can't exceed ${MAX_VERIFICATION_SEAL_LENGTH} characters.`);
145
+ }
146
+ return seal;
147
+ }
148
+ const BASE64URL = /^[A-Za-z0-9_-]+$/;
149
+ /** Splits and decodes a v1 seal, or `undefined` for anything malformed. Never throws. */
150
+ function parseSeal(seal) {
151
+ if (typeof seal !== "string" || seal.length > MAX_VERIFICATION_SEAL_LENGTH || !VERIFICATION_SEAL_CHARSET.test(seal)) {
152
+ return undefined;
153
+ }
154
+ const parts = seal.split(".");
155
+ if (parts.length !== 3 || parts[0] !== SEAL_VERSION || !BASE64URL.test(parts[1]) || !BASE64URL.test(parts[2])) {
156
+ return undefined;
157
+ }
158
+ try {
159
+ const tag = fromBase64Url(parts[2]);
160
+ const payload = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(fromBase64Url(parts[1])));
161
+ if (tag.length !== TAG_LENGTH_BYTES || typeof payload !== "object" || payload === null) {
162
+ return undefined;
163
+ }
164
+ const { v, mb, id, g, h, fp, st, t } = payload;
165
+ if (v !== 1 ||
166
+ typeof mb !== "string" ||
167
+ typeof id !== "string" ||
168
+ !isValidTimestamp(g) ||
169
+ typeof h !== "string" ||
170
+ !SHA256_HEX.test(h) ||
171
+ typeof fp !== "string" ||
172
+ !fp ||
173
+ typeof st !== "string" ||
174
+ !SEALED_STATES.includes(st) ||
175
+ !isValidTimestamp(t)) {
176
+ return undefined;
177
+ }
178
+ return { fields: { mailboxUid: mb, messageUid: id, rawSha256: h, signerFingerprint: fp, state: st, verifiedAt: t, masterKeyGeneration: g }, tag };
179
+ }
180
+ catch {
181
+ // Invalid base64 or UTF-8, or JSON that won't parse.
182
+ return undefined;
183
+ }
184
+ }
185
+ /**
186
+ * Opens a seal written by `buildVerificationSeal()`. Resolves `{ signerFingerprint, state, verifiedAt, masterKeyGeneration }`
187
+ * only when the version is known, the tag verifies (constant-time comparison) under this mailbox's seal key, the sealed mailbox and
188
+ * message uids equal `mailboxUid`/`messageUid`, and the sealed hash equals `rawSha256` (the current raw MIME's
189
+ * `rawMimeSha256()`), and - when `expectedMasterKeyGeneration` is given - the sealed generation equals it (the vault's
190
+ * current `masterKeyGeneration`; a seal from another generation wouldn't open under that master key anyway, but this
191
+ * checks it explicitly). Anything else - a malformed, truncated, tampered, foreign or oversized seal, or a seal sealed
192
+ * under a different master key - resolves `undefined`; this never throws for the seal's content. Throws
193
+ * `KeysLockedError` for destroyed keys, whatever the seal.
194
+ */
195
+ export async function openVerificationSeal(mailboxUid, unlocked, messageUid, seal, rawSha256, expectedMasterKeyGeneration) {
196
+ assertNotDestroyed(unlocked);
197
+ const parsed = parseSeal(seal);
198
+ if (!parsed) {
199
+ return undefined;
200
+ }
201
+ const key = await importSealKey(mailboxUid, unlocked);
202
+ // The tag is computed over the values the caller expects, so a seal for another mailbox or message fails the MAC as
203
+ // well as the explicit comparison below.
204
+ const expected = await computeTag(key, { ...parsed.fields, mailboxUid, messageUid });
205
+ const { fields } = parsed;
206
+ const tagMatches = constantTimeEqual(expected, parsed.tag);
207
+ if (!tagMatches ||
208
+ fields.mailboxUid !== mailboxUid ||
209
+ fields.messageUid !== messageUid ||
210
+ fields.rawSha256 !== String(rawSha256).toLowerCase() ||
211
+ (expectedMasterKeyGeneration !== undefined && fields.masterKeyGeneration !== expectedMasterKeyGeneration)) {
212
+ return undefined;
213
+ }
214
+ return {
215
+ signerFingerprint: fields.signerFingerprint,
216
+ state: fields.state,
217
+ verifiedAt: fields.verifiedAt,
218
+ masterKeyGeneration: fields.masterKeyGeneration,
219
+ };
220
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Builds what a Reply/Reply All/Forward compose starts with - its recipients, its quoted original message, and the
3
+ * body layout around the quote - entirely client-side, same "restapi never composes message bodies" convention as
4
+ * `mailApi.ts`'s `assembleDraft()`.
5
+ *
6
+ * The quote carries the original's full body, as the reader saw it: the caller passes a `QuotedBody` (the message's
7
+ * sanitized HTML body, its decrypted/verified content, or its plain-text body). HTML is sanitized again here with
8
+ * the same remote-resource-stripping policy used to display a client-rendered body (`messageBodySanitizer.ts`), plus
9
+ * a stricter tag list for the editor. `message.bodyPreview` - a server-derived excerpt, truncated - is only the last
10
+ * resort, when no body could be loaded.
11
+ */
12
+ import { Message, Recipient } from "../mailApi.js";
13
+ /**
14
+ * A recipient's display name, without the address the server sometimes leaves in it: an ingested message's `from`
15
+ * carries the whole `"Bob Allen" <bob@example.com>` From header as its display name, which would otherwise be shown
16
+ * (and addressed) as `"Bob Allen" <bob@example.com> <bob@example.com>`. A name that is, or ends in, the recipient's
17
+ * own address is reduced to the part before it; a name that is any other address is dropped entirely.
18
+ */
19
+ export declare function recipientDisplayName(recipient: Recipient): string | undefined;
20
+ /** The body of the message being quoted, as loaded by the caller. `html` is preferred over `text`; either may be
21
+ * absent (e.g. an encrypted message this device can't open, or a failed fetch). */
22
+ export interface QuotedBody {
23
+ /** An HTML body. Sanitized again by the quote builders, so it may come from any source. */
24
+ html?: string;
25
+ /** A plain-text body. HTML-escaped by the quote builders. */
26
+ text?: string;
27
+ }
28
+ /** Prepends "Re: " unless `subject` already starts with it (any casing) — the same convention every
29
+ * mail client uses to avoid a "Re: Re: Re: ..." chain. */
30
+ export declare function replySubject(subject: string): string;
31
+ /** Same convention as `replySubject()`, for forwards. */
32
+ export declare function forwardSubject(subject: string): string;
33
+ /** The quoted original a Reply/Reply All compose starts with: an "On <date>, Name <address> wrote:" line and the
34
+ * original body in a blockquote. `buildComposeBodyHtml()` places it in the body. */
35
+ export declare function buildReplyQuote(message: Message, body?: QuotedBody): string;
36
+ /** The quoted body a Forward compose starts with — includes the original headers block, matching every
37
+ * major mail client's own forward convention, since a forward (unlike a reply) has no visible reply
38
+ * chain of its own to imply who originally sent it. */
39
+ export declare function buildForwardQuote(message: Message, body?: QuotedBody): string;
40
+ /**
41
+ * The HTML a compose body starts with, laid out the way Outlook and Gmail do: an empty paragraph first (where the
42
+ * caret goes, so typing lands above everything else), then the signature, then a blank line, then the quoted
43
+ * original. `""` when there is neither a signature nor a quote, which leaves the editor's own single empty
44
+ * paragraph.
45
+ *
46
+ * A quote is always preceded by an empty paragraph of its own, on top of the one that separates it from a
47
+ * signature: what the reply opens with is the caret's line and then the quote right underneath it, and there has to
48
+ * be somewhere to press Enter into above the "On ... wrote:" line without first making room for it by hand.
49
+ */
50
+ export declare function buildComposeBodyHtml(signatureHtml?: string, quotedHtml?: string): string;
51
+ /**
52
+ * The longest `References` chain `buildReplyThreading()` reports. A chain grows by one entry per reply forever
53
+ * and the server trims what it actually writes into the header anyway; sending an unbounded one is pointless.
54
+ * The root is always kept - it is what a conversation is keyed on - and the oldest entries after it are dropped.
55
+ */
56
+ export declare const MAX_REPLY_REFERENCES = 20;
57
+ /**
58
+ * What a reply or forward must record about the thread it continues, from the message it is a reply to: the
59
+ * RFC 5322 `In-Reply-To` (that message's own `messageId`) and the `References` chain (its own chain, with its
60
+ * `messageId` appended). Pass the result to `createDraft()`.
61
+ *
62
+ * Without it a reply is relayed with no threading headers at all - this server composes a reply's MIME from the
63
+ * structured compose input, which says nothing about what is being replied to - so every recipient's mail server,
64
+ * and the sender's own Sent Items copy, files it as a brand-new conversation instead of adding it to the thread.
65
+ */
66
+ export declare function buildReplyThreading(message: Pick<Message, "messageId" | "references">): {
67
+ inReplyTo: string;
68
+ references: string[];
69
+ };
70
+ /** The To and Cc a reply starts with. */
71
+ export interface ReplyRecipients {
72
+ to: Recipient[];
73
+ cc: Recipient[];
74
+ }
75
+ /**
76
+ * Who a Reply or Reply All goes to. The replying mailbox itself (`ownAddresses`: its primary address and aliases,
77
+ * compared case-insensitively) is left out, and no address is repeated.
78
+ *
79
+ * A reply to someone else's message goes to its sender. Reply All adds the original To recipients to To and the
80
+ * original Cc recipients to Cc.
81
+ *
82
+ * A reply to a message the mailbox sent itself (e.g. from Sent Items) goes to the original To recipients instead of
83
+ * back to the mailbox, and Reply All keeps the original Cc as Cc. With no other To recipient, the original Cc
84
+ * recipients become To. Only a message the mailbox sent to nobody but itself is replied to itself.
85
+ *
86
+ * Bcc recipients are never carried over. Display names are kept.
87
+ */
88
+ export declare function buildReplyRecipients(message: Message, ownAddresses: string[], replyAll: boolean): ReplyRecipients;
@@ -0,0 +1,204 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * Builds what a Reply/Reply All/Forward compose starts with - its recipients, its quoted original message, and the
7
+ * body layout around the quote - entirely client-side, same "restapi never composes message bodies" convention as
8
+ * `mailApi.ts`'s `assembleDraft()`.
9
+ *
10
+ * The quote carries the original's full body, as the reader saw it: the caller passes a `QuotedBody` (the message's
11
+ * sanitized HTML body, its decrypted/verified content, or its plain-text body). HTML is sanitized again here with
12
+ * the same remote-resource-stripping policy used to display a client-rendered body (`messageBodySanitizer.ts`), plus
13
+ * a stricter tag list for the editor. `message.bodyPreview` - a server-derived excerpt, truncated - is only the last
14
+ * resort, when no body could be loaded.
15
+ */
16
+ import { sanitizeQuotedHtml } from "../messageBodySanitizer.js";
17
+ function escapeHtml(text) {
18
+ return text
19
+ .replace(/&/g, "&amp;")
20
+ .replace(/</g, "&lt;")
21
+ .replace(/>/g, "&gt;")
22
+ .replace(/"/g, "&quot;")
23
+ .replace(/'/g, "&#39;");
24
+ }
25
+ function textToHtml(text) {
26
+ return escapeHtml(text)
27
+ .split(/\r?\n/)
28
+ .map((line) => `<p>${line || "&nbsp;"}</p>`)
29
+ .join("");
30
+ }
31
+ /**
32
+ * A recipient's display name, without the address the server sometimes leaves in it: an ingested message's `from`
33
+ * carries the whole `"Bob Allen" <bob@example.com>` From header as its display name, which would otherwise be shown
34
+ * (and addressed) as `"Bob Allen" <bob@example.com> <bob@example.com>`. A name that is, or ends in, the recipient's
35
+ * own address is reduced to the part before it; a name that is any other address is dropped entirely.
36
+ */
37
+ export function recipientDisplayName(recipient) {
38
+ const name = recipient.displayName?.trim();
39
+ if (!name) {
40
+ return undefined;
41
+ }
42
+ const angle = /^(.*)<([^<>]*)>$/.exec(name);
43
+ const inner = angle ? angle[2].trim() : name;
44
+ if (!inner.includes("@")) {
45
+ return name;
46
+ }
47
+ if (inner.toLowerCase() !== recipient.address.trim().toLowerCase()) {
48
+ return undefined;
49
+ }
50
+ const before = (angle ? angle[1] : "").trim().replace(/^"(.*)"$/s, "$1").trim();
51
+ return before || undefined;
52
+ }
53
+ /** The same recipient with `recipientDisplayName()`'s cleaned-up name (absent when nothing is left of it). */
54
+ function cleaned(recipient) {
55
+ const name = recipientDisplayName(recipient);
56
+ return name === recipient.displayName ? recipient : { ...recipient, ...(name ? { displayName: name } : { displayName: undefined }) };
57
+ }
58
+ /** `Name <address>`, or the bare address when there's no usable display name. */
59
+ function nameAndAddress(recipient) {
60
+ const name = recipientDisplayName(recipient);
61
+ return name ? `${name} <${recipient.address}>` : recipient.address;
62
+ }
63
+ const QUOTE_STYLE = "border-left:2px solid #ccc;margin:0;padding-left:1em;color:#666;";
64
+ /** Whether sanitized HTML still shows anything: text other than whitespace, or an image. */
65
+ function hasVisibleContent(html) {
66
+ return /<img\b/i.test(html) || html.replace(/<[^>]*>/g, "").replace(/&nbsp;|\s/g, "") !== "";
67
+ }
68
+ /** The quoted content: the sanitized HTML body, else the text body, else the body preview. */
69
+ function quotedContent(message, body) {
70
+ if (body?.html) {
71
+ const sanitized = sanitizeQuotedHtml(body.html);
72
+ if (hasVisibleContent(sanitized)) {
73
+ return sanitized;
74
+ }
75
+ }
76
+ if (body?.text?.trim()) {
77
+ return textToHtml(body.text);
78
+ }
79
+ return textToHtml(message.bodyPreview ?? "");
80
+ }
81
+ /** Prepends "Re: " unless `subject` already starts with it (any casing) — the same convention every
82
+ * mail client uses to avoid a "Re: Re: Re: ..." chain. */
83
+ export function replySubject(subject) {
84
+ return /^re:/i.test(subject.trim()) ? subject : `Re: ${subject}`;
85
+ }
86
+ /** Same convention as `replySubject()`, for forwards. */
87
+ export function forwardSubject(subject) {
88
+ return /^fwd:/i.test(subject.trim()) ? subject : `Fwd: ${subject}`;
89
+ }
90
+ /** The quoted original a Reply/Reply All compose starts with: an "On <date>, Name <address> wrote:" line and the
91
+ * original body in a blockquote. `buildComposeBodyHtml()` places it in the body. */
92
+ export function buildReplyQuote(message, body) {
93
+ const when = new Date(message.receivedDate).toLocaleString();
94
+ return (`<p>On ${escapeHtml(when)}, ${escapeHtml(nameAndAddress(message.from))} wrote:</p>` +
95
+ `<blockquote style="${QUOTE_STYLE}">${quotedContent(message, body)}</blockquote>`);
96
+ }
97
+ /** The quoted body a Forward compose starts with — includes the original headers block, matching every
98
+ * major mail client's own forward convention, since a forward (unlike a reply) has no visible reply
99
+ * chain of its own to imply who originally sent it. */
100
+ export function buildForwardQuote(message, body) {
101
+ const when = new Date(message.receivedDate).toLocaleString();
102
+ const to = message.recipients
103
+ .filter((r) => r.type === "to")
104
+ .map(nameAndAddress)
105
+ .join(", ");
106
+ return (`<p>---------- Forwarded message ----------<br>` +
107
+ `From: ${escapeHtml(nameAndAddress(message.from))}<br>` +
108
+ `Date: ${escapeHtml(when)}<br>` +
109
+ `Subject: ${escapeHtml(message.subject || "(no subject)")}<br>` +
110
+ `To: ${escapeHtml(to)}</p>` +
111
+ `<blockquote style="${QUOTE_STYLE}">${quotedContent(message, body)}</blockquote>`);
112
+ }
113
+ /**
114
+ * The HTML a compose body starts with, laid out the way Outlook and Gmail do: an empty paragraph first (where the
115
+ * caret goes, so typing lands above everything else), then the signature, then a blank line, then the quoted
116
+ * original. `""` when there is neither a signature nor a quote, which leaves the editor's own single empty
117
+ * paragraph.
118
+ *
119
+ * A quote is always preceded by an empty paragraph of its own, on top of the one that separates it from a
120
+ * signature: what the reply opens with is the caret's line and then the quote right underneath it, and there has to
121
+ * be somewhere to press Enter into above the "On ... wrote:" line without first making room for it by hand.
122
+ */
123
+ export function buildComposeBodyHtml(signatureHtml, quotedHtml) {
124
+ if (!signatureHtml && !quotedHtml) {
125
+ return "";
126
+ }
127
+ const separator = signatureHtml && quotedHtml ? "<p></p>" : "";
128
+ const aboveQuote = quotedHtml ? "<p></p>" : "";
129
+ return `<p></p>${signatureHtml ?? ""}${separator}${aboveQuote}${quotedHtml ?? ""}`;
130
+ }
131
+ /**
132
+ * The longest `References` chain `buildReplyThreading()` reports. A chain grows by one entry per reply forever
133
+ * and the server trims what it actually writes into the header anyway; sending an unbounded one is pointless.
134
+ * The root is always kept - it is what a conversation is keyed on - and the oldest entries after it are dropped.
135
+ */
136
+ export const MAX_REPLY_REFERENCES = 20;
137
+ /**
138
+ * What a reply or forward must record about the thread it continues, from the message it is a reply to: the
139
+ * RFC 5322 `In-Reply-To` (that message's own `messageId`) and the `References` chain (its own chain, with its
140
+ * `messageId` appended). Pass the result to `createDraft()`.
141
+ *
142
+ * Without it a reply is relayed with no threading headers at all - this server composes a reply's MIME from the
143
+ * structured compose input, which says nothing about what is being replied to - so every recipient's mail server,
144
+ * and the sender's own Sent Items copy, files it as a brand-new conversation instead of adding it to the thread.
145
+ */
146
+ export function buildReplyThreading(message) {
147
+ const parent = message.messageId.trim();
148
+ const chain = [];
149
+ for (const reference of message.references ?? []) {
150
+ const id = typeof reference === "string" ? reference.trim() : "";
151
+ if (id && id !== parent && !chain.includes(id)) {
152
+ chain.push(id);
153
+ }
154
+ }
155
+ chain.push(parent);
156
+ // Trimmed from after the root, so the thread's first message (what the conversation is keyed on) and the
157
+ // most recent ancestors both survive.
158
+ while (chain.length > MAX_REPLY_REFERENCES) {
159
+ chain.splice(1, 1);
160
+ }
161
+ return { inReplyTo: parent, references: chain };
162
+ }
163
+ /**
164
+ * Who a Reply or Reply All goes to. The replying mailbox itself (`ownAddresses`: its primary address and aliases,
165
+ * compared case-insensitively) is left out, and no address is repeated.
166
+ *
167
+ * A reply to someone else's message goes to its sender. Reply All adds the original To recipients to To and the
168
+ * original Cc recipients to Cc.
169
+ *
170
+ * A reply to a message the mailbox sent itself (e.g. from Sent Items) goes to the original To recipients instead of
171
+ * back to the mailbox, and Reply All keeps the original Cc as Cc. With no other To recipient, the original Cc
172
+ * recipients become To. Only a message the mailbox sent to nobody but itself is replied to itself.
173
+ *
174
+ * Bcc recipients are never carried over. Display names are kept.
175
+ */
176
+ export function buildReplyRecipients(message, ownAddresses, replyAll) {
177
+ const own = new Set(ownAddresses.map((address) => address.trim().toLowerCase()));
178
+ const seen = new Set();
179
+ const take = (recipients) => recipients
180
+ .filter((recipient) => {
181
+ const key = recipient.address.trim().toLowerCase();
182
+ if (!key || own.has(key) || seen.has(key)) {
183
+ return false;
184
+ }
185
+ seen.add(key);
186
+ return true;
187
+ })
188
+ .map(cleaned);
189
+ const originalTo = message.recipients.filter((r) => r.type === "to");
190
+ const originalCc = message.recipients.filter((r) => r.type === "cc");
191
+ if (!own.has(message.from.address.trim().toLowerCase())) {
192
+ const to = take([message.from, ...(replyAll ? originalTo : [])]);
193
+ return { to, cc: replyAll ? take(originalCc) : [] };
194
+ }
195
+ const to = take(originalTo);
196
+ const cc = take(originalCc);
197
+ if (to.length > 0) {
198
+ return { to, cc: replyAll ? cc : [] };
199
+ }
200
+ if (cc.length > 0) {
201
+ return { to: cc, cc: [] };
202
+ }
203
+ return { to: [cleaned(message.from)], cc: [] };
204
+ }
@@ -0,0 +1,9 @@
1
+ export interface EmojiCategory {
2
+ id: string;
3
+ emojis: {
4
+ id: string;
5
+ native: string;
6
+ name: string;
7
+ }[];
8
+ }
9
+ export declare const EMOJI_CATEGORIES: EmojiCategory[];
@@ -0,0 +1,18 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * Emoji data for the Compose window's "Insert emoji" picker — the full standard unicode emoji set
7
+ * (categories + native characters), sourced from `@emoji-mart/data` (used as a pure data file only;
8
+ * this app has its own grid UI rather than pulling in `@emoji-mart`'s full React picker component).
9
+ */
10
+ import emojiData from "@emoji-mart/data" with { type: "json" };
11
+ const data = emojiData;
12
+ export const EMOJI_CATEGORIES = data.categories.map((category) => ({
13
+ id: category.id,
14
+ emojis: category.emojis
15
+ .map((emojiId) => data.emojis[emojiId])
16
+ .filter((emoji) => emoji != null && emoji.skins.length > 0)
17
+ .map((emoji) => ({ id: emoji.id, native: emoji.skins[0].native, name: emoji.name })),
18
+ }));
@@ -0,0 +1,17 @@
1
+ /** Thin wrapper over this server's own Giphy search proxy (`src/routes/BaseGiphySearchRoute.ts`) —
2
+ * never calls Giphy directly from the browser, since that would require shipping the API key in the
3
+ * client bundle. See `GifPicker.tsx` for the UI this backs. */
4
+ import { ApiClient } from "../../util/api.js";
5
+ export interface GiphyGif {
6
+ id: string;
7
+ /** A small rendition, for the search grid's thumbnails. */
8
+ previewUrl: string;
9
+ /** The full-resolution GIF — inserted into the message body when chosen. */
10
+ url: string;
11
+ title: string;
12
+ }
13
+ /** An empty/blank `query` returns Giphy's trending feed (see the backend route's own doc comment). `client`,
14
+ * given here, is an explicit `ApiClient` from `createApiClient()` (e.g. one account of a multi-account app) to
15
+ * call instead of the default global `apiFetch()` - see `withClient()`'s own doc comment in `util/api.ts`.
16
+ * Omitted (the default), this behaves exactly as before. */
17
+ export declare function searchGifs(query: string, client?: ApiClient): Promise<GiphyGif[]>;
@@ -0,0 +1,20 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /** Thin wrapper over this server's own Giphy search proxy (`src/routes/BaseGiphySearchRoute.ts`) —
6
+ * never calls Giphy directly from the browser, since that would require shipping the API key in the
7
+ * client bundle. See `GifPicker.tsx` for the UI this backs. */
8
+ import { withClient } from "../../util/api.js";
9
+ /** An empty/blank `query` returns Giphy's trending feed (see the backend route's own doc comment). `client`,
10
+ * given here, is an explicit `ApiClient` from `createApiClient()` (e.g. one account of a multi-account app) to
11
+ * call instead of the default global `apiFetch()` - see `withClient()`'s own doc comment in `util/api.ts`.
12
+ * Omitted (the default), this behaves exactly as before. */
13
+ export function searchGifs(query, client) {
14
+ const params = new URLSearchParams();
15
+ const trimmed = query.trim();
16
+ if (trimmed) {
17
+ params.set("q", trimmed);
18
+ }
19
+ return withClient(client, `/mail/giphy/search?${params.toString()}`);
20
+ }