@rapidmx/web-client 0.21.0 → 0.22.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 (885) 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 +27 -23
  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 +2 -2
  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 +7 -5
  120. package/apps/shared/components/mail/ConversationThreadPane.tsx +26 -15
  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 +32 -30
  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 +2 -2
  142. package/apps/shared/components/mail/invite/InviteRsvpPopover.tsx +9 -7
  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/messageExport.ts +1 -1
  159. package/apps/shared/components/mail/reading/printMessage.ts +2 -2
  160. package/apps/shared/components/mail/reading/useMessageActions.ts +28 -21
  161. package/apps/shared/components/mail/unreadStyle.tsx +1 -1
  162. package/apps/shared/components/mail/verificationSeals.ts +16 -12
  163. package/apps/shared/components/mail/writableMailboxes.ts +14 -7
  164. package/apps/shared/components/rules/RuleBuilder.tsx +1 -1
  165. package/apps/shared/components/settings/SigningCertificateCard.tsx +4 -4
  166. package/apps/shared/components/settings/layout/SettingsShell.tsx +8 -6
  167. package/apps/shared/components/sharing/PrincipalListField.tsx +1 -1
  168. package/apps/shared/components/sharing/PrincipalPicker.tsx +1 -1
  169. package/apps/shared/components/sharing/PrincipalResolver.tsx +4 -4
  170. package/apps/shared/components/tasks/TasksSidebar.tsx +7 -5
  171. package/apps/shared/components/tasks/layout/TasksShell.tsx +9 -7
  172. package/apps/shared/keyboard/ShortcutsDialog.tsx +1 -1
  173. package/apps/shared/mail/findWellKnownFolderUid.ts +6 -4
  174. package/apps/shared/mail/folderCounts.ts +8 -4
  175. package/apps/shared/mail/folderOfType.ts +5 -3
  176. package/apps/shared/mail/folderTree.ts +1 -1
  177. package/apps/shared/mail/listSnapshots.ts +2 -2
  178. package/apps/shared/mail/messageReadState.ts +6 -5
  179. package/apps/shared/mail/newMailNotifications.ts +2 -2
  180. package/apps/shared/mail/outbox/composeBridge.ts +2 -2
  181. package/apps/shared/mail/outbox/outboxState.ts +1 -1
  182. package/apps/shared/mail/outbox/outgoingReplies.ts +2 -2
  183. package/apps/shared/mail/outbox/sendDecision.ts +2 -2
  184. package/apps/shared/mail/outbox/sendJob.ts +40 -35
  185. package/apps/shared/mail/outbox/sendOutcomes.ts +20 -15
  186. package/apps/shared/mail/outbox/useOutboxStatus.ts +5 -3
  187. package/apps/shared/mail/permanentDelete.ts +8 -7
  188. package/apps/shared/mail/primaryMailbox.ts +1 -1
  189. package/apps/shared/mail/reportNotices.ts +1 -1
  190. package/apps/shared/mail/senderBlocking.ts +36 -20
  191. package/apps/shared/mail/useMailConnection.ts +12 -10
  192. package/apps/shared/mail/useMailLiveUpdates.ts +3 -3
  193. package/apps/shared/mail/useMailboxUpdateAccess.ts +35 -11
  194. package/apps/shared/mail/useMarkMessageRead.ts +14 -7
  195. package/apps/shared/mail/useNewMailNotifications.ts +1 -1
  196. package/apps/shared/mail/usePermanentDelete.tsx +5 -3
  197. package/apps/shared/navigation/pageTitle.ts +1 -1
  198. package/apps/shared/notifications/NotificationCenter.tsx +1 -1
  199. package/apps/shared/notifications/NotificationHistoryDialog.tsx +2 -2
  200. package/apps/shared/notifications/apiErrors.ts +2 -2
  201. package/apps/shared/notifications/pushStatus.ts +1 -1
  202. package/apps/shared/notifications/systemErrors.ts +1 -1
  203. package/apps/shared/search/LocalIndexLifecycle.tsx +18 -12
  204. package/apps/shared/search/crossMailboxSearch.ts +3 -3
  205. package/apps/shared/search/localIndexBuilder.ts +24 -12
  206. package/apps/shared/search/localIndexKey.ts +1 -1
  207. package/apps/shared/search/localIndexRpcClient.ts +150 -30
  208. package/apps/shared/search/localIndexTransport.ts +84 -0
  209. package/apps/shared/search/localIndexWorker.ts +1 -1
  210. package/apps/shared/search/searchTier2.ts +3 -3
  211. package/apps/shared/signing/enrollmentTracker.ts +3 -3
  212. package/apps/shared/signing/enrollmentView.ts +1 -1
  213. package/apps/shared/signing/signingInfo.ts +1 -1
  214. package/apps/shared/signing/useSigningEnrollmentWatcher.ts +6 -4
  215. package/apps/shared/styles/app.css +14 -23
  216. package/apps/www/_layout.tsx +2 -2
  217. package/apps/www/calendar/index.tsx +20 -18
  218. package/apps/www/contacts/[uid].tsx +8 -6
  219. package/apps/www/contacts/index.tsx +19 -17
  220. package/apps/www/index.tsx +57 -48
  221. package/apps/www/messages/[uid].tsx +11 -9
  222. package/apps/www/settings/auto-reply/index.tsx +6 -4
  223. package/apps/www/settings/blocked-senders/index.tsx +9 -7
  224. package/apps/www/settings/encryption/index.tsx +38 -32
  225. package/apps/www/settings/filters/[uid].tsx +19 -14
  226. package/apps/www/settings/filters/_mailFilterRuleConfig.tsx +2 -2
  227. package/apps/www/settings/filters/index.tsx +4 -4
  228. package/apps/www/settings/filters/new/index.tsx +10 -8
  229. package/apps/www/settings/labels/index.tsx +12 -10
  230. package/apps/www/settings/privacy/index.tsx +18 -14
  231. package/apps/www/settings/profile/index.tsx +16 -11
  232. package/apps/www/settings/read-receipts/index.tsx +17 -12
  233. package/apps/www/settings/sharing/index.tsx +6 -6
  234. package/apps/www/settings/signatures/[uid].tsx +5 -5
  235. package/apps/www/settings/signatures/index.tsx +4 -4
  236. package/apps/www/settings/signatures/new/index.tsx +4 -4
  237. package/apps/www/settings/signatures/signatureDefaults.ts +1 -1
  238. package/apps/www/tasks/index.tsx +28 -23
  239. package/dist/apps/admin/_layout.d.ts +1 -1
  240. package/dist/apps/admin/_layout.js +1 -1
  241. package/dist/apps/admin/audit-log/index.d.ts +1 -1
  242. package/dist/apps/admin/audit-log/index.js +4 -4
  243. package/dist/apps/admin/branding/index.js +3 -3
  244. package/dist/apps/admin/data-requests/index.js +8 -8
  245. package/dist/apps/admin/distribution-lists/[uid].js +3 -3
  246. package/dist/apps/admin/distribution-lists/index.js +4 -4
  247. package/dist/apps/admin/distribution-lists/new/index.js +5 -5
  248. package/dist/apps/admin/domains/[uid].js +6 -6
  249. package/dist/apps/admin/domains/index.js +4 -4
  250. package/dist/apps/admin/domains/new/index.js +5 -5
  251. package/dist/apps/admin/encryption-policy/index.js +1 -1
  252. package/dist/apps/admin/escrow-scopes/[uid].d.ts +1 -1
  253. package/dist/apps/admin/escrow-scopes/[uid].js +7 -7
  254. package/dist/apps/admin/escrow-scopes/index.js +4 -4
  255. package/dist/apps/admin/escrow-scopes/new/index.js +5 -5
  256. package/dist/apps/admin/index.js +6 -6
  257. package/dist/apps/admin/ingest-queue/index.js +4 -4
  258. package/dist/apps/admin/mailbox-policy/index.js +1 -1
  259. package/dist/apps/admin/mailboxes/[uid].js +5 -5
  260. package/dist/apps/admin/quarantine/index.js +5 -5
  261. package/dist/apps/admin/retention-policy/index.js +3 -3
  262. package/dist/apps/admin/signing-certificates/index.js +5 -5
  263. package/dist/apps/admin/transport-rules/[uid].js +5 -5
  264. package/dist/apps/admin/transport-rules/_transportRuleConfig.d.ts +1 -1
  265. package/dist/apps/admin/transport-rules/_transportRuleConfig.js +2 -2
  266. package/dist/apps/admin/transport-rules/index.js +4 -4
  267. package/dist/apps/admin/transport-rules/new/index.js +5 -5
  268. package/dist/apps/escrow/_layout.d.ts +1 -1
  269. package/dist/apps/escrow/audit-log/index.d.ts +1 -1
  270. package/dist/apps/escrow/audit-log/index.js +4 -4
  271. package/dist/apps/escrow/index.js +4 -4
  272. package/dist/apps/escrow/matters/[uid].js +10 -10
  273. package/dist/apps/escrow/matters/new/index.js +6 -6
  274. package/dist/apps/shared/appearance/AppearanceForm.js +3 -3
  275. package/dist/apps/shared/appearance/AppearanceHead.js +1 -1
  276. package/dist/apps/shared/appearance/AppearanceProvider.d.ts +1 -1
  277. package/dist/apps/shared/appearance/AppearanceProvider.js +3 -3
  278. package/dist/apps/shared/appearance/appearanceCache.d.ts +1 -1
  279. package/dist/apps/shared/appearance/appearanceCache.js +1 -1
  280. package/dist/apps/shared/appearance/appearanceContext.d.ts +1 -1
  281. package/dist/apps/shared/appearance/theme.d.ts +1 -1
  282. package/dist/apps/shared/auth/adminAccess.js +1 -1
  283. package/dist/apps/shared/calendar/bookingPlugin.js +1 -1
  284. package/dist/apps/shared/calendar/calendarLiveUpdates.d.ts +1 -1
  285. package/dist/apps/shared/calendar/calendarReminders.d.ts +1 -1
  286. package/dist/apps/shared/calendar/useCalendarReminders.js +1 -1
  287. package/dist/apps/shared/components/admin/diagnostics/DiagnosticsManager.js +1 -1
  288. package/dist/apps/shared/components/admin/diagnostics/InstalledPlugins.d.ts +1 -1
  289. package/dist/apps/shared/components/admin/diagnostics/InstalledPlugins.js +2 -2
  290. package/dist/apps/shared/components/admin/diagnostics/LogsPanel.js +2 -2
  291. package/dist/apps/shared/components/admin/diagnostics/PackagesTable.js +1 -1
  292. package/dist/apps/shared/components/admin/diagnostics/RuntimePanel.js +1 -1
  293. package/dist/apps/shared/components/admin/diagnostics/SystemPanel.js +2 -2
  294. package/dist/apps/shared/components/admin/diagnostics/VersionsPanel.js +1 -1
  295. package/dist/apps/shared/components/admin/diagnostics/diagnosticsApi.js +1 -1
  296. package/dist/apps/shared/components/admin/diagnostics/format.js +1 -1
  297. package/dist/apps/shared/components/admin/diagnostics/logClient.js +1 -1
  298. package/dist/apps/shared/components/admin/distributionLists/MemberListCard.d.ts +1 -1
  299. package/dist/apps/shared/components/admin/distributionLists/MemberListCard.js +4 -4
  300. package/dist/apps/shared/components/admin/elevation.js +1 -1
  301. package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.js +3 -3
  302. package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +1 -1
  303. package/dist/apps/shared/components/admin/layout/AdminShell.js +7 -7
  304. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.d.ts +1 -1
  305. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.js +6 -6
  306. package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.d.ts +1 -1
  307. package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.js +10 -8
  308. package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.js +4 -4
  309. package/dist/apps/shared/components/admin/mailboxes/MailboxTable.d.ts +1 -1
  310. package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.d.ts +1 -1
  311. package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.js +7 -5
  312. package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.js +5 -5
  313. package/dist/apps/shared/components/admin/settings/BrandingForm.d.ts +1 -1
  314. package/dist/apps/shared/components/admin/settings/BrandingForm.js +5 -5
  315. package/dist/apps/shared/components/admin/settings/DomainDnsSetup.d.ts +1 -1
  316. package/dist/apps/shared/components/admin/settings/DomainDnsSetup.js +5 -5
  317. package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.d.ts +1 -1
  318. package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.js +4 -4
  319. package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.js +2 -2
  320. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.d.ts +1 -1
  321. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +14 -12
  322. package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.d.ts +1 -1
  323. package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.js +4 -4
  324. package/dist/apps/shared/components/admin/settings/PluginsManager.js +5 -5
  325. package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.d.ts +1 -1
  326. package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.js +5 -5
  327. package/dist/apps/shared/components/admin/setup/EscrowSetupStep.js +7 -7
  328. package/dist/apps/shared/components/admin/setup/SetupWizard.js +26 -22
  329. package/dist/apps/shared/components/admin/signOut.js +1 -1
  330. package/dist/apps/shared/components/admin/usePagedList.js +2 -2
  331. package/dist/apps/shared/components/calendar/AppointmentQuickForm.js +3 -3
  332. package/dist/apps/shared/components/calendar/CalendarListSidebar.d.ts +1 -1
  333. package/dist/apps/shared/components/calendar/CalendarListSidebar.js +2 -2
  334. package/dist/apps/shared/components/calendar/DescriptionEditor.js +1 -1
  335. package/dist/apps/shared/components/calendar/EventDescriptionView.js +1 -1
  336. package/dist/apps/shared/components/calendar/EventDetails.d.ts +2 -2
  337. package/dist/apps/shared/components/calendar/EventDetails.js +16 -14
  338. package/dist/apps/shared/components/calendar/EventEditor.d.ts +2 -2
  339. package/dist/apps/shared/components/calendar/EventEditor.js +22 -20
  340. package/dist/apps/shared/components/calendar/EventExpandedForm.js +2 -2
  341. package/dist/apps/shared/components/calendar/EventFormParts.d.ts +1 -1
  342. package/dist/apps/shared/components/calendar/EventFormParts.js +1 -1
  343. package/dist/apps/shared/components/calendar/EventModal.d.ts +2 -2
  344. package/dist/apps/shared/components/calendar/EventModal.js +3 -3
  345. package/dist/apps/shared/components/calendar/EventQuickForm.js +3 -3
  346. package/dist/apps/shared/components/calendar/EventShell.js +1 -1
  347. package/dist/apps/shared/components/calendar/FindATime.js +6 -4
  348. package/dist/apps/shared/components/calendar/GuestInput.d.ts +2 -2
  349. package/dist/apps/shared/components/calendar/MonthView.d.ts +1 -1
  350. package/dist/apps/shared/components/calendar/MonthView.js +1 -1
  351. package/dist/apps/shared/components/calendar/QuickCreateFaces.js +1 -1
  352. package/dist/apps/shared/components/calendar/QuickFaceFrame.js +1 -1
  353. package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +1 -1
  354. package/dist/apps/shared/components/calendar/RecurrenceEditor.js +1 -1
  355. package/dist/apps/shared/components/calendar/RequestChangeForm.js +8 -6
  356. package/dist/apps/shared/components/calendar/ResourcePicker.d.ts +1 -1
  357. package/dist/apps/shared/components/calendar/ResourcePicker.js +7 -5
  358. package/dist/apps/shared/components/calendar/SplitDayView.d.ts +1 -1
  359. package/dist/apps/shared/components/calendar/TaskQuickForm.d.ts +1 -1
  360. package/dist/apps/shared/components/calendar/TaskQuickForm.js +9 -7
  361. package/dist/apps/shared/components/calendar/TimeGridView.d.ts +1 -1
  362. package/dist/apps/shared/components/calendar/TimeGridView.js +1 -1
  363. package/dist/apps/shared/components/calendar/allDay.d.ts +2 -2
  364. package/dist/apps/shared/components/calendar/allDay.js +1 -1
  365. package/dist/apps/shared/components/calendar/eventDialogFields.d.ts +2 -2
  366. package/dist/apps/shared/components/calendar/eventDialogFields.js +2 -2
  367. package/dist/apps/shared/components/calendar/eventForm.d.ts +3 -3
  368. package/dist/apps/shared/components/calendar/eventFormat.d.ts +1 -1
  369. package/dist/apps/shared/components/calendar/eventFormat.js +2 -2
  370. package/dist/apps/shared/components/calendar/findTimeGrid.d.ts +1 -1
  371. package/dist/apps/shared/components/calendar/findTimeGrid.js +1 -1
  372. package/dist/apps/shared/components/calendar/layout/CalendarShell.d.ts +1 -1
  373. package/dist/apps/shared/components/calendar/layout/CalendarShell.js +11 -9
  374. package/dist/apps/shared/components/contacts/ContactDetailPane.d.ts +1 -1
  375. package/dist/apps/shared/components/contacts/ContactDetailPane.js +2 -2
  376. package/dist/apps/shared/components/contacts/ContactForm.d.ts +2 -2
  377. package/dist/apps/shared/components/contacts/ContactForm.js +12 -8
  378. package/dist/apps/shared/components/contacts/ContactsSidebar.d.ts +1 -1
  379. package/dist/apps/shared/components/contacts/ContactsSidebar.js +7 -5
  380. package/dist/apps/shared/components/contacts/KeyChangeReview.d.ts +1 -1
  381. package/dist/apps/shared/components/contacts/KeyChangeReview.js +5 -5
  382. package/dist/apps/shared/components/contacts/contactKeys.d.ts +2 -2
  383. package/dist/apps/shared/components/contacts/contactKeys.js +2 -2
  384. package/dist/apps/shared/components/contacts/layout/ContactsShell.d.ts +1 -1
  385. package/dist/apps/shared/components/contacts/layout/ContactsShell.js +9 -7
  386. package/dist/apps/shared/components/escrow/layout/EscrowShell.js +6 -6
  387. package/dist/apps/shared/components/forms/StringListField.js +1 -1
  388. package/dist/apps/shared/components/layout/AppShell.d.ts +2 -2
  389. package/dist/apps/shared/components/layout/AppShell.js +11 -9
  390. package/dist/apps/shared/components/layout/BrandingChrome.d.ts +1 -1
  391. package/dist/apps/shared/components/layout/KeyEnrollmentGate.d.ts +1 -1
  392. package/dist/apps/shared/components/layout/KeyEnrollmentGate.js +9 -9
  393. package/dist/apps/shared/components/layout/MailboxProvisioning.js +8 -6
  394. package/dist/apps/shared/components/layout/RecoveryCodeUnlock.d.ts +1 -1
  395. package/dist/apps/shared/components/layout/RecoveryCodeUnlock.js +9 -9
  396. package/dist/apps/shared/components/layout/UnlockPromptProvider.d.ts +2 -2
  397. package/dist/apps/shared/components/layout/UnlockPromptProvider.js +5 -5
  398. package/dist/apps/shared/components/layout/UserMenu.js +6 -4
  399. package/dist/apps/shared/components/mail/ConversationList.d.ts +2 -2
  400. package/dist/apps/shared/components/mail/ConversationList.js +6 -4
  401. package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +3 -3
  402. package/dist/apps/shared/components/mail/ConversationThreadPane.js +13 -11
  403. package/dist/apps/shared/components/mail/InviteCard.js +10 -8
  404. package/dist/apps/shared/components/mail/LazyReadingPane.js +2 -2
  405. package/dist/apps/shared/components/mail/MailAddress.d.ts +1 -1
  406. package/dist/apps/shared/components/mail/MailAddress.js +1 -1
  407. package/dist/apps/shared/components/mail/MailListToolbar.d.ts +2 -2
  408. package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +2 -2
  409. package/dist/apps/shared/components/mail/MenuButton.js +1 -1
  410. package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +3 -3
  411. package/dist/apps/shared/components/mail/MessageDetailPane.js +30 -28
  412. package/dist/apps/shared/components/mail/MoveToFolderDialog.d.ts +1 -1
  413. package/dist/apps/shared/components/mail/MoveToFolderDialog.js +8 -6
  414. package/dist/apps/shared/components/mail/OutboxRowStatus.d.ts +1 -1
  415. package/dist/apps/shared/components/mail/PermanentDeleteDialog.js +2 -2
  416. package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +10 -1
  417. package/dist/apps/shared/components/mail/compose/ComposeContext.js +4 -2
  418. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +34 -30
  419. package/dist/apps/shared/components/mail/compose/ComposeWindowPlaceholder.js +4 -4
  420. package/dist/apps/shared/components/mail/compose/EmojiPicker.js +2 -2
  421. package/dist/apps/shared/components/mail/compose/GifPicker.js +3 -3
  422. package/dist/apps/shared/components/mail/compose/RecipientInput.d.ts +1 -1
  423. package/dist/apps/shared/components/mail/compose/RecipientInput.js +1 -1
  424. package/dist/apps/shared/components/mail/compose/ScheduleSendPicker.js +1 -1
  425. package/dist/apps/shared/components/mail/compose/encryptionRequirement.d.ts +2 -2
  426. package/dist/apps/shared/components/mail/compose/encryptionRequirement.js +1 -1
  427. package/dist/apps/shared/components/mail/compose/quotedBody.d.ts +3 -3
  428. package/dist/apps/shared/components/mail/compose/quotedBody.js +3 -3
  429. package/dist/apps/shared/components/mail/compose/recipients.d.ts +1 -1
  430. package/dist/apps/shared/components/mail/invite/InviteRowChip.d.ts +1 -1
  431. package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.d.ts +1 -1
  432. package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.js +9 -7
  433. package/dist/apps/shared/components/mail/invite/InviteTimeline.d.ts +1 -1
  434. package/dist/apps/shared/components/mail/invite/ProposeTimeForm.d.ts +1 -1
  435. package/dist/apps/shared/components/mail/invite/ProposeTimeForm.js +1 -1
  436. package/dist/apps/shared/components/mail/invite/inviteFormat.d.ts +2 -2
  437. package/dist/apps/shared/components/mail/invite/inviteStore.d.ts +9 -3
  438. package/dist/apps/shared/components/mail/invite/inviteStore.js +13 -6
  439. package/dist/apps/shared/components/mail/labelMenu.d.ts +1 -1
  440. package/dist/apps/shared/components/mail/labelMenu.js +9 -7
  441. package/dist/apps/shared/components/mail/layout/MailShell.d.ts +1 -1
  442. package/dist/apps/shared/components/mail/layout/MailShell.js +3 -3
  443. package/dist/apps/shared/components/mail/listPreferences.d.ts +2 -2
  444. package/dist/apps/shared/components/mail/listPreferences.js +1 -1
  445. package/dist/apps/shared/components/mail/pinnedSigners.d.ts +12 -5
  446. package/dist/apps/shared/components/mail/pinnedSigners.js +37 -18
  447. package/dist/apps/shared/components/mail/reading/EncryptedBody.js +2 -2
  448. package/dist/apps/shared/components/mail/reading/MessageBody.d.ts +2 -2
  449. package/dist/apps/shared/components/mail/reading/MessageBody.js +4 -4
  450. package/dist/apps/shared/components/mail/reading/MessageCard.d.ts +1 -1
  451. package/dist/apps/shared/components/mail/reading/MessageCard.js +2 -2
  452. package/dist/apps/shared/components/mail/reading/MessageSourceDialog.js +3 -3
  453. package/dist/apps/shared/components/mail/reading/PendingMessageCard.js +1 -1
  454. package/dist/apps/shared/components/mail/reading/bodyContent.d.ts +2 -2
  455. package/dist/apps/shared/components/mail/reading/bodyContent.js +2 -2
  456. package/dist/apps/shared/components/mail/reading/bodyHtml.js +1 -1
  457. package/dist/apps/shared/components/mail/reading/messageExport.js +1 -1
  458. package/dist/apps/shared/components/mail/reading/printMessage.d.ts +2 -2
  459. package/dist/apps/shared/components/mail/reading/useMessageActions.d.ts +1 -1
  460. package/dist/apps/shared/components/mail/reading/useMessageActions.js +18 -16
  461. package/dist/apps/shared/components/mail/unreadStyle.d.ts +1 -1
  462. package/dist/apps/shared/components/mail/verificationSeals.d.ts +27 -6
  463. package/dist/apps/shared/components/mail/verificationSeals.js +15 -11
  464. package/dist/apps/shared/components/mail/writableMailboxes.d.ts +8 -3
  465. package/dist/apps/shared/components/mail/writableMailboxes.js +12 -6
  466. package/dist/apps/shared/components/rules/RuleBuilder.js +1 -1
  467. package/dist/apps/shared/components/settings/SigningCertificateCard.d.ts +1 -1
  468. package/dist/apps/shared/components/settings/SigningCertificateCard.js +3 -3
  469. package/dist/apps/shared/components/settings/layout/SettingsShell.d.ts +1 -1
  470. package/dist/apps/shared/components/settings/layout/SettingsShell.js +8 -6
  471. package/dist/apps/shared/components/sharing/PrincipalListField.d.ts +1 -1
  472. package/dist/apps/shared/components/sharing/PrincipalPicker.d.ts +1 -1
  473. package/dist/apps/shared/components/sharing/PrincipalPicker.js +1 -1
  474. package/dist/apps/shared/components/sharing/PrincipalResolver.d.ts +1 -1
  475. package/dist/apps/shared/components/sharing/PrincipalResolver.js +3 -3
  476. package/dist/apps/shared/components/tasks/TasksSidebar.d.ts +1 -1
  477. package/dist/apps/shared/components/tasks/TasksSidebar.js +7 -5
  478. package/dist/apps/shared/components/tasks/layout/TasksShell.d.ts +1 -1
  479. package/dist/apps/shared/components/tasks/layout/TasksShell.js +9 -7
  480. package/dist/apps/shared/keyboard/ShortcutsDialog.js +1 -1
  481. package/dist/apps/shared/mail/findWellKnownFolderUid.d.ts +5 -3
  482. package/dist/apps/shared/mail/findWellKnownFolderUid.js +5 -4
  483. package/dist/apps/shared/mail/folderCounts.d.ts +1 -1
  484. package/dist/apps/shared/mail/folderCounts.js +6 -4
  485. package/dist/apps/shared/mail/folderOfType.d.ts +3 -2
  486. package/dist/apps/shared/mail/folderOfType.js +4 -4
  487. package/dist/apps/shared/mail/folderTree.d.ts +1 -1
  488. package/dist/apps/shared/mail/listSnapshots.d.ts +2 -2
  489. package/dist/apps/shared/mail/messageReadState.d.ts +4 -3
  490. package/dist/apps/shared/mail/messageReadState.js +5 -5
  491. package/dist/apps/shared/mail/newMailNotifications.d.ts +1 -1
  492. package/dist/apps/shared/mail/newMailNotifications.js +1 -1
  493. package/dist/apps/shared/mail/outbox/composeBridge.d.ts +2 -2
  494. package/dist/apps/shared/mail/outbox/outboxState.d.ts +1 -1
  495. package/dist/apps/shared/mail/outbox/outgoingReplies.d.ts +2 -2
  496. package/dist/apps/shared/mail/outbox/sendDecision.d.ts +2 -2
  497. package/dist/apps/shared/mail/outbox/sendDecision.js +1 -1
  498. package/dist/apps/shared/mail/outbox/sendJob.d.ts +10 -6
  499. package/dist/apps/shared/mail/outbox/sendJob.js +39 -35
  500. package/dist/apps/shared/mail/outbox/sendOutcomes.d.ts +6 -3
  501. package/dist/apps/shared/mail/outbox/sendOutcomes.js +19 -15
  502. package/dist/apps/shared/mail/outbox/useOutboxStatus.js +5 -3
  503. package/dist/apps/shared/mail/permanentDelete.d.ts +4 -3
  504. package/dist/apps/shared/mail/permanentDelete.js +8 -8
  505. package/dist/apps/shared/mail/primaryMailbox.d.ts +1 -1
  506. package/dist/apps/shared/mail/primaryMailbox.js +1 -1
  507. package/dist/apps/shared/mail/reportNotices.d.ts +1 -1
  508. package/dist/apps/shared/mail/senderBlocking.d.ts +5 -4
  509. package/dist/apps/shared/mail/senderBlocking.js +19 -16
  510. package/dist/apps/shared/mail/useMailConnection.d.ts +1 -1
  511. package/dist/apps/shared/mail/useMailConnection.js +12 -10
  512. package/dist/apps/shared/mail/useMailLiveUpdates.d.ts +2 -2
  513. package/dist/apps/shared/mail/useMailLiveUpdates.js +2 -2
  514. package/dist/apps/shared/mail/useMailboxUpdateAccess.d.ts +3 -2
  515. package/dist/apps/shared/mail/useMailboxUpdateAccess.js +31 -10
  516. package/dist/apps/shared/mail/useMarkMessageRead.d.ts +1 -1
  517. package/dist/apps/shared/mail/useMarkMessageRead.js +5 -3
  518. package/dist/apps/shared/mail/useNewMailNotifications.d.ts +1 -1
  519. package/dist/apps/shared/mail/usePermanentDelete.d.ts +1 -1
  520. package/dist/apps/shared/mail/usePermanentDelete.js +4 -2
  521. package/dist/apps/shared/navigation/pageTitle.d.ts +1 -1
  522. package/dist/apps/shared/notifications/NotificationCenter.js +1 -1
  523. package/dist/apps/shared/notifications/NotificationHistoryDialog.js +2 -2
  524. package/dist/apps/shared/notifications/apiErrors.js +2 -2
  525. package/dist/apps/shared/notifications/pushStatus.js +1 -1
  526. package/dist/apps/shared/notifications/systemErrors.js +1 -1
  527. package/dist/apps/shared/search/LocalIndexLifecycle.d.ts +2 -2
  528. package/dist/apps/shared/search/LocalIndexLifecycle.js +15 -10
  529. package/dist/apps/shared/search/crossMailboxSearch.d.ts +1 -1
  530. package/dist/apps/shared/search/crossMailboxSearch.js +2 -2
  531. package/dist/apps/shared/search/localIndexBuilder.d.ts +4 -3
  532. package/dist/apps/shared/search/localIndexBuilder.js +15 -12
  533. package/dist/apps/shared/search/localIndexKey.js +1 -1
  534. package/dist/apps/shared/search/localIndexRpcClient.d.ts +43 -31
  535. package/dist/apps/shared/search/localIndexRpcClient.js +113 -20
  536. package/dist/apps/shared/search/localIndexTransport.d.ts +77 -0
  537. package/dist/apps/shared/search/localIndexTransport.js +1 -0
  538. package/dist/apps/shared/search/localIndexWorker.d.ts +1 -1
  539. package/dist/apps/shared/search/searchTier2.d.ts +3 -3
  540. package/dist/apps/shared/signing/enrollmentTracker.d.ts +1 -1
  541. package/dist/apps/shared/signing/enrollmentTracker.js +3 -3
  542. package/dist/apps/shared/signing/enrollmentView.d.ts +1 -1
  543. package/dist/apps/shared/signing/signingInfo.d.ts +1 -1
  544. package/dist/apps/shared/signing/signingInfo.js +1 -1
  545. package/dist/apps/shared/signing/useSigningEnrollmentWatcher.d.ts +1 -1
  546. package/dist/apps/shared/signing/useSigningEnrollmentWatcher.js +5 -3
  547. package/dist/apps/shared/styles/app.css +14 -23
  548. package/dist/apps/www/_layout.d.ts +1 -1
  549. package/dist/apps/www/_layout.js +1 -1
  550. package/dist/apps/www/calendar/index.d.ts +1 -1
  551. package/dist/apps/www/calendar/index.js +20 -18
  552. package/dist/apps/www/contacts/[uid].d.ts +1 -1
  553. package/dist/apps/www/contacts/[uid].js +8 -6
  554. package/dist/apps/www/contacts/index.d.ts +1 -1
  555. package/dist/apps/www/contacts/index.js +19 -17
  556. package/dist/apps/www/index.d.ts +1 -1
  557. package/dist/apps/www/index.js +54 -50
  558. package/dist/apps/www/messages/[uid].d.ts +1 -1
  559. package/dist/apps/www/messages/[uid].js +11 -9
  560. package/dist/apps/www/settings/appearance/index.d.ts +1 -1
  561. package/dist/apps/www/settings/auto-reply/index.d.ts +1 -1
  562. package/dist/apps/www/settings/auto-reply/index.js +6 -4
  563. package/dist/apps/www/settings/blocked-senders/index.d.ts +1 -1
  564. package/dist/apps/www/settings/blocked-senders/index.js +6 -4
  565. package/dist/apps/www/settings/encryption/index.d.ts +1 -1
  566. package/dist/apps/www/settings/encryption/index.js +31 -29
  567. package/dist/apps/www/settings/filters/[uid].d.ts +1 -1
  568. package/dist/apps/www/settings/filters/[uid].js +11 -9
  569. package/dist/apps/www/settings/filters/_mailFilterRuleConfig.d.ts +2 -2
  570. package/dist/apps/www/settings/filters/index.d.ts +1 -1
  571. package/dist/apps/www/settings/filters/index.js +4 -4
  572. package/dist/apps/www/settings/filters/new/index.d.ts +1 -1
  573. package/dist/apps/www/settings/filters/new/index.js +10 -8
  574. package/dist/apps/www/settings/labels/index.d.ts +1 -1
  575. package/dist/apps/www/settings/labels/index.js +12 -10
  576. package/dist/apps/www/settings/privacy/index.d.ts +1 -1
  577. package/dist/apps/www/settings/privacy/index.js +18 -14
  578. package/dist/apps/www/settings/profile/index.d.ts +1 -1
  579. package/dist/apps/www/settings/profile/index.js +7 -5
  580. package/dist/apps/www/settings/read-receipts/index.d.ts +1 -1
  581. package/dist/apps/www/settings/read-receipts/index.js +5 -3
  582. package/dist/apps/www/settings/sharing/index.d.ts +1 -1
  583. package/dist/apps/www/settings/sharing/index.js +6 -6
  584. package/dist/apps/www/settings/signatures/[uid].d.ts +1 -1
  585. package/dist/apps/www/settings/signatures/[uid].js +5 -5
  586. package/dist/apps/www/settings/signatures/index.d.ts +1 -1
  587. package/dist/apps/www/settings/signatures/index.js +4 -4
  588. package/dist/apps/www/settings/signatures/new/index.d.ts +1 -1
  589. package/dist/apps/www/settings/signatures/new/index.js +4 -4
  590. package/dist/apps/www/settings/signatures/signatureDefaults.d.ts +1 -1
  591. package/dist/apps/www/settings/signatures/signatureDefaults.js +1 -1
  592. package/dist/apps/www/tasks/index.d.ts +1 -1
  593. package/dist/apps/www/tasks/index.js +17 -15
  594. package/dist/lib/admin/auditLogApi.d.ts +32 -0
  595. package/dist/lib/admin/auditLogApi.js +27 -0
  596. package/dist/lib/admin/distributionListsApi.d.ts +47 -0
  597. package/dist/lib/admin/distributionListsApi.js +34 -0
  598. package/dist/lib/admin/domainsApi.d.ts +75 -0
  599. package/dist/lib/admin/domainsApi.js +44 -0
  600. package/dist/lib/admin/escrowAccessRequestsApi.d.ts +79 -0
  601. package/dist/lib/admin/escrowAccessRequestsApi.js +46 -0
  602. package/dist/lib/admin/escrowAuditLogApi.d.ts +66 -0
  603. package/dist/lib/admin/escrowAuditLogApi.js +31 -0
  604. package/dist/lib/admin/escrowScopesApi.d.ts +78 -0
  605. package/dist/lib/admin/escrowScopesApi.js +50 -0
  606. package/dist/lib/admin/leftoverMailboxApi.d.ts +73 -0
  607. package/dist/lib/admin/leftoverMailboxApi.js +67 -0
  608. package/dist/lib/admin/mailboxPolicyApi.d.ts +27 -0
  609. package/dist/lib/admin/mailboxPolicyApi.js +21 -0
  610. package/dist/lib/admin/matterExportApi.d.ts +40 -0
  611. package/dist/lib/admin/matterExportApi.js +39 -0
  612. package/dist/lib/admin/matterSearchApi.d.ts +20 -0
  613. package/dist/lib/admin/matterSearchApi.js +27 -0
  614. package/dist/lib/admin/mattersApi.d.ts +56 -0
  615. package/dist/lib/admin/mattersApi.js +40 -0
  616. package/dist/lib/admin/pluginsApi.d.ts +265 -0
  617. package/dist/lib/admin/pluginsApi.js +102 -0
  618. package/dist/lib/admin/retentionPolicyApi.d.ts +32 -0
  619. package/dist/lib/admin/retentionPolicyApi.js +29 -0
  620. package/dist/lib/admin/setupApi.d.ts +23 -0
  621. package/dist/lib/admin/setupApi.js +26 -0
  622. package/dist/lib/admin/transportRulesApi.d.ts +66 -0
  623. package/dist/lib/admin/transportRulesApi.js +43 -0
  624. package/dist/lib/appearance/preferencesApi.d.ts +128 -0
  625. package/dist/lib/appearance/preferencesApi.js +257 -0
  626. package/dist/lib/auth/profileApi.d.ts +33 -0
  627. package/dist/lib/auth/profileApi.js +52 -0
  628. package/dist/lib/auth/session.d.ts +70 -0
  629. package/dist/lib/auth/session.js +210 -0
  630. package/dist/lib/branding/brandingApi.d.ts +47 -0
  631. package/dist/lib/branding/brandingApi.js +61 -0
  632. package/dist/lib/branding/useBranding.d.ts +23 -0
  633. package/dist/lib/branding/useBranding.js +65 -0
  634. package/dist/lib/calendar/calendarApi.d.ts +230 -0
  635. package/dist/lib/calendar/calendarApi.js +106 -0
  636. package/dist/lib/calendar/calendarColors.d.ts +18 -0
  637. package/dist/lib/calendar/calendarColors.js +39 -0
  638. package/dist/lib/calendar/calendarDragIds.d.ts +42 -0
  639. package/dist/lib/calendar/calendarDragIds.js +92 -0
  640. package/dist/lib/calendar/calendarMutations.d.ts +68 -0
  641. package/dist/lib/calendar/calendarMutations.js +190 -0
  642. package/dist/lib/calendar/eventDescription.d.ts +43 -0
  643. package/dist/lib/calendar/eventDescription.js +195 -0
  644. package/dist/lib/calendar/freeBusyApi.d.ts +100 -0
  645. package/dist/lib/calendar/freeBusyApi.js +119 -0
  646. package/dist/lib/calendar/inviteApi.d.ts +121 -0
  647. package/dist/lib/calendar/inviteApi.js +54 -0
  648. package/dist/lib/calendar/recurrence.d.ts +60 -0
  649. package/dist/lib/calendar/recurrence.js +225 -0
  650. package/dist/lib/components/avatar/ContactAvatar.d.ts +8 -0
  651. package/dist/lib/components/avatar/ContactAvatar.js +26 -0
  652. package/dist/lib/components/buttons/Button.d.ts +9 -0
  653. package/dist/lib/components/buttons/Button.js +14 -0
  654. package/dist/lib/components/buttons/CopyButton.d.ts +18 -0
  655. package/dist/lib/components/buttons/CopyButton.js +14 -0
  656. package/dist/lib/components/feedback/Alert.d.ts +4 -0
  657. package/dist/lib/components/feedback/Alert.js +4 -0
  658. package/dist/lib/components/feedback/Skeleton.d.ts +21 -0
  659. package/dist/lib/components/feedback/Skeleton.js +14 -0
  660. package/dist/lib/components/forms/FormField.d.ts +8 -0
  661. package/dist/lib/components/forms/FormField.js +5 -0
  662. package/dist/lib/components/navigation/BottomTabBar.d.ts +27 -0
  663. package/dist/lib/components/navigation/BottomTabBar.js +32 -0
  664. package/dist/lib/components/overlays/Drawer.d.ts +20 -0
  665. package/dist/lib/components/overlays/Drawer.js +27 -0
  666. package/dist/lib/components/overlays/Modal.d.ts +17 -0
  667. package/dist/lib/components/overlays/Modal.js +25 -0
  668. package/dist/lib/components/overlays/PopoverPortal.d.ts +23 -0
  669. package/dist/lib/components/overlays/PopoverPortal.js +53 -0
  670. package/dist/lib/components/overlays/overlayStack.d.ts +31 -0
  671. package/dist/lib/components/overlays/overlayStack.js +143 -0
  672. package/dist/lib/components/pickers/MiniDatePicker.d.ts +13 -0
  673. package/dist/lib/components/pickers/MiniDatePicker.js +42 -0
  674. package/dist/lib/contacts/contactsApi.d.ts +174 -0
  675. package/dist/lib/contacts/contactsApi.js +139 -0
  676. package/dist/lib/contacts/vcard.d.ts +23 -0
  677. package/dist/lib/contacts/vcard.js +179 -0
  678. package/dist/lib/crypto/composeSecurity.d.ts +67 -0
  679. package/dist/lib/crypto/composeSecurity.js +93 -0
  680. package/dist/lib/crypto/encoding.d.ts +9 -0
  681. package/dist/lib/crypto/encoding.js +32 -0
  682. package/dist/lib/crypto/escrowKeys.d.ts +25 -0
  683. package/dist/lib/crypto/escrowKeys.js +59 -0
  684. package/dist/lib/crypto/idleTimeout.d.ts +16 -0
  685. package/dist/lib/crypto/idleTimeout.js +47 -0
  686. package/dist/lib/crypto/keySession.d.ts +159 -0
  687. package/dist/lib/crypto/keySession.js +367 -0
  688. package/dist/lib/crypto/keys.d.ts +50 -0
  689. package/dist/lib/crypto/keys.js +89 -0
  690. package/dist/lib/crypto/keyvaultApi.d.ts +394 -0
  691. package/dist/lib/crypto/keyvaultApi.js +350 -0
  692. package/dist/lib/crypto/masterKey.d.ts +59 -0
  693. package/dist/lib/crypto/masterKey.js +104 -0
  694. package/dist/lib/crypto/masterKeyWraps.d.ts +108 -0
  695. package/dist/lib/crypto/masterKeyWraps.js +228 -0
  696. package/dist/lib/crypto/messageSecurity.d.ts +248 -0
  697. package/dist/lib/crypto/messageSecurity.js +367 -0
  698. package/dist/lib/crypto/mime.d.ts +143 -0
  699. package/dist/lib/crypto/mime.js +504 -0
  700. package/dist/lib/crypto/passkeyUnlock.d.ts +20 -0
  701. package/dist/lib/crypto/passkeyUnlock.js +79 -0
  702. package/dist/lib/crypto/passwordUnlock.d.ts +39 -0
  703. package/dist/lib/crypto/passwordUnlock.js +73 -0
  704. package/dist/lib/crypto/recoveryCode.d.ts +28 -0
  705. package/dist/lib/crypto/recoveryCode.js +86 -0
  706. package/dist/lib/crypto/signingProviderApi.d.ts +95 -0
  707. package/dist/lib/crypto/signingProviderApi.js +60 -0
  708. package/dist/lib/crypto/smime.d.ts +128 -0
  709. package/dist/lib/crypto/smime.js +402 -0
  710. package/dist/lib/crypto/smimeMessage.d.ts +132 -0
  711. package/dist/lib/crypto/smimeMessage.js +341 -0
  712. package/dist/lib/crypto/useIdleKeyTimeout.d.ts +10 -0
  713. package/dist/lib/crypto/useIdleKeyTimeout.js +163 -0
  714. package/dist/lib/crypto/verificationSeal.d.ts +56 -0
  715. package/dist/lib/crypto/verificationSeal.js +220 -0
  716. package/dist/lib/mail/compose/composeQuoting.d.ts +88 -0
  717. package/dist/lib/mail/compose/composeQuoting.js +204 -0
  718. package/dist/lib/mail/compose/emojiData.d.ts +9 -0
  719. package/dist/lib/mail/compose/emojiData.js +18 -0
  720. package/dist/lib/mail/compose/giphyApi.d.ts +17 -0
  721. package/dist/lib/mail/compose/giphyApi.js +20 -0
  722. package/dist/lib/mail/conversationsApi.d.ts +80 -0
  723. package/dist/lib/mail/conversationsApi.js +44 -0
  724. package/dist/lib/mail/dataExportApi.d.ts +50 -0
  725. package/dist/lib/mail/dataExportApi.js +40 -0
  726. package/dist/lib/mail/directoryApi.d.ts +49 -0
  727. package/dist/lib/mail/directoryApi.js +101 -0
  728. package/dist/lib/mail/erasureRequestApi.d.ts +45 -0
  729. package/dist/lib/mail/erasureRequestApi.js +43 -0
  730. package/dist/lib/mail/flaggedMessages.d.ts +22 -0
  731. package/dist/lib/mail/flaggedMessages.js +73 -0
  732. package/dist/lib/mail/focusedInboxOverridesApi.d.ts +37 -0
  733. package/dist/lib/mail/focusedInboxOverridesApi.js +34 -0
  734. package/dist/lib/mail/labelsApi.d.ts +47 -0
  735. package/dist/lib/mail/labelsApi.js +38 -0
  736. package/dist/lib/mail/mailAddress.d.ts +27 -0
  737. package/dist/lib/mail/mailAddress.js +54 -0
  738. package/dist/lib/mail/mailApi.d.ts +850 -0
  739. package/dist/lib/mail/mailApi.js +602 -0
  740. package/dist/lib/mail/mailDetailHooks.d.ts +10 -0
  741. package/dist/lib/mail/mailDetailHooks.js +53 -0
  742. package/dist/lib/mail/mailFilterRulesApi.d.ts +76 -0
  743. package/dist/lib/mail/mailFilterRulesApi.js +45 -0
  744. package/dist/lib/mail/mailSignaturesApi.d.ts +49 -0
  745. package/dist/lib/mail/mailSignaturesApi.js +42 -0
  746. package/dist/lib/mail/mailboxAccessApi.d.ts +74 -0
  747. package/dist/lib/mail/mailboxAccessApi.js +56 -0
  748. package/dist/lib/mail/mailboxImportApi.d.ts +53 -0
  749. package/dist/lib/mail/mailboxImportApi.js +51 -0
  750. package/dist/lib/mail/messageBodySanitizer.d.ts +16 -0
  751. package/dist/lib/mail/messageBodySanitizer.js +118 -0
  752. package/dist/lib/mail/pushClient.d.ts +106 -0
  753. package/dist/lib/mail/pushClient.js +317 -0
  754. package/dist/lib/mail/sendEvents.d.ts +33 -0
  755. package/dist/lib/mail/sendEvents.js +44 -0
  756. package/dist/lib/mail/sendFailure.d.ts +16 -0
  757. package/dist/lib/mail/sendFailure.js +86 -0
  758. package/dist/lib/mail/senderListsApi.d.ts +69 -0
  759. package/dist/lib/mail/senderListsApi.js +126 -0
  760. package/dist/lib/search/queryGrammar.d.ts +51 -0
  761. package/dist/lib/search/queryGrammar.js +111 -0
  762. package/dist/lib/search/searchApi.d.ts +100 -0
  763. package/dist/lib/search/searchApi.js +107 -0
  764. package/dist/lib/search/searchScoring.d.ts +34 -0
  765. package/dist/lib/search/searchScoring.js +44 -0
  766. package/dist/lib/search/searchTier3.d.ts +64 -0
  767. package/dist/lib/search/searchTier3.js +335 -0
  768. package/dist/lib/tasks/tasksApi.d.ts +85 -0
  769. package/dist/lib/tasks/tasksApi.js +55 -0
  770. package/dist/lib/util/api.d.ts +160 -0
  771. package/dist/lib/util/api.js +251 -0
  772. package/dist/lib/util/apiClientContext.d.ts +7 -0
  773. package/dist/lib/util/apiClientContext.js +32 -0
  774. package/dist/lib/util/apiQuery.d.ts +32 -0
  775. package/dist/lib/util/apiQuery.js +42 -0
  776. package/dist/lib/util/clipboard.d.ts +7 -0
  777. package/dist/lib/util/clipboard.js +56 -0
  778. package/dist/lib/util/dateInput.d.ts +6 -0
  779. package/dist/lib/util/dateInput.js +14 -0
  780. package/dist/lib/util/timeZone.d.ts +12 -0
  781. package/dist/lib/util/timeZone.js +32 -0
  782. package/dist/lib/util/useCopyToClipboard.d.ts +12 -0
  783. package/dist/lib/util/useCopyToClipboard.js +34 -0
  784. package/dist/lib/util/useIsMobile.d.ts +10 -0
  785. package/dist/lib/util/useIsMobile.js +29 -0
  786. package/dist/lib/videoconf/videoMeetingsApi.d.ts +116 -0
  787. package/dist/lib/videoconf/videoMeetingsApi.js +49 -0
  788. package/lib/admin/auditLogApi.ts +48 -0
  789. package/lib/admin/distributionListsApi.ts +77 -0
  790. package/lib/admin/domainsApi.ts +113 -0
  791. package/lib/admin/escrowAccessRequestsApi.ts +110 -0
  792. package/lib/admin/escrowAuditLogApi.ts +101 -0
  793. package/lib/admin/escrowScopesApi.ts +112 -0
  794. package/lib/admin/leftoverMailboxApi.ts +120 -0
  795. package/lib/admin/mailboxPolicyApi.ts +38 -0
  796. package/lib/admin/matterExportApi.ts +62 -0
  797. package/lib/admin/matterSearchApi.ts +35 -0
  798. package/lib/admin/mattersApi.ts +86 -0
  799. package/lib/admin/pluginsApi.ts +339 -0
  800. package/lib/admin/retentionPolicyApi.ts +46 -0
  801. package/lib/admin/setupApi.ts +40 -0
  802. package/lib/admin/transportRulesApi.ts +106 -0
  803. package/lib/appearance/preferencesApi.ts +335 -0
  804. package/lib/auth/profileApi.ts +77 -0
  805. package/lib/auth/session.ts +238 -0
  806. package/lib/branding/brandingApi.ts +97 -0
  807. package/lib/branding/useBranding.ts +81 -0
  808. package/lib/calendar/calendarApi.ts +309 -0
  809. package/lib/calendar/calendarColors.ts +45 -0
  810. package/lib/calendar/calendarDragIds.ts +112 -0
  811. package/lib/calendar/calendarMutations.ts +236 -0
  812. package/lib/calendar/eventDescription.ts +211 -0
  813. package/lib/calendar/freeBusyApi.ts +197 -0
  814. package/lib/calendar/inviteApi.ts +154 -0
  815. package/lib/calendar/recurrence.ts +285 -0
  816. package/lib/components/avatar/ContactAvatar.tsx +47 -0
  817. package/lib/components/buttons/Button.tsx +40 -0
  818. package/lib/components/buttons/CopyButton.tsx +45 -0
  819. package/lib/components/feedback/Alert.tsx +13 -0
  820. package/lib/components/feedback/Skeleton.tsx +38 -0
  821. package/lib/components/forms/FormField.tsx +23 -0
  822. package/lib/components/navigation/BottomTabBar.tsx +66 -0
  823. package/lib/components/overlays/Drawer.tsx +72 -0
  824. package/lib/components/overlays/Modal.tsx +64 -0
  825. package/lib/components/overlays/PopoverPortal.tsx +74 -0
  826. package/lib/components/overlays/overlayStack.ts +165 -0
  827. package/lib/components/pickers/MiniDatePicker.tsx +90 -0
  828. package/lib/contacts/contactsApi.ts +289 -0
  829. package/lib/contacts/vcard.ts +197 -0
  830. package/lib/crypto/composeSecurity.ts +140 -0
  831. package/lib/crypto/encoding.ts +36 -0
  832. package/lib/crypto/escrowKeys.ts +74 -0
  833. package/lib/crypto/idleTimeout.ts +49 -0
  834. package/lib/crypto/keySession.ts +483 -0
  835. package/lib/crypto/keys.ts +105 -0
  836. package/lib/crypto/keyvaultApi.ts +674 -0
  837. package/lib/crypto/masterKey.ts +134 -0
  838. package/lib/crypto/masterKeyWraps.ts +269 -0
  839. package/lib/crypto/messageSecurity.ts +600 -0
  840. package/lib/crypto/mime.ts +568 -0
  841. package/lib/crypto/passkeyUnlock.ts +103 -0
  842. package/lib/crypto/passwordUnlock.ts +98 -0
  843. package/lib/crypto/recoveryCode.ts +93 -0
  844. package/lib/crypto/signingProviderApi.ts +135 -0
  845. package/lib/crypto/smime.ts +459 -0
  846. package/lib/crypto/smimeMessage.ts +491 -0
  847. package/lib/crypto/useIdleKeyTimeout.ts +176 -0
  848. package/lib/crypto/verificationSeal.ts +288 -0
  849. package/lib/mail/compose/composeQuoting.ts +243 -0
  850. package/lib/mail/compose/emojiData.ts +34 -0
  851. package/lib/mail/compose/giphyApi.ts +31 -0
  852. package/lib/mail/conversationsApi.ts +123 -0
  853. package/lib/mail/dataExportApi.ts +73 -0
  854. package/lib/mail/directoryApi.ts +161 -0
  855. package/lib/mail/erasureRequestApi.ts +71 -0
  856. package/lib/mail/flaggedMessages.ts +80 -0
  857. package/lib/mail/focusedInboxOverridesApi.ts +64 -0
  858. package/lib/mail/labelsApi.ts +71 -0
  859. package/lib/mail/mailAddress.ts +76 -0
  860. package/lib/mail/mailApi.ts +1286 -0
  861. package/lib/mail/mailDetailHooks.ts +57 -0
  862. package/lib/mail/mailFilterRulesApi.ts +116 -0
  863. package/lib/mail/mailSignaturesApi.ts +84 -0
  864. package/lib/mail/mailboxAccessApi.ts +106 -0
  865. package/lib/mail/mailboxImportApi.ts +87 -0
  866. package/lib/mail/messageBodySanitizer.ts +129 -0
  867. package/lib/mail/pushClient.ts +375 -0
  868. package/lib/mail/sendEvents.ts +72 -0
  869. package/lib/mail/sendFailure.ts +98 -0
  870. package/lib/mail/senderListsApi.ts +161 -0
  871. package/lib/search/queryGrammar.ts +179 -0
  872. package/lib/search/searchApi.ts +199 -0
  873. package/lib/search/searchScoring.ts +46 -0
  874. package/lib/search/searchTier3.ts +406 -0
  875. package/lib/tasks/tasksApi.ts +128 -0
  876. package/lib/util/api.ts +318 -0
  877. package/lib/util/apiClientContext.ts +35 -0
  878. package/lib/util/apiQuery.ts +61 -0
  879. package/lib/util/clipboard.ts +55 -0
  880. package/lib/util/dateInput.ts +15 -0
  881. package/lib/util/timeZone.ts +33 -0
  882. package/lib/util/useCopyToClipboard.ts +48 -0
  883. package/lib/util/useIsMobile.ts +34 -0
  884. package/lib/videoconf/videoMeetingsApi.ts +144 -0
  885. package/package.json +10 -4
