@rapidmx/web-client 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -14
- package/apps/admin/_layout.tsx +2 -2
- package/apps/admin/audit-log/index.tsx +4 -4
- package/apps/admin/branding/index.tsx +3 -3
- package/apps/admin/data-requests/index.tsx +8 -8
- package/apps/admin/distribution-lists/[uid].tsx +3 -3
- package/apps/admin/distribution-lists/index.tsx +4 -4
- package/apps/admin/distribution-lists/new/index.tsx +5 -5
- package/apps/admin/domains/[uid].tsx +6 -6
- package/apps/admin/domains/index.tsx +4 -4
- package/apps/admin/domains/new/index.tsx +5 -5
- package/apps/admin/encryption-policy/index.tsx +1 -1
- package/apps/admin/escrow-scopes/[uid].tsx +7 -7
- package/apps/admin/escrow-scopes/index.tsx +4 -4
- package/apps/admin/escrow-scopes/new/index.tsx +5 -5
- package/apps/admin/index.tsx +6 -6
- package/apps/admin/ingest-queue/index.tsx +4 -4
- package/apps/admin/mailbox-policy/index.tsx +1 -1
- package/apps/admin/mailboxes/[uid].tsx +5 -5
- package/apps/admin/quarantine/index.tsx +5 -5
- package/apps/admin/retention-policy/index.tsx +3 -3
- package/apps/admin/signing-certificates/index.tsx +5 -5
- package/apps/admin/transport-rules/[uid].tsx +5 -5
- package/apps/admin/transport-rules/_transportRuleConfig.tsx +3 -3
- package/apps/admin/transport-rules/index.tsx +4 -4
- package/apps/admin/transport-rules/new/index.tsx +5 -5
- package/apps/escrow/_layout.tsx +1 -1
- package/apps/escrow/audit-log/index.tsx +4 -4
- package/apps/escrow/index.tsx +4 -4
- package/apps/escrow/matters/[uid].tsx +10 -10
- package/apps/escrow/matters/new/index.tsx +6 -6
- package/apps/shared/appearance/AppearanceForm.tsx +3 -3
- package/apps/shared/appearance/AppearanceHead.tsx +1 -1
- package/apps/shared/appearance/AppearanceProvider.tsx +3 -3
- package/apps/shared/appearance/appearanceCache.ts +1 -1
- package/apps/shared/appearance/appearanceContext.ts +1 -1
- package/apps/shared/appearance/theme.ts +1 -1
- package/apps/shared/auth/adminAccess.ts +1 -1
- package/apps/shared/calendar/bookingPlugin.ts +1 -1
- package/apps/shared/calendar/calendarLiveUpdates.ts +1 -1
- package/apps/shared/calendar/calendarReminders.ts +1 -1
- package/apps/shared/calendar/useCalendarReminders.ts +1 -1
- package/apps/shared/components/admin/diagnostics/DiagnosticsManager.tsx +1 -1
- package/apps/shared/components/admin/diagnostics/InstalledPlugins.tsx +2 -2
- package/apps/shared/components/admin/diagnostics/LogsPanel.tsx +2 -2
- package/apps/shared/components/admin/diagnostics/PackagesTable.tsx +1 -1
- package/apps/shared/components/admin/diagnostics/RuntimePanel.tsx +1 -1
- package/apps/shared/components/admin/diagnostics/SystemPanel.tsx +2 -2
- package/apps/shared/components/admin/diagnostics/VersionsPanel.tsx +1 -1
- package/apps/shared/components/admin/diagnostics/diagnosticsApi.ts +1 -1
- package/apps/shared/components/admin/diagnostics/format.ts +1 -1
- package/apps/shared/components/admin/diagnostics/logClient.ts +1 -1
- package/apps/shared/components/admin/distributionLists/MemberListCard.tsx +4 -4
- package/apps/shared/components/admin/elevation.ts +1 -1
- package/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.tsx +3 -3
- package/apps/shared/components/admin/layout/AdminShell.tsx +8 -8
- package/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.tsx +6 -6
- package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +10 -8
- package/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.tsx +4 -4
- package/apps/shared/components/admin/mailboxes/MailboxTable.tsx +1 -1
- package/apps/shared/components/admin/mailboxes/ResourceSettingsCard.tsx +19 -14
- package/apps/shared/components/admin/mailboxes/ShareAccessCard.tsx +5 -5
- package/apps/shared/components/admin/settings/BrandingForm.tsx +5 -5
- package/apps/shared/components/admin/settings/DomainDnsSetup.tsx +5 -5
- package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +4 -4
- package/apps/shared/components/admin/settings/LoadedSettingsForm.tsx +2 -2
- package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +32 -27
- package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +4 -4
- package/apps/shared/components/admin/settings/PluginsManager.tsx +5 -5
- package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +5 -5
- package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +7 -7
- package/apps/shared/components/admin/setup/SetupWizard.tsx +28 -24
- package/apps/shared/components/admin/signOut.ts +1 -1
- package/apps/shared/components/admin/usePagedList.tsx +2 -2
- package/apps/shared/components/calendar/AppointmentQuickForm.tsx +3 -3
- package/apps/shared/components/calendar/CalendarListSidebar.tsx +3 -3
- package/apps/shared/components/calendar/DescriptionEditor.tsx +1 -1
- package/apps/shared/components/calendar/EventDescriptionView.tsx +1 -1
- package/apps/shared/components/calendar/EventDetails.tsx +16 -14
- package/apps/shared/components/calendar/EventEditor.tsx +54 -39
- package/apps/shared/components/calendar/EventExpandedForm.tsx +3 -3
- package/apps/shared/components/calendar/EventFormParts.tsx +2 -2
- package/apps/shared/components/calendar/EventModal.tsx +5 -5
- package/apps/shared/components/calendar/EventQuickForm.tsx +3 -3
- package/apps/shared/components/calendar/EventShell.tsx +1 -1
- package/apps/shared/components/calendar/FindATime.tsx +6 -4
- package/apps/shared/components/calendar/GuestInput.tsx +2 -2
- package/apps/shared/components/calendar/MonthView.tsx +2 -2
- package/apps/shared/components/calendar/QuickCreateFaces.tsx +1 -1
- package/apps/shared/components/calendar/QuickFaceFrame.tsx +1 -1
- package/apps/shared/components/calendar/RecurrenceEditor.tsx +2 -2
- package/apps/shared/components/calendar/RequestChangeForm.tsx +8 -6
- package/apps/shared/components/calendar/ResourcePicker.tsx +7 -5
- package/apps/shared/components/calendar/SplitDayView.tsx +1 -1
- package/apps/shared/components/calendar/TaskQuickForm.tsx +23 -18
- package/apps/shared/components/calendar/TimeGridView.tsx +5 -3
- package/apps/shared/components/calendar/allDay.ts +2 -2
- package/apps/shared/components/calendar/eventDialogFields.ts +3 -3
- package/apps/shared/components/calendar/eventForm.ts +3 -3
- package/apps/shared/components/calendar/eventFormat.ts +3 -3
- package/apps/shared/components/calendar/findTimeGrid.ts +2 -2
- package/apps/shared/components/calendar/layout/CalendarShell.tsx +11 -9
- package/apps/shared/components/contacts/ContactDetailPane.tsx +4 -4
- package/apps/shared/components/contacts/ContactForm.tsx +27 -17
- package/apps/shared/components/contacts/ContactsSidebar.tsx +7 -5
- package/apps/shared/components/contacts/KeyChangeReview.tsx +5 -5
- package/apps/shared/components/contacts/contactKeys.ts +3 -3
- package/apps/shared/components/contacts/layout/ContactsShell.tsx +9 -7
- package/apps/shared/components/escrow/layout/EscrowShell.tsx +6 -6
- package/apps/shared/components/forms/StringListField.tsx +1 -1
- package/apps/shared/components/layout/AppShell.tsx +12 -10
- package/apps/shared/components/layout/BrandingChrome.tsx +1 -1
- package/apps/shared/components/layout/KeyEnrollmentGate.tsx +9 -9
- package/apps/shared/components/layout/MailboxProvisioning.tsx +8 -6
- package/apps/shared/components/layout/RecoveryCodeUnlock.tsx +9 -9
- package/apps/shared/components/layout/ThemeSwitch.tsx +1 -1
- package/apps/shared/components/layout/UnlockPromptProvider.tsx +6 -6
- package/apps/shared/components/layout/UserMenu.tsx +6 -4
- package/apps/shared/components/mail/ConversationList.tsx +25 -10
- package/apps/shared/components/mail/ConversationThreadPane.tsx +33 -17
- package/apps/shared/components/mail/InviteCard.tsx +11 -9
- package/apps/shared/components/mail/LazyReadingPane.tsx +2 -2
- package/apps/shared/components/mail/MailAddress.tsx +1 -1
- package/apps/shared/components/mail/MailListToolbar.tsx +2 -2
- package/apps/shared/components/mail/MailSelectionBar.tsx +2 -2
- package/apps/shared/components/mail/MenuButton.tsx +1 -1
- package/apps/shared/components/mail/MessageDetailPane.tsx +69 -48
- package/apps/shared/components/mail/MoveToFolderDialog.tsx +8 -6
- package/apps/shared/components/mail/OutboxRowStatus.tsx +1 -1
- package/apps/shared/components/mail/PermanentDeleteDialog.tsx +2 -2
- package/apps/shared/components/mail/compose/ComposeContext.tsx +14 -3
- package/apps/shared/components/mail/compose/ComposeWindow.tsx +34 -30
- package/apps/shared/components/mail/compose/ComposeWindowPlaceholder.tsx +4 -4
- package/apps/shared/components/mail/compose/EmojiPicker.tsx +2 -2
- package/apps/shared/components/mail/compose/GifPicker.tsx +3 -3
- package/apps/shared/components/mail/compose/RecipientInput.tsx +1 -1
- package/apps/shared/components/mail/compose/ScheduleSendPicker.tsx +1 -1
- package/apps/shared/components/mail/compose/encryptionRequirement.ts +2 -2
- package/apps/shared/components/mail/compose/quotedBody.ts +5 -5
- package/apps/shared/components/mail/compose/recipients.ts +1 -1
- package/apps/shared/components/mail/invite/InviteRowChip.tsx +10 -14
- package/apps/shared/components/mail/invite/InviteRsvpPopover.tsx +11 -9
- package/apps/shared/components/mail/invite/InviteTimeline.tsx +1 -1
- package/apps/shared/components/mail/invite/ProposeTimeForm.tsx +2 -2
- package/apps/shared/components/mail/invite/inviteFormat.ts +2 -2
- package/apps/shared/components/mail/invite/inviteStore.ts +14 -6
- package/apps/shared/components/mail/labelMenu.tsx +9 -7
- package/apps/shared/components/mail/layout/MailShell.tsx +4 -4
- package/apps/shared/components/mail/listPreferences.ts +2 -2
- package/apps/shared/components/mail/pinnedSigners.ts +45 -19
- package/apps/shared/components/mail/reading/EncryptedBody.tsx +2 -2
- package/apps/shared/components/mail/reading/MessageBody.tsx +6 -6
- package/apps/shared/components/mail/reading/MessageCard.tsx +3 -3
- package/apps/shared/components/mail/reading/MessageSourceDialog.tsx +3 -3
- package/apps/shared/components/mail/reading/PendingMessageCard.tsx +1 -1
- package/apps/shared/components/mail/reading/bodyContent.ts +3 -3
- package/apps/shared/components/mail/reading/bodyHtml.ts +1 -1
- package/apps/shared/components/mail/reading/conversationPrint.ts +76 -0
- package/apps/shared/components/mail/reading/messageExport.ts +1 -1
- package/apps/shared/components/mail/reading/printMessage.ts +46 -9
- package/apps/shared/components/mail/reading/useMessageActions.ts +28 -21
- package/apps/shared/components/mail/unreadStyle.tsx +1 -1
- package/apps/shared/components/mail/verificationSeals.ts +16 -12
- package/apps/shared/components/mail/writableMailboxes.ts +14 -7
- package/apps/shared/components/rules/RuleBuilder.tsx +1 -1
- package/apps/shared/components/settings/SigningCertificateCard.tsx +4 -4
- package/apps/shared/components/settings/layout/SettingsShell.tsx +8 -6
- package/apps/shared/components/sharing/PrincipalListField.tsx +1 -1
- package/apps/shared/components/sharing/PrincipalPicker.tsx +1 -1
- package/apps/shared/components/sharing/PrincipalResolver.tsx +4 -4
- package/apps/shared/components/tasks/TasksSidebar.tsx +7 -5
- package/apps/shared/components/tasks/layout/TasksShell.tsx +9 -7
- package/apps/shared/keyboard/ShortcutsDialog.tsx +1 -1
- package/apps/shared/keyboard/keymap.ts +1 -0
- package/apps/shared/mail/decryptedMessages.ts +116 -0
- package/apps/shared/mail/findWellKnownFolderUid.ts +6 -4
- package/apps/shared/mail/folderCounts.ts +8 -4
- package/apps/shared/mail/folderOfType.ts +5 -3
- package/apps/shared/mail/folderTree.ts +1 -1
- package/apps/shared/mail/listSnapshots.ts +2 -2
- package/apps/shared/mail/messageReadState.ts +6 -5
- package/apps/shared/mail/newMailNotifications.ts +2 -2
- package/apps/shared/mail/outbox/composeBridge.ts +2 -2
- package/apps/shared/mail/outbox/outboxState.ts +1 -1
- package/apps/shared/mail/outbox/outgoingReplies.ts +2 -2
- package/apps/shared/mail/outbox/sendDecision.ts +2 -2
- package/apps/shared/mail/outbox/sendJob.ts +40 -35
- package/apps/shared/mail/outbox/sendOutcomes.ts +20 -15
- package/apps/shared/mail/outbox/useOutboxStatus.ts +5 -3
- package/apps/shared/mail/permanentDelete.ts +8 -7
- package/apps/shared/mail/primaryMailbox.ts +1 -1
- package/apps/shared/mail/reportNotices.ts +1 -1
- package/apps/shared/mail/senderBlocking.ts +36 -20
- package/apps/shared/mail/useMailConnection.ts +12 -10
- package/apps/shared/mail/useMailLiveUpdates.ts +3 -3
- package/apps/shared/mail/useMailboxUpdateAccess.ts +35 -11
- package/apps/shared/mail/useMarkMessageRead.ts +14 -7
- package/apps/shared/mail/useNewMailNotifications.ts +1 -1
- package/apps/shared/mail/usePermanentDelete.tsx +5 -3
- package/apps/shared/navigation/pageTitle.ts +1 -1
- package/apps/shared/notifications/NotificationCenter.tsx +1 -1
- package/apps/shared/notifications/NotificationHistoryDialog.tsx +2 -2
- package/apps/shared/notifications/apiErrors.ts +2 -2
- package/apps/shared/notifications/pushStatus.ts +1 -1
- package/apps/shared/notifications/systemErrors.ts +1 -1
- package/apps/shared/search/LocalIndexLifecycle.tsx +18 -12
- package/apps/shared/search/crossMailboxSearch.ts +3 -3
- package/apps/shared/search/localIndexBuilder.ts +24 -12
- package/apps/shared/search/localIndexKey.ts +1 -1
- package/apps/shared/search/localIndexRpcClient.ts +150 -30
- package/apps/shared/search/localIndexTransport.ts +84 -0
- package/apps/shared/search/localIndexWorker.ts +1 -1
- package/apps/shared/search/searchTier2.ts +3 -3
- package/apps/shared/signing/enrollmentTracker.ts +3 -3
- package/apps/shared/signing/enrollmentView.ts +1 -1
- package/apps/shared/signing/signingInfo.ts +1 -1
- package/apps/shared/signing/useSigningEnrollmentWatcher.ts +6 -4
- package/apps/shared/styles/app.css +14 -23
- package/apps/www/_layout.tsx +2 -2
- package/apps/www/calendar/index.tsx +20 -18
- package/apps/www/contacts/[uid].tsx +8 -6
- package/apps/www/contacts/index.tsx +19 -17
- package/apps/www/index.tsx +68 -48
- package/apps/www/messages/[uid].tsx +11 -9
- package/apps/www/settings/auto-reply/index.tsx +6 -4
- package/apps/www/settings/blocked-senders/index.tsx +9 -7
- package/apps/www/settings/encryption/index.tsx +38 -32
- package/apps/www/settings/filters/[uid].tsx +19 -14
- package/apps/www/settings/filters/_mailFilterRuleConfig.tsx +2 -2
- package/apps/www/settings/filters/index.tsx +4 -4
- package/apps/www/settings/filters/new/index.tsx +10 -8
- package/apps/www/settings/labels/index.tsx +12 -10
- package/apps/www/settings/privacy/index.tsx +18 -14
- package/apps/www/settings/profile/index.tsx +16 -11
- package/apps/www/settings/read-receipts/index.tsx +17 -12
- package/apps/www/settings/sharing/index.tsx +6 -6
- package/apps/www/settings/signatures/[uid].tsx +5 -5
- package/apps/www/settings/signatures/index.tsx +4 -4
- package/apps/www/settings/signatures/new/index.tsx +4 -4
- package/apps/www/settings/signatures/signatureDefaults.ts +1 -1
- package/apps/www/tasks/index.tsx +28 -23
- package/dist/apps/admin/_layout.d.ts +1 -1
- package/dist/apps/admin/_layout.js +1 -1
- package/dist/apps/admin/audit-log/index.d.ts +1 -1
- package/dist/apps/admin/audit-log/index.js +4 -4
- package/dist/apps/admin/branding/index.js +3 -3
- package/dist/apps/admin/data-requests/index.js +8 -8
- package/dist/apps/admin/distribution-lists/[uid].js +3 -3
- package/dist/apps/admin/distribution-lists/index.js +4 -4
- package/dist/apps/admin/distribution-lists/new/index.js +5 -5
- package/dist/apps/admin/domains/[uid].js +6 -6
- package/dist/apps/admin/domains/index.js +4 -4
- package/dist/apps/admin/domains/new/index.js +5 -5
- package/dist/apps/admin/encryption-policy/index.js +1 -1
- package/dist/apps/admin/escrow-scopes/[uid].d.ts +1 -1
- package/dist/apps/admin/escrow-scopes/[uid].js +7 -7
- package/dist/apps/admin/escrow-scopes/index.js +4 -4
- package/dist/apps/admin/escrow-scopes/new/index.js +5 -5
- package/dist/apps/admin/index.js +6 -6
- package/dist/apps/admin/ingest-queue/index.js +4 -4
- package/dist/apps/admin/mailbox-policy/index.js +1 -1
- package/dist/apps/admin/mailboxes/[uid].js +5 -5
- package/dist/apps/admin/quarantine/index.js +5 -5
- package/dist/apps/admin/retention-policy/index.js +3 -3
- package/dist/apps/admin/signing-certificates/index.js +5 -5
- package/dist/apps/admin/transport-rules/[uid].js +5 -5
- package/dist/apps/admin/transport-rules/_transportRuleConfig.d.ts +1 -1
- package/dist/apps/admin/transport-rules/_transportRuleConfig.js +2 -2
- package/dist/apps/admin/transport-rules/index.js +4 -4
- package/dist/apps/admin/transport-rules/new/index.js +5 -5
- package/dist/apps/escrow/_layout.d.ts +1 -1
- package/dist/apps/escrow/audit-log/index.d.ts +1 -1
- package/dist/apps/escrow/audit-log/index.js +4 -4
- package/dist/apps/escrow/index.js +4 -4
- package/dist/apps/escrow/matters/[uid].js +10 -10
- package/dist/apps/escrow/matters/new/index.js +6 -6
- package/dist/apps/shared/appearance/AppearanceForm.js +3 -3
- package/dist/apps/shared/appearance/AppearanceHead.js +1 -1
- package/dist/apps/shared/appearance/AppearanceProvider.d.ts +1 -1
- package/dist/apps/shared/appearance/AppearanceProvider.js +3 -3
- package/dist/apps/shared/appearance/appearanceCache.d.ts +1 -1
- package/dist/apps/shared/appearance/appearanceCache.js +1 -1
- package/dist/apps/shared/appearance/appearanceContext.d.ts +1 -1
- package/dist/apps/shared/appearance/theme.d.ts +1 -1
- package/dist/apps/shared/auth/adminAccess.js +1 -1
- package/dist/apps/shared/calendar/bookingPlugin.js +1 -1
- package/dist/apps/shared/calendar/calendarLiveUpdates.d.ts +1 -1
- package/dist/apps/shared/calendar/calendarReminders.d.ts +1 -1
- package/dist/apps/shared/calendar/useCalendarReminders.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/DiagnosticsManager.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/InstalledPlugins.d.ts +1 -1
- package/dist/apps/shared/components/admin/diagnostics/InstalledPlugins.js +2 -2
- package/dist/apps/shared/components/admin/diagnostics/LogsPanel.js +2 -2
- package/dist/apps/shared/components/admin/diagnostics/PackagesTable.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/RuntimePanel.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/SystemPanel.js +2 -2
- package/dist/apps/shared/components/admin/diagnostics/VersionsPanel.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/diagnosticsApi.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/format.js +1 -1
- package/dist/apps/shared/components/admin/diagnostics/logClient.js +1 -1
- package/dist/apps/shared/components/admin/distributionLists/MemberListCard.d.ts +1 -1
- package/dist/apps/shared/components/admin/distributionLists/MemberListCard.js +4 -4
- package/dist/apps/shared/components/admin/elevation.js +1 -1
- package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.js +3 -3
- package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +1 -1
- package/dist/apps/shared/components/admin/layout/AdminShell.js +7 -7
- package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.d.ts +1 -1
- package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.js +6 -6
- package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.d.ts +1 -1
- package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.js +10 -8
- package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.js +4 -4
- package/dist/apps/shared/components/admin/mailboxes/MailboxTable.d.ts +1 -1
- package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.d.ts +1 -1
- package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.js +7 -5
- package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.js +5 -5
- package/dist/apps/shared/components/admin/settings/BrandingForm.d.ts +1 -1
- package/dist/apps/shared/components/admin/settings/BrandingForm.js +5 -5
- package/dist/apps/shared/components/admin/settings/DomainDnsSetup.d.ts +1 -1
- package/dist/apps/shared/components/admin/settings/DomainDnsSetup.js +5 -5
- package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.d.ts +1 -1
- package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.js +4 -4
- package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.js +2 -2
- package/dist/apps/shared/components/admin/settings/MailboxCreateForm.d.ts +1 -1
- package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +14 -12
- package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.d.ts +1 -1
- package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.js +4 -4
- package/dist/apps/shared/components/admin/settings/PluginsManager.js +5 -5
- package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.d.ts +1 -1
- package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.js +5 -5
- package/dist/apps/shared/components/admin/setup/EscrowSetupStep.js +7 -7
- package/dist/apps/shared/components/admin/setup/SetupWizard.d.ts +4 -4
- package/dist/apps/shared/components/admin/setup/SetupWizard.js +27 -23
- package/dist/apps/shared/components/admin/signOut.js +1 -1
- package/dist/apps/shared/components/admin/usePagedList.js +2 -2
- package/dist/apps/shared/components/calendar/AppointmentQuickForm.js +3 -3
- package/dist/apps/shared/components/calendar/CalendarListSidebar.d.ts +1 -1
- package/dist/apps/shared/components/calendar/CalendarListSidebar.js +2 -2
- package/dist/apps/shared/components/calendar/DescriptionEditor.js +1 -1
- package/dist/apps/shared/components/calendar/EventDescriptionView.js +1 -1
- package/dist/apps/shared/components/calendar/EventDetails.d.ts +2 -2
- package/dist/apps/shared/components/calendar/EventDetails.js +16 -14
- package/dist/apps/shared/components/calendar/EventEditor.d.ts +2 -2
- package/dist/apps/shared/components/calendar/EventEditor.js +22 -20
- package/dist/apps/shared/components/calendar/EventExpandedForm.js +2 -2
- package/dist/apps/shared/components/calendar/EventFormParts.d.ts +1 -1
- package/dist/apps/shared/components/calendar/EventFormParts.js +1 -1
- package/dist/apps/shared/components/calendar/EventModal.d.ts +2 -2
- package/dist/apps/shared/components/calendar/EventModal.js +3 -3
- package/dist/apps/shared/components/calendar/EventQuickForm.js +3 -3
- package/dist/apps/shared/components/calendar/EventShell.js +1 -1
- package/dist/apps/shared/components/calendar/FindATime.js +6 -4
- package/dist/apps/shared/components/calendar/GuestInput.d.ts +2 -2
- package/dist/apps/shared/components/calendar/MonthView.d.ts +1 -1
- package/dist/apps/shared/components/calendar/MonthView.js +1 -1
- package/dist/apps/shared/components/calendar/QuickCreateFaces.js +1 -1
- package/dist/apps/shared/components/calendar/QuickFaceFrame.js +1 -1
- package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +1 -1
- package/dist/apps/shared/components/calendar/RecurrenceEditor.js +1 -1
- package/dist/apps/shared/components/calendar/RequestChangeForm.js +8 -6
- package/dist/apps/shared/components/calendar/ResourcePicker.d.ts +1 -1
- package/dist/apps/shared/components/calendar/ResourcePicker.js +7 -5
- package/dist/apps/shared/components/calendar/SplitDayView.d.ts +1 -1
- package/dist/apps/shared/components/calendar/TaskQuickForm.d.ts +1 -1
- package/dist/apps/shared/components/calendar/TaskQuickForm.js +9 -7
- package/dist/apps/shared/components/calendar/TimeGridView.d.ts +1 -1
- package/dist/apps/shared/components/calendar/TimeGridView.js +2 -2
- package/dist/apps/shared/components/calendar/allDay.d.ts +2 -2
- package/dist/apps/shared/components/calendar/allDay.js +1 -1
- package/dist/apps/shared/components/calendar/eventDialogFields.d.ts +2 -2
- package/dist/apps/shared/components/calendar/eventDialogFields.js +2 -2
- package/dist/apps/shared/components/calendar/eventForm.d.ts +3 -3
- package/dist/apps/shared/components/calendar/eventFormat.d.ts +1 -1
- package/dist/apps/shared/components/calendar/eventFormat.js +2 -2
- package/dist/apps/shared/components/calendar/findTimeGrid.d.ts +1 -1
- package/dist/apps/shared/components/calendar/findTimeGrid.js +1 -1
- package/dist/apps/shared/components/calendar/layout/CalendarShell.d.ts +1 -1
- package/dist/apps/shared/components/calendar/layout/CalendarShell.js +11 -9
- package/dist/apps/shared/components/contacts/ContactDetailPane.d.ts +1 -1
- package/dist/apps/shared/components/contacts/ContactDetailPane.js +2 -2
- package/dist/apps/shared/components/contacts/ContactForm.d.ts +2 -2
- package/dist/apps/shared/components/contacts/ContactForm.js +12 -8
- package/dist/apps/shared/components/contacts/ContactsSidebar.d.ts +1 -1
- package/dist/apps/shared/components/contacts/ContactsSidebar.js +7 -5
- package/dist/apps/shared/components/contacts/KeyChangeReview.d.ts +1 -1
- package/dist/apps/shared/components/contacts/KeyChangeReview.js +5 -5
- package/dist/apps/shared/components/contacts/contactKeys.d.ts +2 -2
- package/dist/apps/shared/components/contacts/contactKeys.js +2 -2
- package/dist/apps/shared/components/contacts/layout/ContactsShell.d.ts +1 -1
- package/dist/apps/shared/components/contacts/layout/ContactsShell.js +9 -7
- package/dist/apps/shared/components/escrow/layout/EscrowShell.js +6 -6
- package/dist/apps/shared/components/forms/StringListField.js +1 -1
- package/dist/apps/shared/components/layout/AppShell.d.ts +2 -2
- package/dist/apps/shared/components/layout/AppShell.js +11 -9
- package/dist/apps/shared/components/layout/BrandingChrome.d.ts +1 -1
- package/dist/apps/shared/components/layout/KeyEnrollmentGate.d.ts +1 -1
- package/dist/apps/shared/components/layout/KeyEnrollmentGate.js +9 -9
- package/dist/apps/shared/components/layout/MailboxProvisioning.js +8 -6
- package/dist/apps/shared/components/layout/RecoveryCodeUnlock.d.ts +1 -1
- package/dist/apps/shared/components/layout/RecoveryCodeUnlock.js +9 -9
- package/dist/apps/shared/components/layout/UnlockPromptProvider.d.ts +2 -2
- package/dist/apps/shared/components/layout/UnlockPromptProvider.js +5 -5
- package/dist/apps/shared/components/layout/UserMenu.js +6 -4
- package/dist/apps/shared/components/mail/ConversationList.d.ts +2 -2
- package/dist/apps/shared/components/mail/ConversationList.js +23 -8
- package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +3 -3
- package/dist/apps/shared/components/mail/ConversationThreadPane.js +19 -13
- package/dist/apps/shared/components/mail/InviteCard.js +10 -8
- package/dist/apps/shared/components/mail/LazyReadingPane.js +2 -2
- package/dist/apps/shared/components/mail/MailAddress.d.ts +1 -1
- package/dist/apps/shared/components/mail/MailAddress.js +1 -1
- package/dist/apps/shared/components/mail/MailListToolbar.d.ts +2 -2
- package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +2 -2
- package/dist/apps/shared/components/mail/MenuButton.js +1 -1
- package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +3 -3
- package/dist/apps/shared/components/mail/MessageDetailPane.js +61 -46
- package/dist/apps/shared/components/mail/MoveToFolderDialog.d.ts +1 -1
- package/dist/apps/shared/components/mail/MoveToFolderDialog.js +8 -6
- package/dist/apps/shared/components/mail/OutboxRowStatus.d.ts +1 -1
- package/dist/apps/shared/components/mail/PermanentDeleteDialog.js +2 -2
- package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +10 -1
- package/dist/apps/shared/components/mail/compose/ComposeContext.js +4 -2
- package/dist/apps/shared/components/mail/compose/ComposeWindow.js +34 -30
- package/dist/apps/shared/components/mail/compose/ComposeWindowPlaceholder.js +4 -4
- package/dist/apps/shared/components/mail/compose/EmojiPicker.js +2 -2
- package/dist/apps/shared/components/mail/compose/GifPicker.js +3 -3
- package/dist/apps/shared/components/mail/compose/RecipientInput.d.ts +1 -1
- package/dist/apps/shared/components/mail/compose/RecipientInput.js +1 -1
- package/dist/apps/shared/components/mail/compose/ScheduleSendPicker.js +1 -1
- package/dist/apps/shared/components/mail/compose/encryptionRequirement.d.ts +2 -2
- package/dist/apps/shared/components/mail/compose/encryptionRequirement.js +1 -1
- package/dist/apps/shared/components/mail/compose/quotedBody.d.ts +3 -3
- package/dist/apps/shared/components/mail/compose/quotedBody.js +3 -3
- package/dist/apps/shared/components/mail/compose/recipients.d.ts +1 -1
- package/dist/apps/shared/components/mail/invite/InviteRowChip.d.ts +3 -3
- package/dist/apps/shared/components/mail/invite/InviteRowChip.js +7 -9
- package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.d.ts +2 -2
- package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.js +11 -9
- package/dist/apps/shared/components/mail/invite/InviteTimeline.d.ts +1 -1
- package/dist/apps/shared/components/mail/invite/ProposeTimeForm.d.ts +1 -1
- package/dist/apps/shared/components/mail/invite/ProposeTimeForm.js +1 -1
- package/dist/apps/shared/components/mail/invite/inviteFormat.d.ts +2 -2
- package/dist/apps/shared/components/mail/invite/inviteStore.d.ts +9 -3
- package/dist/apps/shared/components/mail/invite/inviteStore.js +13 -6
- package/dist/apps/shared/components/mail/labelMenu.d.ts +1 -1
- package/dist/apps/shared/components/mail/labelMenu.js +9 -7
- package/dist/apps/shared/components/mail/layout/MailShell.d.ts +1 -1
- package/dist/apps/shared/components/mail/layout/MailShell.js +3 -3
- package/dist/apps/shared/components/mail/listPreferences.d.ts +2 -2
- package/dist/apps/shared/components/mail/listPreferences.js +1 -1
- package/dist/apps/shared/components/mail/pinnedSigners.d.ts +12 -5
- package/dist/apps/shared/components/mail/pinnedSigners.js +37 -18
- package/dist/apps/shared/components/mail/reading/EncryptedBody.js +2 -2
- package/dist/apps/shared/components/mail/reading/MessageBody.d.ts +2 -2
- package/dist/apps/shared/components/mail/reading/MessageBody.js +4 -4
- package/dist/apps/shared/components/mail/reading/MessageCard.d.ts +1 -1
- package/dist/apps/shared/components/mail/reading/MessageCard.js +2 -2
- package/dist/apps/shared/components/mail/reading/MessageSourceDialog.js +3 -3
- package/dist/apps/shared/components/mail/reading/PendingMessageCard.js +1 -1
- package/dist/apps/shared/components/mail/reading/bodyContent.d.ts +2 -2
- package/dist/apps/shared/components/mail/reading/bodyContent.js +2 -2
- package/dist/apps/shared/components/mail/reading/bodyHtml.js +1 -1
- package/dist/apps/shared/components/mail/reading/conversationPrint.d.ts +15 -0
- package/dist/apps/shared/components/mail/reading/conversationPrint.js +69 -0
- package/dist/apps/shared/components/mail/reading/messageExport.js +1 -1
- package/dist/apps/shared/components/mail/reading/printMessage.d.ts +9 -3
- package/dist/apps/shared/components/mail/reading/printMessage.js +33 -6
- package/dist/apps/shared/components/mail/reading/useMessageActions.d.ts +1 -1
- package/dist/apps/shared/components/mail/reading/useMessageActions.js +18 -16
- package/dist/apps/shared/components/mail/unreadStyle.d.ts +1 -1
- package/dist/apps/shared/components/mail/verificationSeals.d.ts +27 -6
- package/dist/apps/shared/components/mail/verificationSeals.js +15 -11
- package/dist/apps/shared/components/mail/writableMailboxes.d.ts +8 -3
- package/dist/apps/shared/components/mail/writableMailboxes.js +12 -6
- package/dist/apps/shared/components/rules/RuleBuilder.js +1 -1
- package/dist/apps/shared/components/settings/SigningCertificateCard.d.ts +1 -1
- package/dist/apps/shared/components/settings/SigningCertificateCard.js +3 -3
- package/dist/apps/shared/components/settings/layout/SettingsShell.d.ts +1 -1
- package/dist/apps/shared/components/settings/layout/SettingsShell.js +8 -6
- package/dist/apps/shared/components/sharing/PrincipalListField.d.ts +1 -1
- package/dist/apps/shared/components/sharing/PrincipalPicker.d.ts +1 -1
- package/dist/apps/shared/components/sharing/PrincipalPicker.js +1 -1
- package/dist/apps/shared/components/sharing/PrincipalResolver.d.ts +1 -1
- package/dist/apps/shared/components/sharing/PrincipalResolver.js +3 -3
- package/dist/apps/shared/components/tasks/TasksSidebar.d.ts +1 -1
- package/dist/apps/shared/components/tasks/TasksSidebar.js +7 -5
- package/dist/apps/shared/components/tasks/layout/TasksShell.d.ts +1 -1
- package/dist/apps/shared/components/tasks/layout/TasksShell.js +9 -7
- package/dist/apps/shared/keyboard/ShortcutsDialog.js +1 -1
- package/dist/apps/shared/keyboard/keymap.d.ts +6 -0
- package/dist/apps/shared/keyboard/keymap.js +1 -0
- package/dist/apps/shared/mail/decryptedMessages.d.ts +27 -0
- package/dist/apps/shared/mail/decryptedMessages.js +97 -0
- package/dist/apps/shared/mail/findWellKnownFolderUid.d.ts +5 -3
- package/dist/apps/shared/mail/findWellKnownFolderUid.js +5 -4
- package/dist/apps/shared/mail/folderCounts.d.ts +1 -1
- package/dist/apps/shared/mail/folderCounts.js +6 -4
- package/dist/apps/shared/mail/folderOfType.d.ts +3 -2
- package/dist/apps/shared/mail/folderOfType.js +4 -4
- package/dist/apps/shared/mail/folderTree.d.ts +1 -1
- package/dist/apps/shared/mail/listSnapshots.d.ts +2 -2
- package/dist/apps/shared/mail/messageReadState.d.ts +4 -3
- package/dist/apps/shared/mail/messageReadState.js +5 -5
- package/dist/apps/shared/mail/newMailNotifications.d.ts +1 -1
- package/dist/apps/shared/mail/newMailNotifications.js +1 -1
- package/dist/apps/shared/mail/outbox/composeBridge.d.ts +2 -2
- package/dist/apps/shared/mail/outbox/outboxState.d.ts +1 -1
- package/dist/apps/shared/mail/outbox/outgoingReplies.d.ts +2 -2
- package/dist/apps/shared/mail/outbox/sendDecision.d.ts +2 -2
- package/dist/apps/shared/mail/outbox/sendDecision.js +1 -1
- package/dist/apps/shared/mail/outbox/sendJob.d.ts +10 -6
- package/dist/apps/shared/mail/outbox/sendJob.js +39 -35
- package/dist/apps/shared/mail/outbox/sendOutcomes.d.ts +6 -3
- package/dist/apps/shared/mail/outbox/sendOutcomes.js +19 -15
- package/dist/apps/shared/mail/outbox/useOutboxStatus.js +5 -3
- package/dist/apps/shared/mail/permanentDelete.d.ts +4 -3
- package/dist/apps/shared/mail/permanentDelete.js +8 -8
- package/dist/apps/shared/mail/primaryMailbox.d.ts +1 -1
- package/dist/apps/shared/mail/primaryMailbox.js +1 -1
- package/dist/apps/shared/mail/reportNotices.d.ts +1 -1
- package/dist/apps/shared/mail/senderBlocking.d.ts +5 -4
- package/dist/apps/shared/mail/senderBlocking.js +19 -16
- package/dist/apps/shared/mail/useMailConnection.d.ts +1 -1
- package/dist/apps/shared/mail/useMailConnection.js +12 -10
- package/dist/apps/shared/mail/useMailLiveUpdates.d.ts +2 -2
- package/dist/apps/shared/mail/useMailLiveUpdates.js +2 -2
- package/dist/apps/shared/mail/useMailboxUpdateAccess.d.ts +3 -2
- package/dist/apps/shared/mail/useMailboxUpdateAccess.js +31 -10
- package/dist/apps/shared/mail/useMarkMessageRead.d.ts +1 -1
- package/dist/apps/shared/mail/useMarkMessageRead.js +5 -3
- package/dist/apps/shared/mail/useNewMailNotifications.d.ts +1 -1
- package/dist/apps/shared/mail/usePermanentDelete.d.ts +1 -1
- package/dist/apps/shared/mail/usePermanentDelete.js +4 -2
- package/dist/apps/shared/navigation/pageTitle.d.ts +1 -1
- package/dist/apps/shared/notifications/NotificationCenter.js +1 -1
- package/dist/apps/shared/notifications/NotificationHistoryDialog.js +2 -2
- package/dist/apps/shared/notifications/apiErrors.js +2 -2
- package/dist/apps/shared/notifications/pushStatus.js +1 -1
- package/dist/apps/shared/notifications/systemErrors.js +1 -1
- package/dist/apps/shared/search/LocalIndexLifecycle.d.ts +2 -2
- package/dist/apps/shared/search/LocalIndexLifecycle.js +15 -10
- package/dist/apps/shared/search/crossMailboxSearch.d.ts +1 -1
- package/dist/apps/shared/search/crossMailboxSearch.js +2 -2
- package/dist/apps/shared/search/localIndexBuilder.d.ts +4 -3
- package/dist/apps/shared/search/localIndexBuilder.js +15 -12
- package/dist/apps/shared/search/localIndexKey.js +1 -1
- package/dist/apps/shared/search/localIndexRpcClient.d.ts +43 -31
- package/dist/apps/shared/search/localIndexRpcClient.js +113 -20
- package/dist/apps/shared/search/localIndexTransport.d.ts +77 -0
- package/dist/apps/shared/search/localIndexTransport.js +1 -0
- package/dist/apps/shared/search/localIndexWorker.d.ts +1 -1
- package/dist/apps/shared/search/searchTier2.d.ts +3 -3
- package/dist/apps/shared/signing/enrollmentTracker.d.ts +1 -1
- package/dist/apps/shared/signing/enrollmentTracker.js +3 -3
- package/dist/apps/shared/signing/enrollmentView.d.ts +1 -1
- package/dist/apps/shared/signing/signingInfo.d.ts +1 -1
- package/dist/apps/shared/signing/signingInfo.js +1 -1
- package/dist/apps/shared/signing/useSigningEnrollmentWatcher.d.ts +1 -1
- package/dist/apps/shared/signing/useSigningEnrollmentWatcher.js +5 -3
- package/dist/apps/shared/styles/app.css +14 -23
- package/dist/apps/www/_layout.d.ts +1 -1
- package/dist/apps/www/_layout.js +1 -1
- package/dist/apps/www/calendar/index.d.ts +1 -1
- package/dist/apps/www/calendar/index.js +20 -18
- package/dist/apps/www/contacts/[uid].d.ts +1 -1
- package/dist/apps/www/contacts/[uid].js +8 -6
- package/dist/apps/www/contacts/index.d.ts +1 -1
- package/dist/apps/www/contacts/index.js +19 -17
- package/dist/apps/www/index.d.ts +1 -1
- package/dist/apps/www/index.js +64 -50
- package/dist/apps/www/messages/[uid].d.ts +1 -1
- package/dist/apps/www/messages/[uid].js +11 -9
- package/dist/apps/www/settings/appearance/index.d.ts +1 -1
- package/dist/apps/www/settings/auto-reply/index.d.ts +1 -1
- package/dist/apps/www/settings/auto-reply/index.js +6 -4
- package/dist/apps/www/settings/blocked-senders/index.d.ts +1 -1
- package/dist/apps/www/settings/blocked-senders/index.js +6 -4
- package/dist/apps/www/settings/encryption/index.d.ts +1 -1
- package/dist/apps/www/settings/encryption/index.js +31 -29
- package/dist/apps/www/settings/filters/[uid].d.ts +1 -1
- package/dist/apps/www/settings/filters/[uid].js +11 -9
- package/dist/apps/www/settings/filters/_mailFilterRuleConfig.d.ts +2 -2
- package/dist/apps/www/settings/filters/index.d.ts +1 -1
- package/dist/apps/www/settings/filters/index.js +4 -4
- package/dist/apps/www/settings/filters/new/index.d.ts +1 -1
- package/dist/apps/www/settings/filters/new/index.js +10 -8
- package/dist/apps/www/settings/labels/index.d.ts +1 -1
- package/dist/apps/www/settings/labels/index.js +12 -10
- package/dist/apps/www/settings/privacy/index.d.ts +1 -1
- package/dist/apps/www/settings/privacy/index.js +18 -14
- package/dist/apps/www/settings/profile/index.d.ts +1 -1
- package/dist/apps/www/settings/profile/index.js +7 -5
- package/dist/apps/www/settings/read-receipts/index.d.ts +1 -1
- package/dist/apps/www/settings/read-receipts/index.js +5 -3
- package/dist/apps/www/settings/sharing/index.d.ts +1 -1
- package/dist/apps/www/settings/sharing/index.js +6 -6
- package/dist/apps/www/settings/signatures/[uid].d.ts +1 -1
- package/dist/apps/www/settings/signatures/[uid].js +5 -5
- package/dist/apps/www/settings/signatures/index.d.ts +1 -1
- package/dist/apps/www/settings/signatures/index.js +4 -4
- package/dist/apps/www/settings/signatures/new/index.d.ts +1 -1
- package/dist/apps/www/settings/signatures/new/index.js +4 -4
- package/dist/apps/www/settings/signatures/signatureDefaults.d.ts +1 -1
- package/dist/apps/www/settings/signatures/signatureDefaults.js +1 -1
- package/dist/apps/www/tasks/index.d.ts +1 -1
- package/dist/apps/www/tasks/index.js +17 -15
- package/dist/lib/admin/auditLogApi.d.ts +32 -0
- package/dist/lib/admin/auditLogApi.js +27 -0
- package/dist/lib/admin/distributionListsApi.d.ts +47 -0
- package/dist/lib/admin/distributionListsApi.js +34 -0
- package/dist/lib/admin/domainsApi.d.ts +75 -0
- package/dist/lib/admin/domainsApi.js +44 -0
- package/dist/lib/admin/escrowAccessRequestsApi.d.ts +79 -0
- package/dist/lib/admin/escrowAccessRequestsApi.js +46 -0
- package/dist/lib/admin/escrowAuditLogApi.d.ts +66 -0
- package/dist/lib/admin/escrowAuditLogApi.js +31 -0
- package/dist/lib/admin/escrowScopesApi.d.ts +78 -0
- package/dist/lib/admin/escrowScopesApi.js +50 -0
- package/dist/lib/admin/leftoverMailboxApi.d.ts +73 -0
- package/dist/lib/admin/leftoverMailboxApi.js +67 -0
- package/dist/lib/admin/mailboxPolicyApi.d.ts +27 -0
- package/dist/lib/admin/mailboxPolicyApi.js +21 -0
- package/dist/lib/admin/matterExportApi.d.ts +40 -0
- package/dist/lib/admin/matterExportApi.js +39 -0
- package/dist/lib/admin/matterSearchApi.d.ts +20 -0
- package/dist/lib/admin/matterSearchApi.js +27 -0
- package/dist/lib/admin/mattersApi.d.ts +56 -0
- package/dist/lib/admin/mattersApi.js +40 -0
- package/dist/lib/admin/pluginsApi.d.ts +265 -0
- package/dist/lib/admin/pluginsApi.js +102 -0
- package/dist/lib/admin/retentionPolicyApi.d.ts +32 -0
- package/dist/lib/admin/retentionPolicyApi.js +29 -0
- package/dist/lib/admin/setupApi.d.ts +23 -0
- package/dist/lib/admin/setupApi.js +26 -0
- package/dist/lib/admin/transportRulesApi.d.ts +66 -0
- package/dist/lib/admin/transportRulesApi.js +43 -0
- package/dist/lib/appearance/preferencesApi.d.ts +128 -0
- package/dist/lib/appearance/preferencesApi.js +257 -0
- package/dist/lib/auth/profileApi.d.ts +33 -0
- package/dist/lib/auth/profileApi.js +52 -0
- package/dist/lib/auth/session.d.ts +70 -0
- package/dist/lib/auth/session.js +210 -0
- package/dist/lib/branding/brandingApi.d.ts +47 -0
- package/dist/lib/branding/brandingApi.js +61 -0
- package/dist/lib/branding/useBranding.d.ts +23 -0
- package/dist/lib/branding/useBranding.js +65 -0
- package/dist/lib/calendar/calendarApi.d.ts +230 -0
- package/dist/lib/calendar/calendarApi.js +106 -0
- package/dist/lib/calendar/calendarColors.d.ts +18 -0
- package/dist/lib/calendar/calendarColors.js +39 -0
- package/dist/lib/calendar/calendarDragIds.d.ts +42 -0
- package/dist/lib/calendar/calendarDragIds.js +92 -0
- package/dist/lib/calendar/calendarMutations.d.ts +68 -0
- package/dist/lib/calendar/calendarMutations.js +190 -0
- package/dist/lib/calendar/eventDescription.d.ts +43 -0
- package/dist/lib/calendar/eventDescription.js +195 -0
- package/dist/lib/calendar/freeBusyApi.d.ts +100 -0
- package/dist/lib/calendar/freeBusyApi.js +119 -0
- package/dist/lib/calendar/inviteApi.d.ts +121 -0
- package/dist/lib/calendar/inviteApi.js +54 -0
- package/dist/lib/calendar/recurrence.d.ts +60 -0
- package/dist/lib/calendar/recurrence.js +225 -0
- package/dist/lib/components/avatar/ContactAvatar.d.ts +8 -0
- package/dist/lib/components/avatar/ContactAvatar.js +26 -0
- package/dist/lib/components/buttons/Button.d.ts +9 -0
- package/dist/lib/components/buttons/Button.js +14 -0
- package/dist/lib/components/buttons/CopyButton.d.ts +18 -0
- package/dist/lib/components/buttons/CopyButton.js +14 -0
- package/dist/lib/components/feedback/Alert.d.ts +4 -0
- package/dist/lib/components/feedback/Alert.js +4 -0
- package/dist/lib/components/feedback/Skeleton.d.ts +21 -0
- package/dist/lib/components/feedback/Skeleton.js +14 -0
- package/dist/lib/components/forms/FormField.d.ts +8 -0
- package/dist/lib/components/forms/FormField.js +5 -0
- package/dist/lib/components/navigation/BottomTabBar.d.ts +27 -0
- package/dist/lib/components/navigation/BottomTabBar.js +32 -0
- package/dist/lib/components/overlays/Drawer.d.ts +20 -0
- package/dist/lib/components/overlays/Drawer.js +27 -0
- package/dist/lib/components/overlays/Modal.d.ts +17 -0
- package/dist/lib/components/overlays/Modal.js +25 -0
- package/dist/lib/components/overlays/PopoverPortal.d.ts +23 -0
- package/dist/lib/components/overlays/PopoverPortal.js +53 -0
- package/dist/lib/components/overlays/overlayStack.d.ts +31 -0
- package/dist/lib/components/overlays/overlayStack.js +143 -0
- package/dist/lib/components/pickers/MiniDatePicker.d.ts +13 -0
- package/dist/lib/components/pickers/MiniDatePicker.js +42 -0
- package/dist/lib/contacts/contactsApi.d.ts +174 -0
- package/dist/lib/contacts/contactsApi.js +139 -0
- package/dist/lib/contacts/vcard.d.ts +23 -0
- package/dist/lib/contacts/vcard.js +179 -0
- package/dist/lib/crypto/composeSecurity.d.ts +67 -0
- package/dist/lib/crypto/composeSecurity.js +93 -0
- package/dist/lib/crypto/encoding.d.ts +9 -0
- package/dist/lib/crypto/encoding.js +32 -0
- package/dist/lib/crypto/escrowKeys.d.ts +25 -0
- package/dist/lib/crypto/escrowKeys.js +59 -0
- package/dist/lib/crypto/idleTimeout.d.ts +16 -0
- package/dist/lib/crypto/idleTimeout.js +47 -0
- package/dist/lib/crypto/keySession.d.ts +159 -0
- package/dist/lib/crypto/keySession.js +367 -0
- package/dist/lib/crypto/keys.d.ts +50 -0
- package/dist/lib/crypto/keys.js +89 -0
- package/dist/lib/crypto/keyvaultApi.d.ts +394 -0
- package/dist/lib/crypto/keyvaultApi.js +350 -0
- package/dist/lib/crypto/masterKey.d.ts +59 -0
- package/dist/lib/crypto/masterKey.js +104 -0
- package/dist/lib/crypto/masterKeyWraps.d.ts +108 -0
- package/dist/lib/crypto/masterKeyWraps.js +228 -0
- package/dist/lib/crypto/messageSecurity.d.ts +248 -0
- package/dist/lib/crypto/messageSecurity.js +367 -0
- package/dist/lib/crypto/mime.d.ts +143 -0
- package/dist/lib/crypto/mime.js +504 -0
- package/dist/lib/crypto/passkeyUnlock.d.ts +20 -0
- package/dist/lib/crypto/passkeyUnlock.js +79 -0
- package/dist/lib/crypto/passwordUnlock.d.ts +39 -0
- package/dist/lib/crypto/passwordUnlock.js +73 -0
- package/dist/lib/crypto/recoveryCode.d.ts +28 -0
- package/dist/lib/crypto/recoveryCode.js +86 -0
- package/dist/lib/crypto/signingProviderApi.d.ts +95 -0
- package/dist/lib/crypto/signingProviderApi.js +60 -0
- package/dist/lib/crypto/smime.d.ts +128 -0
- package/dist/lib/crypto/smime.js +402 -0
- package/dist/lib/crypto/smimeMessage.d.ts +132 -0
- package/dist/lib/crypto/smimeMessage.js +341 -0
- package/dist/lib/crypto/useIdleKeyTimeout.d.ts +10 -0
- package/dist/lib/crypto/useIdleKeyTimeout.js +163 -0
- package/dist/lib/crypto/verificationSeal.d.ts +56 -0
- package/dist/lib/crypto/verificationSeal.js +220 -0
- package/dist/lib/mail/compose/composeQuoting.d.ts +88 -0
- package/dist/lib/mail/compose/composeQuoting.js +204 -0
- package/dist/lib/mail/compose/emojiData.d.ts +9 -0
- package/dist/lib/mail/compose/emojiData.js +18 -0
- package/dist/lib/mail/compose/giphyApi.d.ts +17 -0
- package/dist/lib/mail/compose/giphyApi.js +20 -0
- package/dist/lib/mail/conversationsApi.d.ts +80 -0
- package/dist/lib/mail/conversationsApi.js +44 -0
- package/dist/lib/mail/dataExportApi.d.ts +50 -0
- package/dist/lib/mail/dataExportApi.js +40 -0
- package/dist/lib/mail/directoryApi.d.ts +49 -0
- package/dist/lib/mail/directoryApi.js +101 -0
- package/dist/lib/mail/erasureRequestApi.d.ts +45 -0
- package/dist/lib/mail/erasureRequestApi.js +43 -0
- package/dist/lib/mail/flaggedMessages.d.ts +22 -0
- package/dist/lib/mail/flaggedMessages.js +73 -0
- package/dist/lib/mail/focusedInboxOverridesApi.d.ts +37 -0
- package/dist/lib/mail/focusedInboxOverridesApi.js +34 -0
- package/dist/lib/mail/labelsApi.d.ts +47 -0
- package/dist/lib/mail/labelsApi.js +38 -0
- package/dist/lib/mail/mailAddress.d.ts +27 -0
- package/dist/lib/mail/mailAddress.js +54 -0
- package/dist/lib/mail/mailApi.d.ts +850 -0
- package/dist/lib/mail/mailApi.js +602 -0
- package/dist/lib/mail/mailDetailHooks.d.ts +10 -0
- package/dist/lib/mail/mailDetailHooks.js +53 -0
- package/dist/lib/mail/mailFilterRulesApi.d.ts +76 -0
- package/dist/lib/mail/mailFilterRulesApi.js +45 -0
- package/dist/lib/mail/mailSignaturesApi.d.ts +49 -0
- package/dist/lib/mail/mailSignaturesApi.js +42 -0
- package/dist/lib/mail/mailboxAccessApi.d.ts +74 -0
- package/dist/lib/mail/mailboxAccessApi.js +56 -0
- package/dist/lib/mail/mailboxImportApi.d.ts +53 -0
- package/dist/lib/mail/mailboxImportApi.js +51 -0
- package/dist/lib/mail/messageBodySanitizer.d.ts +16 -0
- package/dist/lib/mail/messageBodySanitizer.js +118 -0
- package/dist/lib/mail/pushClient.d.ts +106 -0
- package/dist/lib/mail/pushClient.js +317 -0
- package/dist/lib/mail/sendEvents.d.ts +33 -0
- package/dist/lib/mail/sendEvents.js +44 -0
- package/dist/lib/mail/sendFailure.d.ts +16 -0
- package/dist/lib/mail/sendFailure.js +86 -0
- package/dist/lib/mail/senderListsApi.d.ts +69 -0
- package/dist/lib/mail/senderListsApi.js +126 -0
- package/dist/lib/search/queryGrammar.d.ts +51 -0
- package/dist/lib/search/queryGrammar.js +111 -0
- package/dist/lib/search/searchApi.d.ts +100 -0
- package/dist/lib/search/searchApi.js +107 -0
- package/dist/lib/search/searchScoring.d.ts +34 -0
- package/dist/lib/search/searchScoring.js +44 -0
- package/dist/lib/search/searchTier3.d.ts +64 -0
- package/dist/lib/search/searchTier3.js +335 -0
- package/dist/lib/tasks/tasksApi.d.ts +85 -0
- package/dist/lib/tasks/tasksApi.js +55 -0
- package/dist/lib/util/api.d.ts +160 -0
- package/dist/lib/util/api.js +251 -0
- package/dist/lib/util/apiClientContext.d.ts +7 -0
- package/dist/lib/util/apiClientContext.js +32 -0
- package/dist/lib/util/apiQuery.d.ts +32 -0
- package/dist/lib/util/apiQuery.js +42 -0
- package/dist/lib/util/clipboard.d.ts +7 -0
- package/dist/lib/util/clipboard.js +56 -0
- package/dist/lib/util/dateInput.d.ts +6 -0
- package/dist/lib/util/dateInput.js +14 -0
- package/dist/lib/util/timeZone.d.ts +12 -0
- package/dist/lib/util/timeZone.js +32 -0
- package/dist/lib/util/useCopyToClipboard.d.ts +12 -0
- package/dist/lib/util/useCopyToClipboard.js +34 -0
- package/dist/lib/util/useIsMobile.d.ts +10 -0
- package/dist/lib/util/useIsMobile.js +29 -0
- package/dist/lib/videoconf/videoMeetingsApi.d.ts +116 -0
- package/dist/lib/videoconf/videoMeetingsApi.js +49 -0
- package/lib/admin/auditLogApi.ts +48 -0
- package/lib/admin/distributionListsApi.ts +77 -0
- package/lib/admin/domainsApi.ts +113 -0
- package/lib/admin/escrowAccessRequestsApi.ts +110 -0
- package/lib/admin/escrowAuditLogApi.ts +101 -0
- package/lib/admin/escrowScopesApi.ts +112 -0
- package/lib/admin/leftoverMailboxApi.ts +120 -0
- package/lib/admin/mailboxPolicyApi.ts +38 -0
- package/lib/admin/matterExportApi.ts +62 -0
- package/lib/admin/matterSearchApi.ts +35 -0
- package/lib/admin/mattersApi.ts +86 -0
- package/lib/admin/pluginsApi.ts +339 -0
- package/lib/admin/retentionPolicyApi.ts +46 -0
- package/lib/admin/setupApi.ts +40 -0
- package/lib/admin/transportRulesApi.ts +106 -0
- package/lib/appearance/preferencesApi.ts +335 -0
- package/lib/auth/profileApi.ts +77 -0
- package/lib/auth/session.ts +238 -0
- package/lib/branding/brandingApi.ts +97 -0
- package/lib/branding/useBranding.ts +81 -0
- package/lib/calendar/calendarApi.ts +309 -0
- package/lib/calendar/calendarColors.ts +45 -0
- package/lib/calendar/calendarDragIds.ts +112 -0
- package/lib/calendar/calendarMutations.ts +236 -0
- package/lib/calendar/eventDescription.ts +211 -0
- package/lib/calendar/freeBusyApi.ts +197 -0
- package/lib/calendar/inviteApi.ts +154 -0
- package/lib/calendar/recurrence.ts +285 -0
- package/lib/components/avatar/ContactAvatar.tsx +47 -0
- package/lib/components/buttons/Button.tsx +40 -0
- package/lib/components/buttons/CopyButton.tsx +45 -0
- package/lib/components/feedback/Alert.tsx +13 -0
- package/lib/components/feedback/Skeleton.tsx +38 -0
- package/lib/components/forms/FormField.tsx +23 -0
- package/lib/components/navigation/BottomTabBar.tsx +66 -0
- package/lib/components/overlays/Drawer.tsx +72 -0
- package/lib/components/overlays/Modal.tsx +64 -0
- package/lib/components/overlays/PopoverPortal.tsx +74 -0
- package/lib/components/overlays/overlayStack.ts +165 -0
- package/lib/components/pickers/MiniDatePicker.tsx +90 -0
- package/lib/contacts/contactsApi.ts +289 -0
- package/lib/contacts/vcard.ts +197 -0
- package/lib/crypto/composeSecurity.ts +140 -0
- package/lib/crypto/encoding.ts +36 -0
- package/lib/crypto/escrowKeys.ts +74 -0
- package/lib/crypto/idleTimeout.ts +49 -0
- package/lib/crypto/keySession.ts +483 -0
- package/lib/crypto/keys.ts +105 -0
- package/lib/crypto/keyvaultApi.ts +674 -0
- package/lib/crypto/masterKey.ts +134 -0
- package/lib/crypto/masterKeyWraps.ts +269 -0
- package/lib/crypto/messageSecurity.ts +600 -0
- package/lib/crypto/mime.ts +568 -0
- package/lib/crypto/passkeyUnlock.ts +103 -0
- package/lib/crypto/passwordUnlock.ts +98 -0
- package/lib/crypto/recoveryCode.ts +93 -0
- package/lib/crypto/signingProviderApi.ts +135 -0
- package/lib/crypto/smime.ts +459 -0
- package/lib/crypto/smimeMessage.ts +491 -0
- package/lib/crypto/useIdleKeyTimeout.ts +176 -0
- package/lib/crypto/verificationSeal.ts +288 -0
- package/lib/mail/compose/composeQuoting.ts +243 -0
- package/lib/mail/compose/emojiData.ts +34 -0
- package/lib/mail/compose/giphyApi.ts +31 -0
- package/lib/mail/conversationsApi.ts +123 -0
- package/lib/mail/dataExportApi.ts +73 -0
- package/lib/mail/directoryApi.ts +161 -0
- package/lib/mail/erasureRequestApi.ts +71 -0
- package/lib/mail/flaggedMessages.ts +80 -0
- package/lib/mail/focusedInboxOverridesApi.ts +64 -0
- package/lib/mail/labelsApi.ts +71 -0
- package/lib/mail/mailAddress.ts +76 -0
- package/lib/mail/mailApi.ts +1286 -0
- package/lib/mail/mailDetailHooks.ts +57 -0
- package/lib/mail/mailFilterRulesApi.ts +116 -0
- package/lib/mail/mailSignaturesApi.ts +84 -0
- package/lib/mail/mailboxAccessApi.ts +106 -0
- package/lib/mail/mailboxImportApi.ts +87 -0
- package/lib/mail/messageBodySanitizer.ts +129 -0
- package/lib/mail/pushClient.ts +375 -0
- package/lib/mail/sendEvents.ts +72 -0
- package/lib/mail/sendFailure.ts +98 -0
- package/lib/mail/senderListsApi.ts +161 -0
- package/lib/search/queryGrammar.ts +179 -0
- package/lib/search/searchApi.ts +199 -0
- package/lib/search/searchScoring.ts +46 -0
- package/lib/search/searchTier3.ts +406 -0
- package/lib/tasks/tasksApi.ts +128 -0
- package/lib/util/api.ts +318 -0
- package/lib/util/apiClientContext.ts +35 -0
- package/lib/util/apiQuery.ts +61 -0
- package/lib/util/clipboard.ts +55 -0
- package/lib/util/dateInput.ts +15 -0
- package/lib/util/timeZone.ts +33 -0
- package/lib/util/useCopyToClipboard.ts +48 -0
- package/lib/util/useIsMobile.ts +34 -0
- package/lib/videoconf/videoMeetingsApi.ts +144 -0
- package/package.json +10 -4
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
/**
|
|
6
|
+
* A mailbox's Blocked Senders and Safe Senders lists (`Mailbox.blockedSenders`, `Mailbox.safeSenders`) - typed wrappers over
|
|
7
|
+
* `@rapidmx/restapi`'s `POST/DELETE /mail/mailboxes/:id/blocked-senders[/:entry]` and `.../safe-senders[/:entry]`, and the entry
|
|
8
|
+
* normalizer that mirrors the server's, so a form can say what is wrong with what was typed before sending it.
|
|
9
|
+
*
|
|
10
|
+
* An entry is a plain lowercase address (`user@example.com`) or a domain (`@example.com` - that exact domain, not its subdomains). Adding
|
|
11
|
+
* an entry to one list takes it off the other. Both lists are owner-level settings: every call needs FULL access to the mailbox (a 403
|
|
12
|
+
* otherwise), which the mailbox's owner and a "manager" delegate have.
|
|
13
|
+
*/
|
|
14
|
+
import { ApiClient, withClient } from "../util/api.js";
|
|
15
|
+
|
|
16
|
+
/** The most entries one list may hold (a 400 past it). */
|
|
17
|
+
export const MAX_SENDER_LIST_ENTRIES = 1000;
|
|
18
|
+
|
|
19
|
+
/** The longest an entry may be, in characters (RFC 5321's forward-path limit). */
|
|
20
|
+
export const MAX_SENDER_ENTRY_LENGTH = 254;
|
|
21
|
+
|
|
22
|
+
/** Which list. */
|
|
23
|
+
export type SenderListKind = "blocked" | "safe";
|
|
24
|
+
|
|
25
|
+
/** What a change to a list answers: the entry as the server stored it, whether anything changed (`false` for an entry already there, or an absent one
|
|
26
|
+
* removed), and both lists as they now are. */
|
|
27
|
+
export interface SenderListsChange {
|
|
28
|
+
entry: string;
|
|
29
|
+
changed: boolean;
|
|
30
|
+
blockedSenders: string[];
|
|
31
|
+
safeSenders: string[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** A DNS host name of at least two labels: letters, digits and inner hyphens, each label at most 63 characters, the whole at most 253. Lowercase input. */
|
|
35
|
+
const DOMAIN_PATTERN = /^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$/;
|
|
36
|
+
|
|
37
|
+
/** One plain address: no display name, angle brackets, group, comment, list, quoting or whitespace. */
|
|
38
|
+
const PLAIN_ADDRESS_PATTERN = /^[^\s()<>@,;:\\"[\]]+@[^\s()<>@,;:\\"[\]]+$/;
|
|
39
|
+
|
|
40
|
+
// eslint-disable-next-line no-control-regex
|
|
41
|
+
const CONTROL_CHARACTER = /[\u0000-\u001F\u007F]/;
|
|
42
|
+
|
|
43
|
+
function parseDomain(value: string): string | undefined {
|
|
44
|
+
const trimmed = value.trim().toLowerCase();
|
|
45
|
+
const domain = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
|
|
46
|
+
return domain.length <= MAX_SENDER_ENTRY_LENGTH && DOMAIN_PATTERN.test(domain) ? domain : undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function parseAddress(value: string): string | undefined {
|
|
50
|
+
const address = value.trim().toLowerCase();
|
|
51
|
+
return address.length <= MAX_SENDER_ENTRY_LENGTH && !CONTROL_CHARACTER.test(address) && PLAIN_ADDRESS_PATTERN.test(address) ? address : undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* `value` as the canonical entry the server stores, or `undefined` when the server would refuse it (a 400): trimmed and lowercased, a plain address
|
|
56
|
+
* stays `user@example.com`, and a domain - typed `@example.com` or `example.com` - becomes `@example.com`, so the two spellings are one entry.
|
|
57
|
+
*/
|
|
58
|
+
export function normalizeSenderEntry(value: string): string | undefined {
|
|
59
|
+
const trimmed = value.trim();
|
|
60
|
+
if (trimmed.startsWith("@") || !trimmed.includes("@")) {
|
|
61
|
+
const domain = parseDomain(trimmed);
|
|
62
|
+
return domain === undefined ? undefined : `@${domain}`;
|
|
63
|
+
}
|
|
64
|
+
return parseAddress(trimmed);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** What `checkSenderEntry()` decided about what was typed. */
|
|
68
|
+
export type SenderEntryCheck = { ok: true; entry: string; kind: "address" | "domain" } | { ok: false; message: string };
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Checks what a person typed into an "add a sender" field: `{ ok: true, entry, kind }` with the canonical entry (`normalizeSenderEntry()`), or
|
|
72
|
+
* `{ ok: false, message }` with a sentence that says what is wrong - nothing typed, too long, a name with the address in angle brackets, more than one address, a
|
|
73
|
+
* domain with a single label, a non-ASCII domain - fit to show under the field.
|
|
74
|
+
*/
|
|
75
|
+
export function checkSenderEntry(value: string): SenderEntryCheck {
|
|
76
|
+
const trimmed = value.trim();
|
|
77
|
+
if (trimmed.length === 0) {
|
|
78
|
+
return { ok: false, message: "Type an email address (name@example.com) or a domain (example.com)." };
|
|
79
|
+
}
|
|
80
|
+
if (trimmed.length > MAX_SENDER_ENTRY_LENGTH) {
|
|
81
|
+
return { ok: false, message: `That is longer than ${MAX_SENDER_ENTRY_LENGTH} characters.` };
|
|
82
|
+
}
|
|
83
|
+
const entry = normalizeSenderEntry(trimmed);
|
|
84
|
+
if (entry !== undefined) {
|
|
85
|
+
return { ok: true, entry, kind: entry.startsWith("@") ? "domain" : "address" };
|
|
86
|
+
}
|
|
87
|
+
if (/[<>]/.test(trimmed)) {
|
|
88
|
+
return { ok: false, message: "Type only the address, without a name or angle brackets: name@example.com." };
|
|
89
|
+
}
|
|
90
|
+
if (/[,;\s]/.test(trimmed)) {
|
|
91
|
+
return { ok: false, message: "Add one address or domain at a time, with no spaces or commas." };
|
|
92
|
+
}
|
|
93
|
+
if (trimmed.startsWith("@") || !trimmed.includes("@")) {
|
|
94
|
+
if (/[\u0080-]/.test(trimmed)) {
|
|
95
|
+
return { ok: false, message: "Use the ASCII (punycode) form of an international domain name, such as xn--bcher-kva.example." };
|
|
96
|
+
}
|
|
97
|
+
return { ok: false, message: "That is not a domain. Type one such as example.com, with at least two parts and only letters, digits and hyphens." };
|
|
98
|
+
}
|
|
99
|
+
return { ok: false, message: "That is not an email address. Type one such as name@example.com, or a domain such as example.com." };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** The domain of `address` (after its last `@`), lowercased; `undefined` when it has none. */
|
|
103
|
+
export function senderDomainOf(address: string): string | undefined {
|
|
104
|
+
const at = address.lastIndexOf("@");
|
|
105
|
+
return at >= 0 && at < address.length - 1 ? address.slice(at + 1).trim().toLowerCase() : undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Whether `entry` (`user@example.com` or `@example.com`) names `address` - compared case-insensitively; a domain entry names that exact domain, not its subdomains. */
|
|
109
|
+
export function senderEntryMatches(entry: string, address: string): boolean {
|
|
110
|
+
const lower = address.trim().toLowerCase();
|
|
111
|
+
return entry.startsWith("@") ? senderDomainOf(lower) === entry.slice(1).toLowerCase() : lower === entry.toLowerCase();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** The entry of `list` that names `address` (the address itself, or its domain), if any - the one a "blocked" or "safe" badge would come from. */
|
|
115
|
+
export function senderListEntryFor(list: readonly string[] | null | undefined, address: string): string | undefined {
|
|
116
|
+
return (list ?? []).find((entry) => senderEntryMatches(entry, address));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function listPath(mailboxUid: string, list: SenderListKind): string {
|
|
120
|
+
return `/mail/mailboxes/${encodeURIComponent(mailboxUid)}/${list === "blocked" ? "blocked-senders" : "safe-senders"}`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function add(mailboxUid: string, list: SenderListKind, entry: string, client?: ApiClient): Promise<SenderListsChange> {
|
|
124
|
+
return withClient(client, listPath(mailboxUid, list), { method: "POST", body: JSON.stringify({ entry }) });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function remove(mailboxUid: string, list: SenderListKind, entry: string, client?: ApiClient): Promise<SenderListsChange> {
|
|
128
|
+
return withClient(client, `${listPath(mailboxUid, list)}/${encodeURIComponent(entry)}`, { method: "DELETE" });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** `client`, given by every function below, is an explicit `ApiClient` from `createApiClient()` (e.g. one
|
|
132
|
+
* account of a multi-account app) to call instead of the default global `apiFetch()` - see `withClient()`'s
|
|
133
|
+
* own doc comment in `util/api.ts`. Omitted (the default), every function here behaves exactly as before. */
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Adds an address or domain to the mailbox's Blocked Senders (`POST .../blocked-senders`) and takes it off its Safe Senders. Mail from it goes to Junk Email
|
|
137
|
+
* from then on. `entry` is normalized by the server, so `Example.com` is `@example.com`; use `checkSenderEntry()` first to tell the person what is wrong.
|
|
138
|
+
* Adding an entry already there changes nothing (`changed: false`). Rejects with a 400 for an invalid entry or a full list, a 403 without full access to the
|
|
139
|
+
* mailbox, and a 404 for a mailbox the caller cannot read - or a server without the lists.
|
|
140
|
+
*/
|
|
141
|
+
export function addBlockedSender(mailboxUid: string, entry: string, client?: ApiClient): Promise<SenderListsChange> {
|
|
142
|
+
return add(mailboxUid, "blocked", entry, client);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Takes an address or domain off the mailbox's Blocked Senders (`DELETE .../blocked-senders/:entry`, the entry URL-encoded, `@` included). Removing an absent entry
|
|
146
|
+
* succeeds with `changed: false`. */
|
|
147
|
+
export function removeBlockedSender(mailboxUid: string, entry: string, client?: ApiClient): Promise<SenderListsChange> {
|
|
148
|
+
return remove(mailboxUid, "blocked", entry, client);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Adds an address or domain to the mailbox's Safe Senders (`POST .../safe-senders`) and takes it off its Blocked Senders. Authenticated mail from it (a passing DKIM signature
|
|
152
|
+
* aligned with its From domain) is then not sent to Junk Email for the spam filter's verdict; mail that fails authentication, carries a virus or is quarantined
|
|
153
|
+
* by policy still is. Errors as `addBlockedSender()`. */
|
|
154
|
+
export function addSafeSender(mailboxUid: string, entry: string, client?: ApiClient): Promise<SenderListsChange> {
|
|
155
|
+
return add(mailboxUid, "safe", entry, client);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Takes an address or domain off the mailbox's Safe Senders (`DELETE .../safe-senders/:entry`). Removing an absent entry succeeds with `changed: false`. */
|
|
159
|
+
export function removeSafeSender(mailboxUid: string, entry: string, client?: ApiClient): Promise<SenderListsChange> {
|
|
160
|
+
return remove(mailboxUid, "safe", entry, client);
|
|
161
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
/**
|
|
6
|
+
* Parses `specs/search.md` §14's light operator syntax (`from:`, `to:`, `cc:`, `subject:`,
|
|
7
|
+
* `has:attachment`, `before:`, `after:`, `in:`, `is:`, `label:`, `type:`) out of a raw search box
|
|
8
|
+
* string, once, client-side — per the spec's own requirement that parsing happen in exactly one place
|
|
9
|
+
* so every tier (server Tier 1 today; a future local Tier 2/3) interprets the grammar identically.
|
|
10
|
+
*
|
|
11
|
+
* Only the *operator* tokens are extracted. Everything else — plain words, quoted phrases, a leading
|
|
12
|
+
* `-` negating a term — is left untouched in the returned `text` remainder, because each provider's own
|
|
13
|
+
* free-text engine already understands that syntax natively (`specs/search.md` §14's own "Provider
|
|
14
|
+
* Implementation": Postgres's `websearch_to_tsquery` handles quoted phrases, `OR`, and `-` negation
|
|
15
|
+
* safely on untrusted input). Rewriting that ourselves would just be a worse reimplementation of what
|
|
16
|
+
* the provider already does correctly.
|
|
17
|
+
*
|
|
18
|
+
* An operator token is only recognized when it starts at a word boundary (start of string, or after
|
|
19
|
+
* whitespace) — `-from:bob` therefore is NOT parsed as a negated operator (the operator fields
|
|
20
|
+
* `BaseSearchRoute` accepts are single-value/AND-only with no negated form) and is left in `text`
|
|
21
|
+
* verbatim, and a deliberately-quoted phrase like `"from:bob"` is never mistaken for the operator
|
|
22
|
+
* either, since the match requires an *unquoted* key immediately followed by `:`.
|
|
23
|
+
*/
|
|
24
|
+
import { SearchEntityType } from "./searchApi.js";
|
|
25
|
+
|
|
26
|
+
export interface ParsedSearchQuery {
|
|
27
|
+
/** The remaining free-text portion — quotes, `-` negation, and `OR` preserved verbatim for each
|
|
28
|
+
* provider's own free-text engine to interpret. Never rewritten by this parser beyond removing the
|
|
29
|
+
* operator tokens themselves and collapsing the whitespace that leaves behind. */
|
|
30
|
+
text: string;
|
|
31
|
+
/** `from:` — sender address or display name. */
|
|
32
|
+
from?: string;
|
|
33
|
+
/** `to:` — a recipient address. */
|
|
34
|
+
to?: string;
|
|
35
|
+
/** `cc:` — a recipient address. */
|
|
36
|
+
cc?: string;
|
|
37
|
+
/** `subject:` — restricts matching to the subject/title field. */
|
|
38
|
+
subject?: string;
|
|
39
|
+
/** `has:attachment` */
|
|
40
|
+
hasAttachment?: boolean;
|
|
41
|
+
/** `before:` — parsed via `new Date()`; an unparseable value is left in `text` rather than dropped. */
|
|
42
|
+
before?: Date;
|
|
43
|
+
/** `after:` — see `before`. */
|
|
44
|
+
after?: Date;
|
|
45
|
+
/** `in:` — folder or calendar uid. */
|
|
46
|
+
folderUid?: string;
|
|
47
|
+
/** `is:` — one or more flag/state strings (`is:read`, repeated `is:` tokens, or a single
|
|
48
|
+
* comma-separated `is:read,flagged` token all accumulate into this array). */
|
|
49
|
+
flags?: string[];
|
|
50
|
+
/** `label:` — one or more `Label.uid`s. Same repeat/comma-separation rules as `flags`. */
|
|
51
|
+
labels?: string[];
|
|
52
|
+
/** `type:` — maps to `SearchQuery.entityTypes`. An unrecognized type token is dropped rather than
|
|
53
|
+
* forwarded, since the server has no representation for anything outside `SearchEntityType`. */
|
|
54
|
+
entityTypes?: SearchEntityType[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const VALID_ENTITY_TYPES: ReadonlySet<string> = new Set<SearchEntityType>(["message", "contact", "calendarEvent", "note", "task"]);
|
|
58
|
+
|
|
59
|
+
/** Finds and removes the first `key:value`/`key:"quoted value"` occurrence of `key` in `input`, where
|
|
60
|
+
* `value` is either a quoted phrase or a run of non-whitespace characters. Returns `undefined` for
|
|
61
|
+
* `value` (and `input` unchanged as `rest`) when no such token exists. The matched span is replaced by
|
|
62
|
+
* the single whitespace character that preceded it (or removed entirely at start-of-string), so
|
|
63
|
+
* `removeRange` never joins two words together — final whitespace collapsing happens once, in
|
|
64
|
+
* `parseSearchQuery()` itself, after every extraction has run. */
|
|
65
|
+
function extractFirst(input: string, key: string): { value?: string; rest: string } {
|
|
66
|
+
const pattern = new RegExp(`(^|\\s)${key}:(?:"([^"]*)"|(\\S+))`, "i");
|
|
67
|
+
const match = pattern.exec(input);
|
|
68
|
+
if (!match) {
|
|
69
|
+
return { rest: input };
|
|
70
|
+
}
|
|
71
|
+
const value = match[2] ?? match[3] ?? "";
|
|
72
|
+
const rest = input.slice(0, match.index) + match[1] + input.slice(match.index + match[0].length);
|
|
73
|
+
return { value, rest };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Repeatedly applies `extractFirst()` for `key` until no more occurrences remain, splitting any
|
|
77
|
+
* comma-separated value into individual entries — so `is:read is:flagged` and `is:read,flagged` both
|
|
78
|
+
* produce `["read", "flagged"]`. */
|
|
79
|
+
function extractAll(input: string, key: string): { values: string[]; rest: string } {
|
|
80
|
+
const values: string[] = [];
|
|
81
|
+
let rest = input;
|
|
82
|
+
for (;;) {
|
|
83
|
+
const result = extractFirst(rest, key);
|
|
84
|
+
if (result.value === undefined) {
|
|
85
|
+
return { values, rest };
|
|
86
|
+
}
|
|
87
|
+
rest = result.rest;
|
|
88
|
+
for (const part of result.value.split(",")) {
|
|
89
|
+
const trimmed = part.trim();
|
|
90
|
+
if (trimmed) {
|
|
91
|
+
values.push(trimmed);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Removes the exact literal token `has:attachment` (case-insensitively), the one compound keyword the
|
|
98
|
+
* spec defines for this operator — there is no `has:<other value>` form. */
|
|
99
|
+
function extractHasAttachment(input: string): { found: boolean; rest: string } {
|
|
100
|
+
const pattern = /(^|\s)has:attachment\b/i;
|
|
101
|
+
const match = pattern.exec(input);
|
|
102
|
+
if (!match) {
|
|
103
|
+
return { found: false, rest: input };
|
|
104
|
+
}
|
|
105
|
+
return { found: true, rest: input.slice(0, match.index) + match[1] + input.slice(match.index + match[0].length) };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Local midnight on `year`-`month`-`day`, or an Invalid Date when that calendar date doesn't exist
|
|
109
|
+
* (e.g. `2026-02-30`, which the `Date` constructor would otherwise silently roll over into March). */
|
|
110
|
+
function localDate(year: number, month: number, day: number): Date {
|
|
111
|
+
const date = new Date(year, month - 1, day);
|
|
112
|
+
date.setFullYear(year);
|
|
113
|
+
return date.getMonth() === month - 1 && date.getDate() === day ? date : new Date(Number.NaN);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function extractDate(input: string, key: string): { date?: Date; rest: string } {
|
|
117
|
+
const { value, rest } = extractFirst(input, key);
|
|
118
|
+
if (value === undefined) {
|
|
119
|
+
return { rest: input };
|
|
120
|
+
}
|
|
121
|
+
// A date-only `yyyy-MM-dd` value means local midnight on that day (what a user typing `before:2026-01-02`
|
|
122
|
+
// means) — `new Date("2026-01-02")` alone would parse it as UTC midnight per the ECMAScript spec.
|
|
123
|
+
// Anything else (a full ISO date-time, with or without an offset) is left to `new Date()` as-is.
|
|
124
|
+
const dateOnly = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
125
|
+
const date = dateOnly ? localDate(Number(dateOnly[1]), Number(dateOnly[2]), Number(dateOnly[3])) : new Date(value);
|
|
126
|
+
if (Number.isNaN(date.getTime())) {
|
|
127
|
+
// Unparseable — leave the whole token in the free-text remainder rather than silently dropping
|
|
128
|
+
// it, mirroring BaseSearchRoute's own parseDateParam() leniency (invalid date -> undefined).
|
|
129
|
+
return { rest: input };
|
|
130
|
+
}
|
|
131
|
+
return { date, rest };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function parseSearchQuery(raw: string): ParsedSearchQuery {
|
|
135
|
+
let rest = raw;
|
|
136
|
+
|
|
137
|
+
const from = extractFirst(rest, "from");
|
|
138
|
+
rest = from.rest;
|
|
139
|
+
const to = extractFirst(rest, "to");
|
|
140
|
+
rest = to.rest;
|
|
141
|
+
const cc = extractFirst(rest, "cc");
|
|
142
|
+
rest = cc.rest;
|
|
143
|
+
const subject = extractFirst(rest, "subject");
|
|
144
|
+
rest = subject.rest;
|
|
145
|
+
const folder = extractFirst(rest, "in");
|
|
146
|
+
rest = folder.rest;
|
|
147
|
+
|
|
148
|
+
const hasAttachment = extractHasAttachment(rest);
|
|
149
|
+
rest = hasAttachment.rest;
|
|
150
|
+
|
|
151
|
+
const before = extractDate(rest, "before");
|
|
152
|
+
rest = before.rest;
|
|
153
|
+
const after = extractDate(rest, "after");
|
|
154
|
+
rest = after.rest;
|
|
155
|
+
|
|
156
|
+
const flags = extractAll(rest, "is");
|
|
157
|
+
rest = flags.rest;
|
|
158
|
+
const labels = extractAll(rest, "label");
|
|
159
|
+
rest = labels.rest;
|
|
160
|
+
const types = extractAll(rest, "type");
|
|
161
|
+
rest = types.rest;
|
|
162
|
+
|
|
163
|
+
const entityTypes = types.values.filter((t): t is SearchEntityType => VALID_ENTITY_TYPES.has(t));
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
text: rest.replace(/\s+/g, " ").trim(),
|
|
167
|
+
from: from.value,
|
|
168
|
+
to: to.value,
|
|
169
|
+
cc: cc.value,
|
|
170
|
+
subject: subject.value,
|
|
171
|
+
hasAttachment: hasAttachment.found ? true : undefined,
|
|
172
|
+
before: before.date,
|
|
173
|
+
after: after.date,
|
|
174
|
+
folderUid: folder.value,
|
|
175
|
+
flags: flags.values.length > 0 ? flags.values : undefined,
|
|
176
|
+
labels: labels.values.length > 0 ? labels.values : undefined,
|
|
177
|
+
entityTypes: entityTypes.length > 0 ? entityTypes : undefined,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
/**
|
|
6
|
+
* Client wrapper for `@rapidmx/restapi`'s `BaseSearchRoute` (mounted at `/mail/search` — see
|
|
7
|
+
* `src/mongo/routes/SearchRoute.ts`/`src/sql/routes/SearchRoute.ts`), the full-text search endpoint across
|
|
8
|
+
* a mailbox's messages/contacts/calendar events/notes/tasks. Scoped server-side to the caller's own mailbox
|
|
9
|
+
* unless an optional `mailboxUid` (one the caller can access, e.g. the currently open shared mailbox) is
|
|
10
|
+
* passed.
|
|
11
|
+
*
|
|
12
|
+
* The structured filter params below mirror `specs/search.md` §14's operator grammar
|
|
13
|
+
* (`from:`/`to:`/`cc:`/`subject:`/`has:attachment`/`before:`/`after:`/`in:`/`is:`/`label:`), already parsed
|
|
14
|
+
* out of raw query text by `queryGrammar.ts`'s `parseSearchQuery()` — this module only ever sends the
|
|
15
|
+
* already-structured result, matching `BaseSearchRoute`'s own query-param names exactly
|
|
16
|
+
* (`from`/`to`/`cc`/`subject`/`hasAttachment`/`before`/`after`/`in`/`is`/`label`).
|
|
17
|
+
*/
|
|
18
|
+
import { ApiClient, withClient } from "../util/api.js";
|
|
19
|
+
|
|
20
|
+
export type SearchEntityType = "message" | "contact" | "calendarEvent" | "note" | "task";
|
|
21
|
+
|
|
22
|
+
/** Which tier produced a result. Only `"server"` is possible until Tier 2 (local index) and Tier 3
|
|
23
|
+
* (server-assisted narrowing) exist — kept as its own type now so a future client-side tier doesn't need
|
|
24
|
+
* a breaking change to `SearchResult`. */
|
|
25
|
+
export type SearchResultSource = "server" | "local" | "candidate";
|
|
26
|
+
|
|
27
|
+
export interface SearchResult {
|
|
28
|
+
entityType: SearchEntityType;
|
|
29
|
+
entityUid: string;
|
|
30
|
+
score: number;
|
|
31
|
+
/** A short, provider-generated snippet highlighting the matched text, if supported. */
|
|
32
|
+
snippet?: string;
|
|
33
|
+
/** True when `score` is derived from server-visible metadata only (participants/date, not content —
|
|
34
|
+
* always the case for an encrypted message) and is therefore not comparable to a result scored from
|
|
35
|
+
* full content. See `searchScoring.ts` for how this is handled once mixed-source merging exists. */
|
|
36
|
+
metadataOnly?: boolean;
|
|
37
|
+
/** Which tier produced this result. Always `"server"` from this function today. */
|
|
38
|
+
source?: SearchResultSource;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface SearchResultPage {
|
|
42
|
+
results: SearchResult[];
|
|
43
|
+
/** Opaque cursor to pass back as `cursor` to retrieve the next page, if more results exist. */
|
|
44
|
+
nextCursor?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface SearchParams {
|
|
48
|
+
types?: SearchEntityType[];
|
|
49
|
+
cursor?: string;
|
|
50
|
+
limit?: number;
|
|
51
|
+
/** `from:` — sender address. */
|
|
52
|
+
from?: string;
|
|
53
|
+
/** `to:` — a recipient address in the `To` line. */
|
|
54
|
+
to?: string;
|
|
55
|
+
/** `cc:` — a recipient address in the `Cc` line. */
|
|
56
|
+
cc?: string;
|
|
57
|
+
/** `subject:` — restricts matching to the subject/title field only. May be combined with free text. */
|
|
58
|
+
subject?: string;
|
|
59
|
+
/** `has:attachment` */
|
|
60
|
+
hasAttachment?: boolean;
|
|
61
|
+
/** `before:` */
|
|
62
|
+
before?: Date;
|
|
63
|
+
/** `after:` */
|
|
64
|
+
after?: Date;
|
|
65
|
+
/** `in:` — folder or calendar uid. */
|
|
66
|
+
folderUid?: string;
|
|
67
|
+
/** `is:` — one or more flag/state strings, matched as an AND (all must be present). */
|
|
68
|
+
flags?: string[];
|
|
69
|
+
/** `label:` — one or more `Label.uid`s, matched as an AND (all must be present). */
|
|
70
|
+
labels?: string[];
|
|
71
|
+
/** Which of the caller's accessible mailboxes to search (e.g. the one currently open). Omitted, the
|
|
72
|
+
* server falls back to the caller's own mailbox; access to a supplied one is checked server-side. */
|
|
73
|
+
mailboxUid?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Exported so `admin/matterSearchApi.ts` can build the identical query-param set against a different
|
|
77
|
+
* base path (`escrow/matter-search`, plus its own required `matterId`) — `BaseMatterSearchRoute` reuses
|
|
78
|
+
* this exact same query-param grammar verbatim, per its own doc comment. */
|
|
79
|
+
export function buildSearchParams(text: string, params: SearchParams): URLSearchParams {
|
|
80
|
+
const query = new URLSearchParams({ q: text });
|
|
81
|
+
if (params.types?.length) {
|
|
82
|
+
query.set("types", params.types.join(","));
|
|
83
|
+
}
|
|
84
|
+
if (params.cursor) {
|
|
85
|
+
query.set("cursor", params.cursor);
|
|
86
|
+
}
|
|
87
|
+
if (params.limit) {
|
|
88
|
+
query.set("limit", String(params.limit));
|
|
89
|
+
}
|
|
90
|
+
if (params.from) {
|
|
91
|
+
query.set("from", params.from);
|
|
92
|
+
}
|
|
93
|
+
if (params.to) {
|
|
94
|
+
query.set("to", params.to);
|
|
95
|
+
}
|
|
96
|
+
if (params.cc) {
|
|
97
|
+
query.set("cc", params.cc);
|
|
98
|
+
}
|
|
99
|
+
if (params.subject) {
|
|
100
|
+
query.set("subject", params.subject);
|
|
101
|
+
}
|
|
102
|
+
if (params.hasAttachment !== undefined) {
|
|
103
|
+
query.set("hasAttachment", String(params.hasAttachment));
|
|
104
|
+
}
|
|
105
|
+
if (params.before) {
|
|
106
|
+
query.set("before", params.before.toISOString());
|
|
107
|
+
}
|
|
108
|
+
if (params.after) {
|
|
109
|
+
query.set("after", params.after.toISOString());
|
|
110
|
+
}
|
|
111
|
+
if (params.folderUid) {
|
|
112
|
+
query.set("in", params.folderUid);
|
|
113
|
+
}
|
|
114
|
+
if (params.flags?.length) {
|
|
115
|
+
query.set("is", params.flags.join(","));
|
|
116
|
+
}
|
|
117
|
+
if (params.labels?.length) {
|
|
118
|
+
query.set("label", params.labels.join(","));
|
|
119
|
+
}
|
|
120
|
+
if (params.mailboxUid) {
|
|
121
|
+
query.set("mailboxUid", params.mailboxUid);
|
|
122
|
+
}
|
|
123
|
+
return query;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function search(text: string, params: SearchParams = {}, client?: ApiClient): Promise<SearchResultPage> {
|
|
127
|
+
return withClient(client, `/mail/search?${buildSearchParams(text, params).toString()}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Requests a Tier 3 candidate set (`specs/search.md` §6/§12) — identifiers only, ranked purely on
|
|
132
|
+
* server-visible metadata, never on `subject`/`body`/`attachmentText`. Not called anywhere yet (Tier 3 is
|
|
133
|
+
* a separate, not-yet-built follow-on to this pass) — added now so that work doesn't need to revisit this
|
|
134
|
+
* file's shape, since the underlying route (`BaseSearchRoute.candidates()`) is already shipped.
|
|
135
|
+
*/
|
|
136
|
+
export interface CandidateParams {
|
|
137
|
+
types?: SearchEntityType[];
|
|
138
|
+
/** Participant terms extracted from the query text, matched against server-visible envelope data
|
|
139
|
+
* (`from`/`to`/`cc`/`participants`). */
|
|
140
|
+
participants?: string[];
|
|
141
|
+
before?: Date;
|
|
142
|
+
after?: Date;
|
|
143
|
+
folderUid?: string;
|
|
144
|
+
flags?: string[];
|
|
145
|
+
labels?: string[];
|
|
146
|
+
limit?: number;
|
|
147
|
+
cursor?: string;
|
|
148
|
+
/** Same as `SearchParams.mailboxUid`. */
|
|
149
|
+
mailboxUid?: string;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface CandidateResult {
|
|
153
|
+
entityType: SearchEntityType;
|
|
154
|
+
entityUid: string;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface CandidateResultPage {
|
|
158
|
+
candidates: CandidateResult[];
|
|
159
|
+
nextCursor?: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function buildCandidateParams(params: CandidateParams): URLSearchParams {
|
|
163
|
+
const query = new URLSearchParams();
|
|
164
|
+
if (params.types?.length) {
|
|
165
|
+
query.set("types", params.types.join(","));
|
|
166
|
+
}
|
|
167
|
+
if (params.participants?.length) {
|
|
168
|
+
query.set("participants", params.participants.join(","));
|
|
169
|
+
}
|
|
170
|
+
if (params.before) {
|
|
171
|
+
query.set("before", params.before.toISOString());
|
|
172
|
+
}
|
|
173
|
+
if (params.after) {
|
|
174
|
+
query.set("after", params.after.toISOString());
|
|
175
|
+
}
|
|
176
|
+
if (params.folderUid) {
|
|
177
|
+
query.set("in", params.folderUid);
|
|
178
|
+
}
|
|
179
|
+
if (params.flags?.length) {
|
|
180
|
+
query.set("is", params.flags.join(","));
|
|
181
|
+
}
|
|
182
|
+
if (params.labels?.length) {
|
|
183
|
+
query.set("label", params.labels.join(","));
|
|
184
|
+
}
|
|
185
|
+
if (params.cursor) {
|
|
186
|
+
query.set("cursor", params.cursor);
|
|
187
|
+
}
|
|
188
|
+
if (params.limit) {
|
|
189
|
+
query.set("limit", String(params.limit));
|
|
190
|
+
}
|
|
191
|
+
if (params.mailboxUid) {
|
|
192
|
+
query.set("mailboxUid", params.mailboxUid);
|
|
193
|
+
}
|
|
194
|
+
return query;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function candidates(params: CandidateParams = {}, client?: ApiClient): Promise<CandidateResultPage> {
|
|
198
|
+
return withClient(client, `/mail/search/candidates?${buildCandidateParams(params).toString()}`);
|
|
199
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
/**
|
|
6
|
+
* Client-side re-scoring per `specs/search.md` §7 "Ranking and Merge": scores from different search
|
|
7
|
+
* sources are not comparable — a Postgres `ts_rank`, an OpenSearch `_score`, and a future local FTS5
|
|
8
|
+
* `bm25()` value occupy different, provider-specific ranges. The spec requires normalizing every
|
|
9
|
+
* source's scores into one shared space rather than interleaving raw values.
|
|
10
|
+
*
|
|
11
|
+
* This pass only has one source (Tier 1 - the server), so there is nothing to *merge* yet - the real
|
|
12
|
+
* cross-tier merge (§7's full ranking pass, §8's composite pagination cursor) is Tier 2/3 work,
|
|
13
|
+
* deliberately out of scope for this pass. What's implemented here is the normalization step itself,
|
|
14
|
+
* written generically (one page's raw scores in, normalized scores out) so a future per-source call
|
|
15
|
+
* into the same function is all cross-tier merging needs to add - not a second implementation of
|
|
16
|
+
* normalization.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** The spec's own field-weight table (§7), exported for reuse by whichever component eventually
|
|
20
|
+
* computes a *local* (Tier 2) score from decrypted content - the same weights must produce ranking
|
|
21
|
+
* that matches today's server-side behavior. */
|
|
22
|
+
export const SEARCH_FIELD_WEIGHTS = {
|
|
23
|
+
subject: 3,
|
|
24
|
+
participants: 2,
|
|
25
|
+
body: 1,
|
|
26
|
+
attachmentText: 1,
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Normalizes one page's raw provider scores into `[0, 1]`, preserving relative order, so a caller never
|
|
31
|
+
* has to reason about a specific provider's raw score range. `0` for every result when every score in
|
|
32
|
+
* the page is equal (including the degenerate single-result and all-zero cases) - there is no relative
|
|
33
|
+
* ordering information to preserve in that case, and `0` is a safer default than an arbitrary `1`.
|
|
34
|
+
*/
|
|
35
|
+
export function normalizeServerScores<T extends { score: number }>(results: readonly T[]): { result: T; normalizedScore: number }[] {
|
|
36
|
+
if (results.length === 0) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
const maxScore = Math.max(...results.map((r) => r.score));
|
|
40
|
+
const minScore = Math.min(...results.map((r) => r.score));
|
|
41
|
+
const range = maxScore - minScore;
|
|
42
|
+
return results.map((result) => ({
|
|
43
|
+
result,
|
|
44
|
+
normalizedScore: range === 0 ? 0 : (result.score - minScore) / range,
|
|
45
|
+
}));
|
|
46
|
+
}
|