@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,568 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * A small, dependency-free MIME (RFC 5322 / RFC 2045-2047) parser used by `smimeMessage.ts` and
7
+ * `messageSecurity.ts` to read *received* messages - which, unlike this package's own output, can come
8
+ * from any foreign MUA/MTA. It deliberately covers exactly what S/MIME evaluation needs and nothing more:
9
+ *
10
+ * header unfolding (RFC 5322 §2.2.3) and CRLF-or-bare-LF line endings; case-insensitive RFC 2045
11
+ * `type/subtype; name=value` parameters, quoted or unquoted; RFC 2046 multipart splitting with
12
+ * preamble/epilogue, transport padding after the delimiter, and delimiters only recognized at the start
13
+ * of a line; `Content-Transfer-Encoding` decoding (base64, quoted-printable; 7bit/8bit/binary pass
14
+ * through) plus `charset` decoding via `TextDecoder`; and picking the displayable body (text/html
15
+ * preferred, text/plain otherwise) out of a nested multipart.
16
+ *
17
+ * **Binary strings.** Received message source is handled as a "binary string": one UTF-16 code unit per
18
+ * byte (0x00-0xFF), which is what `mailApi.ts`'s `getMessageRawContent()` returns (it reads the response
19
+ * as bytes and decodes them as Latin-1) and what decrypted CMS content is converted to. That keeps an
20
+ * 8bit body's bytes intact until its own `charset` is known, and keeps signed bytes verifiable exactly.
21
+ * A string containing any code unit above 0xFF can't be a binary string, so it is treated as already
22
+ * decoded text and UTF-8 encoded wherever bytes are needed (the pre-round-4 convention) - see
23
+ * `binaryStringToBytes()`.
24
+ *
25
+ * Not supported (documented, not silently wrong): RFC 2231 parameter continuations/charset-encoded
26
+ * parameters - not needed to classify, decrypt, or verify a message, and left verbatim. RFC 2047
27
+ * encoded-words are decoded only where text is shown to a user (`decodeHeaderText()`); raw header values
28
+ * (`MimeEntity.headers`) stay verbatim so header comparisons remain exact.
29
+ */
30
+
31
+ /** One header field, unfolded, with its name exactly as written and its value trimmed. */
32
+ export interface MimeHeaderField {
33
+ name: string;
34
+ value: string;
35
+ }
36
+
37
+ export interface MimeEntity {
38
+ /** Every header field in order - including repeated names (e.g. RFC 9788 `HP-Outer`). */
39
+ fields: MimeHeaderField[];
40
+ /** Lowercased name -> value of that name's FIRST occurrence. */
41
+ headers: Record<string, string>;
42
+ /** The raw, still-folded header block text (everything before the blank separator line). */
43
+ rawHeaderBlock: string;
44
+ /** The raw, undecoded body (everything after the blank separator line). */
45
+ body: string;
46
+ }
47
+
48
+ export interface ParameterizedHeader {
49
+ /** The lowercased main value (e.g. `multipart/signed`). */
50
+ value: string;
51
+ /** Lowercased parameter name -> unquoted value. */
52
+ params: Record<string, string>;
53
+ }
54
+
55
+ /** Maximum multipart nesting `extractDisplayBody()` descends into - a hostile message can nest
56
+ * arbitrarily deep, and nothing legitimate needs more than a handful of levels. */
57
+ const MAX_MULTIPART_DEPTH = 8;
58
+
59
+ /** Splits a MIME entity into its header fields and body. Never throws. */
60
+ export function parseMimeEntity(entity: string): MimeEntity {
61
+ let rawHeaderBlock: string;
62
+ let body: string;
63
+ const leading = /^\r?\n/.exec(entity);
64
+ if (leading) {
65
+ // An entity whose very first line is blank has no headers at all (RFC 2046 §5.1.1 - a body part
66
+ // with no header fields defaults to text/plain; charset=us-ascii).
67
+ rawHeaderBlock = "";
68
+ body = entity.slice(leading[0].length);
69
+ } else {
70
+ const separator = /\r?\n\r?\n/.exec(entity);
71
+ rawHeaderBlock = separator ? entity.slice(0, separator.index) : entity;
72
+ body = separator ? entity.slice(separator.index + separator[0].length) : "";
73
+ }
74
+
75
+ const fields: MimeHeaderField[] = [];
76
+ const headers: Record<string, string> = {};
77
+ const unfolded = rawHeaderBlock.replace(/\r?\n(?=[ \t])/g, "");
78
+ for (const line of unfolded.split(/\r?\n/)) {
79
+ const colonIndex = line.indexOf(":");
80
+ if (colonIndex <= 0) {
81
+ continue;
82
+ }
83
+ const name = line.slice(0, colonIndex).trim();
84
+ const value = line.slice(colonIndex + 1).trim();
85
+ fields.push({ name, value });
86
+ const key = name.toLowerCase();
87
+ if (!(key in headers)) {
88
+ headers[key] = value;
89
+ }
90
+ }
91
+ return { fields, headers, rawHeaderBlock, body };
92
+ }
93
+
94
+ /** Parses an RFC 2045 parameterized header value (`Content-Type`, `Content-Disposition`). */
95
+ export function parseParameterizedHeader(headerValue: string | undefined): ParameterizedHeader {
96
+ const segments: string[] = [];
97
+ let current = "";
98
+ let inQuotes = false;
99
+ const input = headerValue ?? "";
100
+ for (let i = 0; i < input.length; i++) {
101
+ const ch = input[i];
102
+ if (inQuotes && ch === "\\" && i + 1 < input.length) {
103
+ current += input[++i];
104
+ } else if (ch === '"') {
105
+ inQuotes = !inQuotes;
106
+ } else if (ch === ";" && !inQuotes) {
107
+ segments.push(current);
108
+ current = "";
109
+ } else {
110
+ current += ch;
111
+ }
112
+ }
113
+ segments.push(current);
114
+
115
+ const [main, ...rest] = segments;
116
+ const params: Record<string, string> = {};
117
+ for (const segment of rest) {
118
+ const eq = segment.indexOf("=");
119
+ const name = segment.slice(0, Math.max(eq, 0)).trim().toLowerCase();
120
+ if (name && !(name in params)) {
121
+ params[name] = segment.slice(eq + 1).trim();
122
+ }
123
+ }
124
+ return { value: main.trim().toLowerCase(), params };
125
+ }
126
+
127
+ function escapeRegExp(value: string): string {
128
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
129
+ }
130
+
131
+ /**
132
+ * Splits a multipart body on `boundary` per RFC 2046 §5.1.1: a delimiter is `--boundary` at the start of
133
+ * a line (optionally followed by transport-padding whitespace), the CRLF preceding it belongs to the
134
+ * delimiter (not the previous part), text before the first delimiter is preamble and text after the close
135
+ * delimiter (`--boundary--`) is epilogue - both discarded. Each returned part is the exact text between
136
+ * delimiter lines, which is what a `multipart/signed` signature covers.
137
+ */
138
+ export function splitMultipart(body: string, boundary: string): string[] {
139
+ const delimiter = new RegExp(`(?:^|\\r?\\n)--${escapeRegExp(boundary)}(--)?[ \\t]*(?=\\r?\\n|$)`, "g");
140
+ const parts: string[] = [];
141
+ let partStart = -1;
142
+ let match: RegExpExecArray | null;
143
+ while ((match = delimiter.exec(body)) !== null) {
144
+ if (partStart !== -1) {
145
+ parts.push(body.slice(partStart, Math.max(partStart, match.index)));
146
+ }
147
+ if (match[1]) {
148
+ return parts;
149
+ }
150
+ const end = match.index + match[0].length;
151
+ partStart = end + (body.startsWith("\r\n", end) ? 2 : body.startsWith("\n", end) ? 1 : 0);
152
+ }
153
+ // No close delimiter (a truncated message): whatever follows the last delimiter is still a part.
154
+ if (partStart !== -1) {
155
+ parts.push(body.slice(partStart));
156
+ }
157
+ return parts;
158
+ }
159
+
160
+ /** Returns the lowercased, trimmed `Content-Transfer-Encoding` mechanism, or `undefined`. */
161
+ function transferEncodingOf(entity: MimeEntity): string | undefined {
162
+ return entity.headers["content-transfer-encoding"]?.trim().toLowerCase();
163
+ }
164
+
165
+ /** Decodes a base64 body into bytes, ignoring whitespace/line breaks. Returns `undefined` for invalid
166
+ * base64 rather than throwing. */
167
+ export function decodeBase64Text(text: string): Uint8Array | undefined {
168
+ try {
169
+ const binary = atob(text.replace(/\s+/g, ""));
170
+ const bytes = new Uint8Array(binary.length);
171
+ for (let i = 0; i < binary.length; i++) {
172
+ bytes[i] = binary.charCodeAt(i);
173
+ }
174
+ return bytes;
175
+ } catch {
176
+ return undefined;
177
+ }
178
+ }
179
+
180
+ /** `true` when every code unit of `value` is at most 0xFF - i.e. it can be a binary string (see this
181
+ * module's doc comment). */
182
+ export function isBinaryString(value: string): boolean {
183
+ for (let i = 0; i < value.length; i++) {
184
+ if (value.charCodeAt(i) > 0xff) {
185
+ return false;
186
+ }
187
+ }
188
+ return true;
189
+ }
190
+
191
+ /** Converts a binary string to its bytes, or - for a string that can't be one (a code unit above 0xFF) -
192
+ * to its UTF-8 encoding. */
193
+ export function binaryStringToBytes(value: string): Uint8Array {
194
+ if (!isBinaryString(value)) {
195
+ return new TextEncoder().encode(value);
196
+ }
197
+ const bytes = new Uint8Array(value.length);
198
+ for (let i = 0; i < value.length; i++) {
199
+ bytes[i] = value.charCodeAt(i);
200
+ }
201
+ return bytes;
202
+ }
203
+
204
+ /** Converts bytes to a binary string (one code unit per byte), in chunks so a large message never exceeds
205
+ * the engine's argument-count limit. */
206
+ export function bytesToBinaryString(bytes: Uint8Array): string {
207
+ const CHUNK = 0x8000;
208
+ const pieces: string[] = [];
209
+ for (let i = 0; i < bytes.length; i += CHUNK) {
210
+ pieces.push(String.fromCharCode(...bytes.subarray(i, i + CHUNK)));
211
+ }
212
+ return pieces.join("");
213
+ }
214
+
215
+ function hexValue(code: number): number {
216
+ if (code >= 0x30 && code <= 0x39) return code - 0x30;
217
+ if (code >= 0x41 && code <= 0x46) return code - 0x37;
218
+ if (code >= 0x61 && code <= 0x66) return code - 0x57;
219
+ return -1;
220
+ }
221
+
222
+ /** Decodes a quoted-printable body (RFC 2045 §6.7) into bytes, in one linear pass into a preallocated
223
+ * buffer. Literal text between escapes (which can't legally be non-ASCII in QP, but is after an
224
+ * 8-bit-unsafe gateway) is written run by run, decided once for the whole input: as the runs' own bytes
225
+ * when the input is a binary string, else as their UTF-8 encoding (so an already-decoded `é` next to an
226
+ * emoji isn't written as a lone 0xE9 byte). A run always ends at an ASCII `=`, so a surrogate pair is never
227
+ * split. */
228
+ export function decodeQuotedPrintable(text: string): Uint8Array {
229
+ const input = text.replace(/=[ \t]*\r?\n/g, "");
230
+ const binary = isBinaryString(input);
231
+ // At most 3 UTF-8 bytes per UTF-16 code unit, which only a non-binary string can need.
232
+ const out = new Uint8Array(binary ? input.length : input.length * 3);
233
+ const encoder = new TextEncoder();
234
+ let length = 0;
235
+ let runStart = 0;
236
+ const flushRun = (end: number) => {
237
+ if (binary) {
238
+ for (let j = runStart; j < end; j++) {
239
+ out[length++] = input.charCodeAt(j);
240
+ }
241
+ } else {
242
+ length += encoder.encodeInto(input.slice(runStart, end), out.subarray(length)).written;
243
+ }
244
+ };
245
+ for (let i = 0; i + 2 < input.length; i++) {
246
+ if (input.charCodeAt(i) !== 0x3d) {
247
+ continue;
248
+ }
249
+ const high = hexValue(input.charCodeAt(i + 1));
250
+ const low = hexValue(input.charCodeAt(i + 2));
251
+ if (high < 0 || low < 0) {
252
+ continue;
253
+ }
254
+ flushRun(i);
255
+ out[length++] = (high << 4) | low;
256
+ i += 2;
257
+ runStart = i + 1;
258
+ }
259
+ flushRun(input.length);
260
+ return out.slice(0, length);
261
+ }
262
+
263
+ /** Decodes `bytes` in `charset` (UTF-8 when absent or unknown). With `fallbackText`, a decode that hits
264
+ * invalid input returns `fallbackText` instead of replacement characters. */
265
+ function decodeCharset(bytes: Uint8Array, charset: string | undefined, fallbackText?: string): string {
266
+ const options = { fatal: fallbackText !== undefined };
267
+ let decoder: TextDecoder;
268
+ try {
269
+ decoder = new TextDecoder(charset || "utf-8", options);
270
+ } catch {
271
+ // An unknown/unsupported charset label - UTF-8 is the least-bad fallback (a superset of ASCII).
272
+ decoder = new TextDecoder("utf-8", options);
273
+ }
274
+ try {
275
+ return decoder.decode(bytes);
276
+ } catch {
277
+ return fallbackText as string;
278
+ }
279
+ }
280
+
281
+ /** Decodes an entity's body into bytes per its `Content-Transfer-Encoding`. 7bit/8bit/binary (or no
282
+ * header) return the body's own bytes (see `binaryStringToBytes()`). Returns `undefined` only for invalid
283
+ * base64. */
284
+ export function decodeBodyBytes(entity: MimeEntity): Uint8Array | undefined {
285
+ const cte = transferEncodingOf(entity);
286
+ if (cte === "base64") {
287
+ return decodeBase64Text(entity.body);
288
+ }
289
+ if (cte === "quoted-printable") {
290
+ return decodeQuotedPrintable(entity.body);
291
+ }
292
+ return binaryStringToBytes(entity.body);
293
+ }
294
+
295
+ /** Decodes an entity's body to text: transfer encoding first, then its `charset` parameter (UTF-8 when
296
+ * absent). A 7bit/8bit/binary body that isn't a binary string was already decoded by whoever produced the
297
+ * string and passes through unchanged; so does a binary-string body whose bytes are invalid in its charset
298
+ * (e.g. legacy already-decoded Latin-1 text under a UTF-8 charset). */
299
+ export function decodeBodyText(entity: MimeEntity): string {
300
+ const cte = transferEncodingOf(entity);
301
+ const charset = parseParameterizedHeader(entity.headers["content-type"]).params["charset"];
302
+ if (cte !== "base64" && cte !== "quoted-printable") {
303
+ return isBinaryString(entity.body) ? decodeCharset(binaryStringToBytes(entity.body), charset, entity.body) : entity.body;
304
+ }
305
+ return decodeCharset(decodeBodyBytes(entity) ?? new Uint8Array(), charset);
306
+ }
307
+
308
+ const ENCODED_WORD = /=\?([^?\s]+)\?([bBqQ])\?([^?\s]*)\?=/g;
309
+ const WHITESPACE_BETWEEN_ENCODED_WORDS = /(=\?[^?\s]+\?[bBqQ]\?[^?\s]*\?=)\s+(?==\?[^?\s]+\?[bBqQ]\?[^?\s]*\?=)/g;
310
+
311
+ /**
312
+ * Turns a raw header value into display text: a binary string holding valid UTF-8 (a raw 8-bit header,
313
+ * RFC 6532) is decoded as UTF-8, then RFC 2047 encoded-words (`=?charset?B|Q?text?=`) are decoded, with
314
+ * whitespace between adjacent encoded-words dropped (RFC 2047 §6.2). An encoded-word with an unknown
315
+ * charset or undecodable content is left verbatim.
316
+ */
317
+ export function decodeHeaderText(value: string): string {
318
+ let text = value;
319
+ if (isBinaryString(text) && /[\x80-\xff]/.test(text)) {
320
+ text = decodeCharset(binaryStringToBytes(text), "utf-8", text);
321
+ }
322
+ return text.replace(WHITESPACE_BETWEEN_ENCODED_WORDS, "$1").replace(ENCODED_WORD, (word, charset: string, encoding: string, encoded: string) => {
323
+ const bytes =
324
+ encoding.toUpperCase() === "B"
325
+ ? decodeBase64Text(encoded)
326
+ : binaryStringToBytes(encoded.replace(/_/g, " ").replace(/=([0-9A-Fa-f]{2})/g, (_match, hex: string) => String.fromCharCode(parseInt(hex, 16))));
327
+ if (!bytes) {
328
+ return word;
329
+ }
330
+ try {
331
+ // RFC 2231 §5 allows a language suffix on the charset: `charset*lang`.
332
+ return new TextDecoder(charset.split("*")[0], { fatal: true }).decode(bytes);
333
+ } catch {
334
+ return word;
335
+ }
336
+ });
337
+ }
338
+
339
+ /** Anything outside printable ASCII (space through `~`) and tab - such header text needs RFC 2047 encoding. */
340
+ const NEEDS_ENCODING = /[^\x20-\x7e\t]/;
341
+
342
+ /** Characters that must never reach a serialized header value: CR/LF (header injection) and NUL. */
343
+ const HEADER_BREAKING = /[\r\n\0]+/g;
344
+
345
+ /** Encodes `text` as RFC 2047 `B` encoded-words (UTF-8), each at most 75 characters, never splitting a
346
+ * multi-byte character between words, joined by folding whitespace. */
347
+ function encodeWords(text: string): string {
348
+ // "=?UTF-8?B?" + "?=" is 12 characters, leaving 63 for base64 - i.e. at most 45 source bytes.
349
+ const MAX_BYTES_PER_WORD = 45;
350
+ const encoder = new TextEncoder();
351
+ const words: string[] = [];
352
+ let current = "";
353
+ let currentBytes = 0;
354
+ for (const ch of text) {
355
+ const size = encoder.encode(ch).length;
356
+ if (currentBytes + size > MAX_BYTES_PER_WORD && current) {
357
+ words.push(current);
358
+ current = "";
359
+ currentBytes = 0;
360
+ }
361
+ current += ch;
362
+ currentBytes += size;
363
+ }
364
+ words.push(current);
365
+ return words.map((word) => `=?UTF-8?B?${btoa(bytesToBinaryString(encoder.encode(word)))}?=`).join("\r\n ");
366
+ }
367
+
368
+ /** Makes an unstructured header value (e.g. `Subject`) safe to serialize: CR/LF/NUL become a space
369
+ * (never a header break), and a value containing non-ASCII is RFC 2047-encoded. */
370
+ export function encodeUnstructuredHeaderValue(value: string): string {
371
+ const flattened = value.replace(HEADER_BREAKING, " ");
372
+ return NEEDS_ENCODING.test(flattened) ? encodeWords(flattened) : flattened;
373
+ }
374
+
375
+ /** Encodes one mailbox (`Name <addr>` or a bare addr-spec) - see `encodeAddressListHeaderValue()`. */
376
+ function encodeMailbox(mailbox: string): string {
377
+ const angle = mailbox.lastIndexOf("<");
378
+ if (angle === -1) {
379
+ // A bare addr-spec (possibly internationalized) stays verbatim; stray non-ASCII text that
380
+ // isn't an address at all is encoded rather than written raw.
381
+ const bare = mailbox.trim();
382
+ return bare.includes("@") || !NEEDS_ENCODING.test(bare) ? bare : encodeWords(bare);
383
+ }
384
+ const rawName = mailbox.slice(0, angle).trim();
385
+ const address = mailbox.slice(angle).trim();
386
+ const name = encodePhrase(rawName);
387
+ return name ? `${name} ${address}` : address;
388
+ }
389
+
390
+ /** Encodes a display-name phrase (a mailbox's name or a group's label): unquoted and RFC 2047-encoded when
391
+ * it holds non-ASCII, else kept exactly as written. */
392
+ function encodePhrase(rawPhrase: string): string {
393
+ const phrase = rawPhrase.trim();
394
+ const unquoted = /^".*"$/.test(phrase) ? phrase.slice(1, -1).replace(/\\(.)/g, "$1") : phrase;
395
+ return NEEDS_ENCODING.test(unquoted) ? encodeWords(unquoted) : phrase;
396
+ }
397
+
398
+ /**
399
+ * Makes an address-list header value (`From`/`To`/`Cc`) safe to serialize: CR/LF/NUL become a space, and
400
+ * each mailbox's non-ASCII display name (`Zoë <z@example.com>`, quoted or not) is RFC 2047-encoded while
401
+ * its addr-spec is kept verbatim (an internationalized address is left to SMTPUTF8, never encoded -
402
+ * RFC 2047 §5 forbids encoded-words in an addr-spec). RFC 5322 group syntax (`Équipe: Zoë <z@x>, b@x;`)
403
+ * keeps its `:` and `;`, with the group label encoded as a phrase of its own. A top-level `:` only opens
404
+ * a group when a `;` follows it, so a stray colon in an unquoted display name isn't mistaken for one.
405
+ */
406
+ export function encodeAddressListHeaderValue(value: string): string {
407
+ const flattened = value.replace(HEADER_BREAKING, " ");
408
+ if (!NEEDS_ENCODING.test(flattened)) {
409
+ return flattened;
410
+ }
411
+ let out = "";
412
+ let current = "";
413
+ let inQuotes = false;
414
+ let inAngle = false;
415
+ let inGroup = false;
416
+ const emit = (encoded: string, delimiter: string) => {
417
+ out += (encoded && /[,:;]$/.test(out) ? " " : "") + encoded + delimiter;
418
+ current = "";
419
+ };
420
+ for (let i = 0; i < flattened.length; i++) {
421
+ const ch = flattened[i];
422
+ if (inQuotes && ch === "\\" && i + 1 < flattened.length) {
423
+ current += ch + flattened[++i];
424
+ continue;
425
+ }
426
+ if (ch === '"') {
427
+ inQuotes = !inQuotes;
428
+ } else if (!inQuotes && ch === "<") {
429
+ inAngle = true;
430
+ } else if (!inQuotes && ch === ">") {
431
+ inAngle = false;
432
+ } else if (!inQuotes && !inAngle) {
433
+ if (ch === ",") {
434
+ emit(encodeMailbox(current), ",");
435
+ continue;
436
+ }
437
+ if (ch === ":" && !inGroup && flattened.includes(";", i)) {
438
+ emit(encodePhrase(current), ":");
439
+ inGroup = true;
440
+ continue;
441
+ }
442
+ if (ch === ";" && inGroup) {
443
+ emit(encodeMailbox(current), ";");
444
+ inGroup = false;
445
+ continue;
446
+ }
447
+ }
448
+ current += ch;
449
+ }
450
+ emit(encodeMailbox(current), "");
451
+ return out;
452
+ }
453
+
454
+ /** A message's displayable content: `html` only for a real `text/html` part, `text` only for a
455
+ * `text/plain` part - never plain text mislabeled as HTML. */
456
+ export interface DisplayBody {
457
+ html?: string;
458
+ text?: string;
459
+ }
460
+
461
+ function isAttachment(entity: MimeEntity): boolean {
462
+ return parseParameterizedHeader(entity.headers["content-disposition"]).value === "attachment";
463
+ }
464
+
465
+ /** Picks the displayable body out of an entity: a `text/html` part is preferred over `text/plain`, and a
466
+ * multipart entity is searched (non-attachment children only, bounded depth). Entities with no
467
+ * Content-Type default to text/plain per RFC 2045 §5.2. */
468
+ export function extractDisplayBody(entity: MimeEntity, depth = 0): DisplayBody {
469
+ const contentType = parseParameterizedHeader(entity.headers["content-type"] ?? "text/plain");
470
+ if (contentType.value === "text/html") {
471
+ return { html: decodeBodyText(entity) };
472
+ }
473
+ if (contentType.value === "text/plain") {
474
+ return { text: decodeBodyText(entity) };
475
+ }
476
+ const boundary = contentType.params["boundary"];
477
+ if (!contentType.value.startsWith("multipart/") || !boundary || depth >= MAX_MULTIPART_DEPTH) {
478
+ return {};
479
+ }
480
+ let text: string | undefined;
481
+ for (const part of splitMultipart(entity.body, boundary)) {
482
+ const child = parseMimeEntity(part);
483
+ if (isAttachment(child)) {
484
+ continue;
485
+ }
486
+ const found = extractDisplayBody(child, depth + 1);
487
+ if (found.html !== undefined) {
488
+ return { html: found.html };
489
+ }
490
+ text ??= found.text;
491
+ }
492
+ return text === undefined ? {} : { text };
493
+ }
494
+
495
+ /** One attachment found inside a MIME entity (see `extractAttachments()`). */
496
+ export interface MimeAttachment {
497
+ /** The `Content-Disposition` `filename` (else the `Content-Type` `name`), RFC 2047-decoded; absent if neither. */
498
+ filename?: string;
499
+ /** The lowercased MIME type, e.g. `application/pdf`. */
500
+ contentType: string;
501
+ /** `"attachment"` for `Content-Disposition: attachment`, `"inline"` otherwise (an inline image, or a part with a
502
+ * filename and no disposition). */
503
+ disposition: "attachment" | "inline";
504
+ /** The `Content-ID` without its angle brackets, if any - how an HTML body references an inline part. */
505
+ contentId?: string;
506
+ /** Decodes the part's content (transfer encoding undone) - lazily, so evaluating a message never pays for
507
+ * attachments nobody opens. `undefined` for invalid base64. */
508
+ decode(): Uint8Array | undefined;
509
+ }
510
+
511
+ /**
512
+ * Lists the attachments inside `entity` (descending into multipart children, bounded depth): every leaf part
513
+ * with `Content-Disposition: attachment`, a filename, or a non-text type. The `text/plain`/`text/html` parts a
514
+ * reader would display (no disposition, no filename) are not attachments. Nested `message/rfc822` content is
515
+ * reported as one attachment, never expanded.
516
+ */
517
+ export function extractAttachments(entity: MimeEntity, depth = 0): MimeAttachment[] {
518
+ const contentType = parseParameterizedHeader(entity.headers["content-type"] ?? "text/plain");
519
+ const disposition = parseParameterizedHeader(entity.headers["content-disposition"]);
520
+ const boundary = contentType.params["boundary"];
521
+ if (contentType.value.startsWith("multipart/")) {
522
+ if (!boundary || depth >= MAX_MULTIPART_DEPTH) {
523
+ return [];
524
+ }
525
+ return splitMultipart(entity.body, boundary).flatMap((part) => extractAttachments(parseMimeEntity(part), depth + 1));
526
+ }
527
+ const rawFilename = disposition.params["filename"] ?? contentType.params["name"];
528
+ const isAttachmentDisposition = disposition.value === "attachment";
529
+ if (!isAttachmentDisposition && rawFilename === undefined && contentType.value.startsWith("text/")) {
530
+ return [];
531
+ }
532
+ const contentId = entity.headers["content-id"]?.trim().replace(/^<(.*)>$/, "$1");
533
+ return [
534
+ {
535
+ ...(rawFilename !== undefined ? { filename: decodeHeaderText(rawFilename) } : {}),
536
+ contentType: contentType.value,
537
+ disposition: isAttachmentDisposition ? "attachment" : "inline",
538
+ ...(contentId ? { contentId } : {}),
539
+ decode: () => decodeBodyBytes(entity),
540
+ },
541
+ ];
542
+ }
543
+
544
+ /** HTML-escapes plain text and wraps it in a whitespace-preserving `<pre>`, so a `text/plain` body can be
545
+ * rendered through the same HTML path without ever being interpreted as markup. */
546
+ export function plainTextToHtml(text: string): string {
547
+ const escaped = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
548
+ return `<pre style="white-space: pre-wrap; word-wrap: break-word; font-family: inherit">${escaped}</pre>`;
549
+ }
550
+
551
+ /** Extracts the bare, lowercased addr-specs from an address-list header value (`"Name" <a@b>, c@d`).
552
+ * Handles quoted display names containing commas/angle brackets and RFC 5322 comments. */
553
+ export function extractAddresses(headerValue: string | undefined): string[] {
554
+ if (!headerValue) {
555
+ return [];
556
+ }
557
+ const withoutQuoted = headerValue.replace(/"(?:[^"\\]|\\.)*"/g, '""').replace(/\((?:[^()\\]|\\.)*\)/g, "");
558
+ const addresses: string[] = [];
559
+ for (const item of withoutQuoted.split(",")) {
560
+ const angle = /<([^>]*)>/.exec(item);
561
+ // A bare addr-spec may carry RFC 5322 group syntax around it (`Team: a@b, c@d;`).
562
+ const address = (angle ? angle[1] : item.replace(/^[^:]*:/, "").replace(/;\s*$/, "")).trim().toLowerCase();
563
+ if (address.includes("@")) {
564
+ addresses.push(address);
565
+ }
566
+ }
567
+ return addresses;
568
+ }
@@ -0,0 +1,103 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * The "passkey" unlock method from `specs/end-to-end_encryption.md`'s "Master Key Wrapping": uses the
7
+ * WebAuthn **PRF extension** to obtain a stable per-credential secret, then HKDF-derives a wrapping key
8
+ * from it — `wrap_passkey_N = AEAD(HKDF(WebAuthn-PRF(credential_N, salt)), MK)`. The credential's own
9
+ * private key is non-extractable and never used directly; only the PRF extension's derived secret is.
10
+ *
11
+ * This deliberately talks to the raw `navigator.credentials` WebAuthn API rather than
12
+ * `@simplewebauthn/browser` — that library's `startRegistration`/`startAuthentication` helpers expect a
13
+ * server-generated `optionsJSON` (from `@simplewebauthn/server`'s `generateRegistrationOptions()`/
14
+ * `generateAuthenticationOptions()`), which assumes a full relying-party ceremony with server-side
15
+ * challenge issuance and assertion verification. There is no such flow here — this passkey is never used
16
+ * to authenticate to `@rapidmx/restapi` or auth-server, only as a local, hardware-backed KDF input. A
17
+ * locally-generated challenge is fine because nothing server-side ever verifies this credential's
18
+ * attestation/assertion signature; only the PRF extension output is consumed. Identity/session auth
19
+ * remains entirely `auth-server`'s job (see `.claude/NOTES.md` in `server`).
20
+ *
21
+ * **Needs real hardware/browser verification.** PRF extension behavior (in particular, whether a
22
+ * browser returns `prf.results` on the *registration* ceremony itself vs. only on a subsequent
23
+ * `navigator.credentials.get()`) is not exercisable in this test environment (no real authenticator) —
24
+ * this module's tests mock `navigator.credentials` and cover this module's own request-building/
25
+ * response-parsing logic, not real authenticator behavior end to end. Verify against real hardware
26
+ * before shipping, the same honesty standard `@rapidmx/restapi` holds its own hard-to-verify pieces to
27
+ * (e.g. that repo's `sameIssuingCa()` doc comment).
28
+ */
29
+ import { fromBase64Url, toBase64Url } from "./encoding.js";
30
+ import { hkdfDerive } from "./masterKey.js";
31
+
32
+ const PRF_HKDF_INFO = "wrap";
33
+ const CHALLENGE_LENGTH_BYTES = 32;
34
+
35
+ /** Minimal shape of the WebAuthn PRF extension's client extension results this module needs — the DOM
36
+ * lib's own `AuthenticationExtensionsClientOutputs` doesn't yet include `prf` (a newer, Level 3
37
+ * extension), so this is declared locally rather than widening a global type. */
38
+ interface PrfClientExtensionResults {
39
+ prf?: {
40
+ enabled?: boolean;
41
+ results?: { first?: ArrayBuffer };
42
+ };
43
+ }
44
+
45
+ export interface PasskeyRegistration {
46
+ /** Base64url-encoded credential ID — stored as `MasterKeyWrap.methodId`. */
47
+ credentialId: string;
48
+ /** Whether this authenticator reported PRF support at registration time. A `false`/absent value here
49
+ * does not necessarily mean PRF evaluation will fail later on some platforms (some only report
50
+ * support upon first `get()`), but MUST be treated as "unknown/unlikely," not "yes." */
51
+ prfSupported: boolean;
52
+ }
53
+
54
+ /**
55
+ * Registers a new platform/roaming passkey for use purely as a local unlock method (see this module's
56
+ * doc comment for why no server round-trip is involved). `rpId` MUST be this deployment's own domain.
57
+ */
58
+ export async function registerPasskeyForUnlock(rpId: string, userId: Uint8Array, userName: string): Promise<PasskeyRegistration> {
59
+ const challenge = crypto.getRandomValues(new Uint8Array(CHALLENGE_LENGTH_BYTES));
60
+ const credential = (await navigator.credentials.create({
61
+ publicKey: {
62
+ rp: { id: rpId, name: rpId },
63
+ user: { id: userId as BufferSource, name: userName, displayName: userName },
64
+ challenge: challenge as BufferSource,
65
+ // ES256 - matches this system's P-256 default elsewhere (see crypto/keys.ts).
66
+ pubKeyCredParams: [{ type: "public-key", alg: -7 }],
67
+ authenticatorSelection: { residentKey: "preferred", userVerification: "required" },
68
+ extensions: { prf: {} },
69
+ },
70
+ })) as PublicKeyCredential;
71
+
72
+ const results = credential.getClientExtensionResults() as PrfClientExtensionResults;
73
+ return {
74
+ credentialId: toBase64Url(new Uint8Array(credential.rawId)),
75
+ prfSupported: !!results.prf?.enabled,
76
+ };
77
+ }
78
+
79
+ /**
80
+ * Evaluates the PRF extension for an already-registered passkey and HKDF-derives a wrapping key from the
81
+ * result. Throws if the authenticator doesn't return a PRF output (e.g. it doesn't support the
82
+ * extension) — callers MUST treat that as "this unlock method is unavailable here," not silently fall
83
+ * back to a weaker derivation.
84
+ */
85
+ export async function deriveFromPasskey(rpId: string, credentialId: string, salt: Uint8Array): Promise<Uint8Array> {
86
+ const challenge = crypto.getRandomValues(new Uint8Array(CHALLENGE_LENGTH_BYTES));
87
+ const assertion = (await navigator.credentials.get({
88
+ publicKey: {
89
+ rpId,
90
+ challenge: challenge as BufferSource,
91
+ allowCredentials: [{ id: fromBase64Url(credentialId) as BufferSource, type: "public-key" }],
92
+ userVerification: "required",
93
+ extensions: { prf: { eval: { first: salt as BufferSource } } },
94
+ },
95
+ })) as PublicKeyCredential;
96
+
97
+ const results = assertion.getClientExtensionResults() as PrfClientExtensionResults;
98
+ const prfOutput = results.prf?.results?.first;
99
+ if (!prfOutput) {
100
+ throw new Error("This passkey did not return a PRF result - it may not support the PRF extension.");
101
+ }
102
+ return hkdfDerive(new Uint8Array(prfOutput), salt, PRF_HKDF_INFO);
103
+ }