@@ -0,0 +1,289 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /** Typed wrappers over `@rapidmx/restapi`'s `/mail/contacts` REST surface — see `mailApi.ts`'s own header
6
+ * comment for the shared ACL/authorization model every wrapper file here follows. */
7
+
8
+ import { ApiClient, withClient } from "../util/api.js";
9
+ import { ListParams, buildQuery } from "../util/apiQuery.js";
10
+ import {
11
+ type EncryptionPreference,
12
+ type KeyConflict,
13
+ type PreviousKey,
14
+ type PublicKey,
15
+ type RejectedKey,
16
+ signingKeyFingerprints,
17
+ } from "../crypto/keyvaultApi.js";
18
+
19
+ export type ContactAddressKind = "home" | "work" | "other";
20
+
21
+ export interface ContactEmail {
22
+ address: string;
23
+ type: ContactAddressKind;
24
+ }
25
+
26
+ export interface ContactPhone {
27
+ phoneNumber: string;
28
+ type: ContactAddressKind;
29
+ }
30
+
31
+ export interface ContactPostalAddress {
32
+ street?: string;
33
+ city?: string;
34
+ state?: string;
35
+ postalCode?: string;
36
+ country?: string;
37
+ type: ContactAddressKind;
38
+ }
39
+
40
+ export interface Contact {
41
+ uid: string;
42
+ version: number;
43
+ dateCreated: string;
44
+ dateModified: string;
45
+ mailboxUid: string;
46
+ folderUid: string;
47
+ /** The `ContactList` (group) this contact belongs to, if any. */
48
+ contactListUid?: string;
49
+ displayName: string;
50
+ givenName?: string;
51
+ surname?: string;
52
+ emails: ContactEmail[];
53
+ phones: ContactPhone[];
54
+ addresses: ContactPostalAddress[];
55
+ company?: string;
56
+ jobTitle?: string;
57
+ notes?: string;
58
+ photoBlobKey?: string;
59
+ sourceUid?: string;
60
+ /** Whether the caller has starred/favorited this contact. Absent is equivalent to `false`. */
61
+ favorite?: boolean;
62
+ /** Free-form category labels (Outlook-style colored categories) applied to this contact, if any. */
63
+ categories?: string[];
64
+ /** Present (and `true`) only when fetched via `listDeletedContacts()` — a soft-deleted `RecoverableBaseEntity`
65
+ * record still exists server-side so it can be restored, per `@rapidmx/restapi`'s own soft-delete model. */
66
+ deleted?: boolean;
67
+ /** This contact's known encryption preference, per `specs/end-to-end_encryption.md` — discovered
68
+ * via `crypto/keyvaultApi.ts`'s `lookupKeys()` at compose time, never fetched on message receipt
69
+ * (that would leak read timing to the sender's server). */
70
+ encryptPreference?: EncryptionPreference;
71
+ /** This contact's pinned public keys. Trust is TOFU (trust-on-first-use) — see `keyConflicts` for what
72
+ * happens when a newly observed key differs from one of these. */
73
+ keys?: PublicKey[];
74
+ /** Observed keys that conflict with the currently pinned key of the same `useType`, at most one per `useType` —
75
+ * each blocks silent acceptance until the user resolves it (`keyvaultApi.ts`'s `resolveKeyConflict()`, the spec's
76
+ * Key Conflict Handling). The pinned `keys` are retained unchanged while a conflict is set. */
77
+ keyConflicts?: KeyConflict[];
78
+ /** Keys that were pinned before and replaced (by the user accepting a conflict, or by restapi's automatic
79
+ * same-issuer renewal of an expired or revoked key), newest first, at most 5 per `useType`. Signing keys here
80
+ * still count as trusted signers — see `signingKeyFingerprints()`. */
81
+ previousKeys?: PreviousKey[];
82
+ /** Keys the user rejected when resolving a conflict. */
83
+ rejectedKeys?: RejectedKey[];
84
+ }
85
+
86
+ /** Lists a folder's contacts, alphabetically by display name. Never includes soft-deleted contacts — see
87
+ * `listDeletedContacts()` for those. */
88
+ export function listContacts(folderUid: string, params: ListParams = {}, client?: ApiClient): Promise<Contact[]> {
89
+ return withClient(client, `/mail/contacts?${buildQuery(params, { folderUid, sort: JSON.stringify({ displayName: "ASC" }) })}`);
90
+ }
91
+
92
+ function contactsMatching(contacts: Contact[], address: string): Contact[] {
93
+ const wanted = address.trim().toLowerCase();
94
+ return contacts.filter((contact) => contact.emails.some((email) => email.address.trim().toLowerCase() === wanted));
95
+ }
96
+
97
+ /** The trusted signing-key fingerprints of every contact in `contacts` with an email equal (case-insensitively) to
98
+ * `address`: each contact's pinned `keys` and its `previousKeys`, so mail signed before a key rotation still verifies -
99
+ * see `keyvaultApi.ts`'s `signingKeyFingerprints()` for the rules (expired and superseded keys kept, compromised or reasonless revoked keys excluded). De-duplicated;
100
+ * `[]` when no contact matches or none has a trusted signing key. */
101
+ export function pinnedSigningFingerprintsFor(contacts: Contact[], address: string): string[] {
102
+ return [...new Set(contactsMatching(contacts, address).flatMap((contact) => signingKeyFingerprints(contact.keys, contact.previousKeys)))];
103
+ }
104
+
105
+ /** Page size and page cap for `fetchPinnedSigningFingerprints()` and `fetchSignerKeyState()` (500 is restapi's own
106
+ * `limit` cap). */
107
+ export const PINNED_FINGERPRINT_PAGE_SIZE = 500;
108
+ export const PINNED_FINGERPRINT_MAX_PAGES = 20;
109
+
110
+ /** Every contact in `folderUids`, paged (`PINNED_FINGERPRINT_PAGE_SIZE`, at most `PINNED_FINGERPRINT_MAX_PAGES` pages
111
+ * per folder). A plain contacts read - never a Discovery lookup. */
112
+ async function listContactsInFolders(folderUids: string[], client?: ApiClient): Promise<Contact[]> {
113
+ const contacts: Contact[] = [];
114
+ for (const folderUid of folderUids) {
115
+ for (let page = 0; page < PINNED_FINGERPRINT_MAX_PAGES; page++) {
116
+ const batch = await listContacts(folderUid, { limit: PINNED_FINGERPRINT_PAGE_SIZE, page }, client);
117
+ contacts.push(...batch);
118
+ if (batch.length < PINNED_FINGERPRINT_PAGE_SIZE) {
119
+ break;
120
+ }
121
+ }
122
+ }
123
+ return contacts;
124
+ }
125
+
126
+ /**
127
+ * Fetches the trusted signing-key fingerprints (pinned and previous - see `pinnedSigningFingerprintsFor()`) for a
128
+ * message sender's `address` from the contacts in `folderUids` (the reader's contacts folders), for
129
+ * `evaluateMessageSecurity()`'s `pinnedSignerFingerprints`. Reads only what is already stored on the reader's own
130
+ * contacts - never triggers a Discovery lookup, which must not happen on message receipt (it would leak read timing to
131
+ * the sender's server). Pages through each folder (`PINNED_FINGERPRINT_PAGE_SIZE`, at most
132
+ * `PINNED_FINGERPRINT_MAX_PAGES` pages per folder). A caller rendering many messages should cache the contact list and
133
+ * use `pinnedSigningFingerprintsFor()` instead.
134
+ */
135
+ export async function fetchPinnedSigningFingerprints(folderUids: string[], address: string, client?: ApiClient): Promise<string[]> {
136
+ return pinnedSigningFingerprintsFor(await listContactsInFolders(folderUids, client), address);
137
+ }
138
+
139
+ /** A sender's stored signing-key state, for a key-changed comparison - see `signerKeyStateFor()`. */
140
+ export interface SignerKeyState {
141
+ /** The currently pinned signing keys (every `useType: "sign"` key, revoked and expired ones included, so a UI can
142
+ * show their dates and status), de-duplicated by fingerprint. */
143
+ pinned: PublicKey[];
144
+ /** Previously pinned signing keys, newest `replacedAt` first, de-duplicated by fingerprint. */
145
+ previous: PreviousKey[];
146
+ /** The first unresolved signing-key conflict found, if any. */
147
+ conflict?: KeyConflict;
148
+ }
149
+
150
+ function uniqueByFingerprint<T extends PublicKey>(keys: T[]): T[] {
151
+ const seen = new Set<string>();
152
+ return keys.filter((key) => {
153
+ const fingerprint = key.fingerprint.toLowerCase();
154
+ if (seen.has(fingerprint)) {
155
+ return false;
156
+ }
157
+ seen.add(fingerprint);
158
+ return true;
159
+ });
160
+ }
161
+
162
+ /** The signing-key state of every contact in `contacts` with an email equal (case-insensitively) to `address`, merged -
163
+ * what a UI needs to compare a `signer_key_changed` message's certificate with the pinned and previous keys (their
164
+ * fingerprints and `notBefore`/`notAfter`/`revokedAt`/`replacedAt` dates) before calling `resolveKeyConflict()`. Empty
165
+ * `pinned`/`previous` and no `conflict` when no contact matches. */
166
+ export function signerKeyStateFor(contacts: Contact[], address: string): SignerKeyState {
167
+ const matching = contactsMatching(contacts, address);
168
+ const pinned = uniqueByFingerprint(matching.flatMap((contact) => (contact.keys ?? []).filter((key) => key.useType === "sign")));
169
+ const previous = uniqueByFingerprint(
170
+ matching.flatMap((contact) => (contact.previousKeys ?? []).filter((key) => key.useType === "sign")).sort((a, b) => b.replacedAt - a.replacedAt),
171
+ );
172
+ const conflict = matching.flatMap((contact) => contact.keyConflicts ?? []).find((entry) => entry.useType === "sign");
173
+ return { pinned, previous, ...(conflict ? { conflict } : {}) };
174
+ }
175
+
176
+ /** Fetches `signerKeyStateFor()` for `address` from the contacts in `folderUids`, paging exactly like
177
+ * `fetchPinnedSigningFingerprints()`. Reads only stored contacts - never triggers a Discovery lookup. */
178
+ export async function fetchSignerKeyState(folderUids: string[], address: string, client?: ApiClient): Promise<SignerKeyState> {
179
+ return signerKeyStateFor(await listContactsInFolders(folderUids, client), address);
180
+ }
181
+
182
+ /**
183
+ * Lists a folder's soft-deleted contacts
184
+ (for an Outlook-style "Deleted" view) — `deleted` is an ordinary
185
+ * queryable field on `Contact` (a `RecoverableBaseEntity`), so this is the same `find()` the plain listing
186
+ * above uses, just constrained to `deleted: true` instead of the framework's own default of excluding them.
187
+ *
188
+ * Read-only for now — deliberately no `restoreContact()`: `@rapidmx/restapi`'s generic
189
+ * `BaseScopedChildRoute.update()` looks the target record up via a plain `findOne()` with no
190
+ * `includeDeleted` option, so it 404s on an already-deleted record before ever reaching the point where
191
+ * setting `deleted: false` would matter. Restoring would need a real fix in `@rapidmx/restapi` itself
192
+ * (passing `includeDeleted: true` into that lookup) — out of scope for this pass; the "Deleted" view here
193
+ * is browse-only until that lands.
194
+ */
195
+ export function listDeletedContacts(folderUid: string, params: ListParams = {}, client?: ApiClient): Promise<Contact[]> {
196
+ return withClient(
197
+ client,
198
+ `/mail/contacts?${buildQuery(params, { folderUid, deleted: "true", sort: JSON.stringify({ displayName: "ASC" }) })}`,
199
+ );
200
+ }
201
+
202
+ export function getContact(uid: string, client?: ApiClient): Promise<Contact> {
203
+ return withClient(client, `/mail/contacts/${encodeURIComponent(uid)}`);
204
+ }
205
+
206
+ export interface ContactInput {
207
+ mailboxUid: string;
208
+ folderUid: string;
209
+ contactListUid?: string;
210
+ displayName: string;
211
+ givenName?: string;
212
+ surname?: string;
213
+ emails?: ContactEmail[];
214
+ phones?: ContactPhone[];
215
+ addresses?: ContactPostalAddress[];
216
+ company?: string;
217
+ jobTitle?: string;
218
+ notes?: string;
219
+ favorite?: boolean;
220
+ categories?: string[];
221
+ }
222
+
223
+ export function createContact(input: ContactInput, client?: ApiClient): Promise<Contact> {
224
+ return withClient(client, "/mail/contacts", {
225
+ method: "POST",
226
+ body: JSON.stringify({ emails: [], phones: [], addresses: [], ...input }),
227
+ });
228
+ }
229
+
230
+ export interface UpdateContactInput extends ContactInput {
231
+ uid: string;
232
+ version: number;
233
+ }
234
+
235
+ /** A minimal contact update: only `uid`/`version` are required, every other field is sent only if
236
+ * present. The server merges just the fields in the body and rejects server-managed ones
237
+ * (`dateCreated`/`dateModified`/etc.), so prefer sending only what actually changed over a whole
238
+ * fetched `Contact`. An `UpdateContactInput` is also a valid `ContactPatch`. */
239
+ export type ContactPatch = Partial<Contact> & Pick<Contact, "uid" | "version">;
240
+
241
+ export function updateContact(patch: ContactPatch, client?: ApiClient): Promise<Contact> {
242
+ return withClient(client, `/mail/contacts/${encodeURIComponent(patch.uid)}`, {
243
+ method: "PUT",
244
+ body: JSON.stringify(patch),
245
+ });
246
+ }
247
+
248
+ /** Thin `updateContact()` wrapper for toggling favorite/star status — same pattern as `mailApi.ts`'s
249
+ * `setMessageRead()`/`tasksApi.ts`'s `setTaskCompleted()`. Sends only `uid`/`version`/`favorite`, never
250
+ * the rest of `contact` (the server rejects its managed fields). */
251
+ export function setContactFavorite(contact: Contact, favorite: boolean, client?: ApiClient): Promise<Contact> {
252
+ return updateContact({ uid: contact.uid, version: contact.version, favorite }, client);
253
+ }
254
+
255
+ export function deleteContact(uid: string, version: number, client?: ApiClient): Promise<void> {
256
+ return withClient(client, `/mail/contacts/${encodeURIComponent(uid)}?version=${version}`, { method: "DELETE" });
257
+ }
258
+
259
+ export interface ContactList {
260
+ uid: string;
261
+ version: number;
262
+ dateCreated: string;
263
+ dateModified: string;
264
+ mailboxUid: string;
265
+ name: string;
266
+ }
267
+
268
+ /** Lists a mailbox's contact lists (Outlook-style "Your contact lists"), alphabetically by name. */
269
+ export function listContactLists(mailboxUid: string, params: ListParams = {}, client?: ApiClient): Promise<ContactList[]> {
270
+ return withClient(client, `/mail/contact-lists?${buildQuery(params, { mailboxUid, sort: JSON.stringify({ name: "ASC" }) })}`);
271
+ }
272
+
273
+ export function createContactList(input: { mailboxUid: string; name: string }, client?: ApiClient): Promise<ContactList> {
274
+ return withClient(client, "/mail/contact-lists", { method: "POST", body: JSON.stringify(input) });
275
+ }
276
+
277
+ export function updateContactList(
278
+ input: { uid: string; version: number; name: string },
279
+ client?: ApiClient,
280
+ ): Promise<ContactList> {
281
+ return withClient(client, `/mail/contact-lists/${encodeURIComponent(input.uid)}`, {
282
+ method: "PUT",
283
+ body: JSON.stringify(input),
284
+ });
285
+ }
286
+
287
+ export function deleteContactList(uid: string, version: number, client?: ApiClient): Promise<void> {
288
+ return withClient(client, `/mail/contact-lists/${encodeURIComponent(uid)}?version=${version}`, { method: "DELETE" });
289
+ }
@@ -0,0 +1,197 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * Pure client-side vCard 3.0 generate/parse — `@rapidmx/restapi` has no vCard import/export support of its
7
+ * own, and Outlook's Contacts UI treats this as a purely local file-format concern (a `.vcf` file never
8
+ * touches the server as anything but ordinary `Contact` field values), so there's nothing to add there.
9
+ */
10
+ import type { Contact, ContactAddressKind, ContactInput } from "./contactsApi.js";
11
+
12
+ /** Escapes a text value (RFC 6350 §3.4): backslash, comma and semicolon are backslash-escaped, and every
13
+ * line break - CRLF, bare CR or bare LF - becomes `\n`, so a value can never break the content line. */
14
+ function escapeVCardValue(value: string): string {
15
+ return value
16
+ .replace(/\\/g, "\\\\")
17
+ .replace(/,/g, "\\,")
18
+ .replace(/;/g, "\\;")
19
+ .replace(/\r\n|\r|\n/g, "\\n");
20
+ }
21
+
22
+ /** Unescapes a text value in a single pass, so an escaped backslash followed by `n` (`\\n`) stays a
23
+ * literal backslash + `n` instead of becoming a newline. `\n`/`\N` is a newline; any other escaped
24
+ * character is itself. */
25
+ function unescapeVCardValue(value: string): string {
26
+ return value.replace(/\\([\s\S])/g, (_match, ch: string) => (ch === "n" || ch === "N" ? "\n" : ch));
27
+ }
28
+
29
+ /** Splits a structured value (`N`, `ADR`) on its unescaped `;` separators, then unescapes each component. */
30
+ function splitStructuredValue(value: string): string[] {
31
+ const components: string[] = [];
32
+ let current = "";
33
+ for (let i = 0; i < value.length; i++) {
34
+ const ch = value[i];
35
+ if (ch === "\\" && i + 1 < value.length) {
36
+ current += ch + value[++i];
37
+ } else if (ch === ";") {
38
+ components.push(unescapeVCardValue(current));
39
+ current = "";
40
+ } else {
41
+ current += ch;
42
+ }
43
+ }
44
+ components.push(unescapeVCardValue(current));
45
+ return components;
46
+ }
47
+
48
+ /** Builds a single vCard 3.0 record for one contact. */
49
+ export function contactToVCard(contact: Contact): string {
50
+ const lines: string[] = ["BEGIN:VCARD", "VERSION:3.0"];
51
+ lines.push(`N:${escapeVCardValue(contact.surname ?? "")};${escapeVCardValue(contact.givenName ?? "")};;;`);
52
+ lines.push(`FN:${escapeVCardValue(contact.displayName)}`);
53
+ if (contact.company) {
54
+ lines.push(`ORG:${escapeVCardValue(contact.company)}`);
55
+ }
56
+ if (contact.jobTitle) {
57
+ lines.push(`TITLE:${escapeVCardValue(contact.jobTitle)}`);
58
+ }
59
+ for (const email of contact.emails) {
60
+ lines.push(`EMAIL;TYPE=${email.type.toUpperCase()}:${escapeVCardValue(email.address)}`);
61
+ }
62
+ for (const phone of contact.phones) {
63
+ lines.push(`TEL;TYPE=${phone.type.toUpperCase()}:${escapeVCardValue(phone.phoneNumber)}`);
64
+ }
65
+ for (const address of contact.addresses) {
66
+ const parts = [
67
+ "",
68
+ "",
69
+ address.street ?? "",
70
+ address.city ?? "",
71
+ address.state ?? "",
72
+ address.postalCode ?? "",
73
+ address.country ?? "",
74
+ ];
75
+ lines.push(`ADR;TYPE=${address.type.toUpperCase()}:${parts.map(escapeVCardValue).join(";")}`);
76
+ }
77
+ if (contact.notes) {
78
+ lines.push(`NOTE:${escapeVCardValue(contact.notes)}`);
79
+ }
80
+ lines.push("END:VCARD");
81
+ return lines.join("\r\n");
82
+ }
83
+
84
+ /** Builds a single `.vcf` file's text content from multiple contacts (one `BEGIN:VCARD`/`END:VCARD` block
85
+ * per contact — the standard way multiple vCards share one file). */
86
+ export function contactsToVCardFile(contacts: Contact[]): string {
87
+ return contacts.map(contactToVCard).join("\r\n");
88
+ }
89
+
90
+ /** A parsed vCard's fields, shaped as a partial `ContactInput` missing only the `mailboxUid`/`folderUid`
91
+ * scope (the caller supplies those, since they're not part of the vCard format itself). */
92
+ export type ParsedVCardContact = Omit<ContactInput, "mailboxUid" | "folderUid">;
93
+
94
+ /** Index of the content line's name/value separator: the first `:` outside a quoted parameter value. */
95
+ function valueSeparatorIndex(line: string): number {
96
+ let inQuotes = false;
97
+ for (let i = 0; i < line.length; i++) {
98
+ if (line[i] === '"') {
99
+ inQuotes = !inQuotes;
100
+ } else if (line[i] === ":" && !inQuotes) {
101
+ return i;
102
+ }
103
+ }
104
+ return -1;
105
+ }
106
+
107
+ /**
108
+ * Maps a property's type parameters onto `ContactAddressKind`: every `TYPE=` value (vCard 3/4, including
109
+ * comma lists and quoted lists like `TYPE="work,voice"`) plus vCard 2.1's bare parameters (`EMAIL;WORK:`)
110
+ * are collected case-insensitively; `work` wins, then `home`, and anything else (`internet`, `cell`,
111
+ * `pref`, no type at all) is `other`.
112
+ */
113
+ function normalizeType(params: string[]): ContactAddressKind {
114
+ const tokens = new Set<string>();
115
+ for (const param of params) {
116
+ const eq = param.indexOf("=");
117
+ const name = eq === -1 ? "TYPE" : param.slice(0, eq).trim().toUpperCase();
118
+ if (name !== "TYPE") {
119
+ continue;
120
+ }
121
+ for (const token of param.slice(eq + 1).replace(/"/g, "").split(",")) {
122
+ tokens.add(token.trim().toLowerCase());
123
+ }
124
+ }
125
+ return tokens.has("work") ? "work" : tokens.has("home") ? "home" : "other";
126
+ }
127
+
128
+ /**
129
+ * Parses one or more vCard 2.1/3.0/4.0 records from a `.vcf` file's text content. Deliberately tolerant of
130
+ * fields this app doesn't model (PHOTO, BDAY, etc. — silently ignored) and of the `TYPE=` parameter being
131
+ * absent (defaults to "other") — real-world exported vCards vary a lot in exactly which optional parameters
132
+ * they include. Folded lines (a line break followed by a space or tab) are unfolded first; property group
133
+ * prefixes (`item1.EMAIL`, as Apple Contacts writes) are ignored; `TYPE` values are normalized (see
134
+ * `normalizeType()`); structured values are split on unescaped `;` only.
135
+ */
136
+ export function parseVCards(text: string): ParsedVCardContact[] {
137
+ // Unfold first, then split only on a line that is exactly BEGIN:VCARD - a NOTE (or a folded line) that
138
+ // merely contains the text "BEGIN:VCARD" must not start a bogus record.
139
+ const unfolded = text.replace(/(?:\r\n|\r|\n)[ \t]/g, "");
140
+ const cards = unfolded.split(/^[ \t]*BEGIN:VCARD[ \t]*$/im).slice(1);
141
+ return cards.map((card) => {
142
+ const contact: ParsedVCardContact = { displayName: "", emails: [], phones: [], addresses: [] };
143
+ const lines = card.split(/\r\n|\r|\n/);
144
+ for (const rawLine of lines) {
145
+ const line = rawLine.trim();
146
+ const colonIndex = valueSeparatorIndex(line);
147
+ if (colonIndex === -1) {
148
+ continue;
149
+ }
150
+ const key = line.slice(0, colonIndex);
151
+ const rawValue = line.slice(colonIndex + 1);
152
+ const value = unescapeVCardValue(rawValue);
153
+ const [groupedName, ...params] = key.split(";");
154
+ const name = groupedName.slice(groupedName.lastIndexOf(".") + 1).toUpperCase();
155
+ const type = normalizeType(params);
156
+
157
+ switch (name) {
158
+ case "FN":
159
+ contact.displayName = value;
160
+ break;
161
+ case "N": {
162
+ const [surname, given] = splitStructuredValue(rawValue);
163
+ if (surname) contact.surname = surname;
164
+ if (given) contact.givenName = given;
165
+ break;
166
+ }
167
+ case "ORG":
168
+ // ORG is structured too (organization;unit;...) - only the organization name is modeled.
169
+ contact.company = splitStructuredValue(rawValue)[0];
170
+ break;
171
+ case "TITLE":
172
+ contact.jobTitle = value;
173
+ break;
174
+ case "EMAIL":
175
+ contact.emails!.push({ address: value, type });
176
+ break;
177
+ case "TEL":
178
+ contact.phones!.push({ phoneNumber: value, type });
179
+ break;
180
+ case "ADR": {
181
+ const [, , street, city, state, postalCode, country] = splitStructuredValue(rawValue);
182
+ contact.addresses!.push({ street, city, state, postalCode, country, type });
183
+ break;
184
+ }
185
+ case "NOTE":
186
+ contact.notes = value;
187
+ break;
188
+ default:
189
+ break;
190
+ }
191
+ }
192
+ if (!contact.displayName) {
193
+ contact.displayName = [contact.givenName, contact.surname].filter(Boolean).join(" ") || "Unnamed contact";
194
+ }
195
+ return contact;
196
+ });
197
+ }
@@ -0,0 +1,140 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * Compose-time decision logic for `specs/end-to-end_encryption.md`'s Digital Signatures and Encryption
7
+ * sections — kept as pure, side-effect-free functions (no `fetch`, no crypto) precisely so the actual
8
+ * discovery round trip (`keyvaultApi.ts`'s `lookupKeys()`) and MIME assembly (`smimeMessage.ts`) stay in
9
+ * the caller (`ComposeWindow.tsx`), which owns the async orchestration and error handling; this module
10
+ * only decides *what* a compose window should do once it has the facts.
11
+ *
12
+ * **Recipient tier classification is a client-side approximation.** The spec's three tiers
13
+ * (`specs/end-to-end_encryption.md`'s "Terminology": same-organisation / federated peer / external) are
14
+ * a server-side administrative concept - "the specific RapidMX server and the domains it controls" - that
15
+ * `@rapidmx/restapi` 0.6.0 does not actually expose to the client (`KeyLookupResult`/`KeyringUpdate`
16
+ * carry no tier field; confirmed by reading `util/KeyringUtils.ts`). `classifyRecipientTier()` below
17
+ * approximates it as "same domain as the sender's own address" vs. "a domain discovery found keys for"
18
+ * vs. "everything else" - the same domain-suffix heuristic used elsewhere for this class of judgment,
19
+ * not a guarantee. A real fix would be a restapi endpoint exposing which domains a server actually
20
+ * controls; until then this is a disclosed approximation, not a silent one.
21
+ */
22
+ import { findActivePublicKey, type EncryptionPolicy, type KeyLookupResult, type PolicyState, type PublicKey } from "./keyvaultApi.js";
23
+
24
+ export type RecipientTier = "sameOrg" | "federated" | "external";
25
+
26
+ /** See this module's own doc comment for why this is an approximation, not an authoritative classification. */
27
+ export function classifyRecipientTier(ownAddress: string, recipientAddress: string, hasDiscoveredKeys: boolean): RecipientTier {
28
+ const ownDomain = ownAddress.split("@")[1]?.toLowerCase();
29
+ const recipientDomain = recipientAddress.split("@")[1]?.toLowerCase();
30
+ if (ownDomain && recipientDomain && ownDomain === recipientDomain) {
31
+ return "sameOrg";
32
+ }
33
+ return hasDiscoveredKeys ? "federated" : "external";
34
+ }
35
+
36
+ function policyStateForTier(policy: EncryptionPolicy, tier: RecipientTier): PolicyState {
37
+ switch (tier) {
38
+ case "sameOrg":
39
+ return policy.encryptSameOrg;
40
+ case "federated":
41
+ return policy.encryptFederated;
42
+ case "external":
43
+ return policy.encryptExternal;
44
+ }
45
+ }
46
+
47
+ export interface RecipientEncryptionStatus {
48
+ address: string;
49
+ tier: RecipientTier;
50
+ /** The recipient's currently-active encryption certificate, if they have published (and this device
51
+ * has discovered) one. */
52
+ encryptCert?: PublicKey;
53
+ /** Whether this recipient *can* be encrypted to at all right now - false when there's no usable key,
54
+ * or the tier's policy is `prohibited`. */
55
+ canEncrypt: boolean;
56
+ /** Whether encryption should default ON for this recipient specifically: per spec, "MUST default to
57
+ * on only when both parties advertise mutual" AND the tier's policy is `automatic`. */
58
+ autoEncrypt: boolean;
59
+ /** Set (non-undefined) exactly when policy blocks encryption outright for this recipient's tier - the
60
+ * spec: "the client MUST explain why encryption is unavailable rather than silently omitting the
61
+ * control." `undefined` in every other case, including "no key found," which is not a policy block. */
62
+ prohibitedReason?: string;
63
+ }
64
+
65
+ /** Per-recipient encryption eligibility, given this device's own encryption preference and the
66
+ * system-wide policy. One entry per (address, lookup result) pair the caller already resolved via
67
+ * `lookupKeys()` - this function does no discovery itself. */
68
+ export function resolveRecipientEncryption(
69
+ ownAddress: string,
70
+ ownPrefersMutual: boolean,
71
+ policy: EncryptionPolicy,
72
+ recipientAddress: string,
73
+ lookup: KeyLookupResult | undefined,
74
+ ): RecipientEncryptionStatus {
75
+ const encryptCert = lookup ? findActivePublicKey(lookup.keys, "encrypt") : undefined;
76
+ const tier = classifyRecipientTier(ownAddress, recipientAddress, !!lookup && lookup.keys.length > 0);
77
+ const policyState = policyStateForTier(policy, tier);
78
+
79
+ if (policyState === "prohibited") {
80
+ return {
81
+ address: recipientAddress,
82
+ tier,
83
+ encryptCert,
84
+ canEncrypt: false,
85
+ autoEncrypt: false,
86
+ prohibitedReason: "Your organization's encryption policy does not allow encrypting messages to this recipient.",
87
+ };
88
+ }
89
+
90
+ if (!encryptCert) {
91
+ return { address: recipientAddress, tier, canEncrypt: false, autoEncrypt: false };
92
+ }
93
+
94
+ const recipientPrefersMutual = lookup?.encryptPreference?.preferEncrypt === "mutual";
95
+ const mutual = ownPrefersMutual && recipientPrefersMutual;
96
+ return {
97
+ address: recipientAddress,
98
+ tier,
99
+ encryptCert,
100
+ canEncrypt: true,
101
+ autoEncrypt: policyState === "automatic" && mutual,
102
+ };
103
+ }
104
+
105
+ export interface MessageEncryptionDecision {
106
+ /** Whether the compose window's encryption toggle should default to checked - true only when every
107
+ * recipient independently defaults to encrypted. Seeds the toggle's *initial* state only; the user
108
+ * can still turn it on manually even when this is false, subject to `canEncryptAll`. */
109
+ autoEncrypt: boolean;
110
+ /** Every recipient the message *could* be encrypted to right now. */
111
+ canEncryptAll: boolean;
112
+ /** Recipients that cannot currently be encrypted to (no key, or policy-prohibited) - the spec's
113
+ * "Multiple Recipients" all-or-nothing case: when this is non-empty and the user still wants
114
+ * encryption, the client MUST offer to send in plaintext or remove these recipients, never split. */
115
+ blockedRecipients: RecipientEncryptionStatus[];
116
+ }
117
+
118
+ /** Combines every recipient's individual status into the one decision a compose window's UI actually
119
+ * needs: whether to default the toggle on, and whether an all-or-nothing prompt is required. */
120
+ export function decideMessageEncryption(recipients: RecipientEncryptionStatus[]): MessageEncryptionDecision {
121
+ if (recipients.length === 0) {
122
+ return { autoEncrypt: false, canEncryptAll: false, blockedRecipients: [] };
123
+ }
124
+ const blockedRecipients = recipients.filter((r) => !r.canEncrypt);
125
+ return {
126
+ autoEncrypt: recipients.every((r) => r.autoEncrypt),
127
+ canEncryptAll: blockedRecipients.length === 0,
128
+ blockedRecipients,
129
+ };
130
+ }
131
+
132
+ /** Detects list traffic per the spec's "Mailing lists" note under Digital Signatures: a footer a list
133
+ * appends after signing invalidates the signature, so the client MAY suppress signing for it. `headers`
134
+ * is whatever the caller already has on hand (e.g. a `Contact`'s known list-membership flag) - this
135
+ * module has no way to inspect list membership itself, so it just applies the rule to inputs the caller
136
+ * supplies. Currently unused by any caller (no UI surfaces distribution-list membership to compose yet -
137
+ * a disclosed gap, not a silent one; see this module's own file-level doc comment). */
138
+ export function isLikelyMailingList(headers: { listId?: string; listUnsubscribe?: string }): boolean {
139
+ return !!(headers.listId || headers.listUnsubscribe);
140
+ }
@@ -0,0 +1,36 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * Plain base64/base64url <-> `Uint8Array` conversions shared by every `crypto/*` module. Deliberately
7
+ * `Buffer`-free — this code runs in a browser tab and an Electron renderer alike, and `Buffer` is not
8
+ * guaranteed to exist in either without a bundler polyfill.
9
+ */
10
+
11
+ export function toBase64(bytes: Uint8Array): string {
12
+ let binary = "";
13
+ for (const byte of bytes) {
14
+ binary += String.fromCharCode(byte);
15
+ }
16
+ return btoa(binary);
17
+ }
18
+
19
+ export function fromBase64(base64: string): Uint8Array {
20
+ const binary = atob(base64);
21
+ const bytes = new Uint8Array(binary.length);
22
+ for (let i = 0; i < binary.length; i++) {
23
+ bytes[i] = binary.charCodeAt(i);
24
+ }
25
+ return bytes;
26
+ }
27
+
28
+ export function toBase64Url(bytes: Uint8Array): string {
29
+ return toBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
30
+ }
31
+
32
+ export function fromBase64Url(base64url: string): Uint8Array {
33
+ const padded = base64url.replace(/-/g, "+").replace(/_/g, "/");
34
+ const padding = padded.length % 4 === 0 ? "" : "=".repeat(4 - (padded.length % 4));
35
+ return fromBase64(padded + padding);
36
+ }