1 import type { DBSchema } from 'idb';
3 import type { ES_SYNC_ACTIONS, INDEXING_STATUS, TIMESTAMP_TYPE } from '../constants';
4 import type { ESSetResultsList } from './esFunctions';
7 * Object to be stored locally to retry an API call
9 export interface RetryObject {
11 numberRetries: number;
15 * Object stored in local storage during indexing to keep track
16 * of its status. Note that recoveryPoint can differ between
17 * metadata or content indexing
19 export interface ESProgress {
27 originalEstimate: number;
29 status: INDEXING_STATUS;
33 * Collection of progress objects defined by the ESProgress interface
34 * "metadata" is always present, being it the default content type enabled by encrypted search
36 export interface ProgressObject {
42 * Collection of event IDs for all the components specified by the
43 * product (e.g. calendars in calendar and shares in drive)
45 export interface EventsObject {
46 [components: string]: string;
50 * Object containing the ciphertext of items as stored in IDB
52 export interface AesGcmCiphertext {
54 ciphertext: ArrayBuffer;
58 * The type of keys in the temporal index of ESDB. The first number
59 * is supposed to be a time coordinate, while the second one a
60 * tie-breaker in case of equal time
62 export type ESTimepoint = [number, number];
65 * Object representing the primary ID and the temporal coordinate
68 export interface ESItemInfo {
70 timepoint: ESTimepoint;
74 * Encrypted item, that can be either metadata or content, with
75 * extra information in plaintext
77 export interface EncryptedItemWithInfo extends ESItemInfo {
79 aesGcmCiphertext: AesGcmCiphertext;
83 * Encrypted item, that can be either metadata or content, with
86 export type EncryptedItemWithID = Omit<EncryptedItemWithInfo, 'timepoint' | 'keepSize'>;
89 * Ciphertexts in the metadata table of IDB have out-of-line keys,
90 * therefore we need to specify the ID with which to index items externally
92 export type EncryptedMetadataItem = Omit<EncryptedItemWithInfo, 'ID'>;
95 * List of possible key-value pairs types in the config object store
97 export interface ConfigValues {
105 export type ConfigKeys = keyof ConfigValues;
108 * IndexedDB structure. Each sub-object corresponds to an object store
109 * - config contains overall information, e.g. whether ES was enabled
110 * or disabled, the index key and the estimated size of all items
111 * - events contains the latest event IDs according to which items
112 * had been updated, for all components of the product
113 * - indexingProgress contains information about the status of indexing
114 * for metadata and for any other content type specified by the product
115 * - metadata contains all the actual items' metadata
116 * - content contains the content of the items which are stored in the
117 * metadata objectStore
119 export interface EncryptedSearchDB extends DBSchema {
121 value: ConfigValues[ConfigKeys];
133 value: EncryptedMetadataItem;
135 indexes: { temporal: 'timepoint' };
138 value: AesGcmCiphertext;
144 * Collection of fields to determine UI elements during indexing (e.g. progress bar, ...)
146 export interface ESIndexingState {
148 * number of items indexed so far
152 * estimated time (in minutes) expected for indexing to finish
154 estimatedMinutes: number;
156 * Total items to index
158 totalIndexingItems: number;
160 * progress value in percentage, i.e. number from 0 to 100
162 currentProgressValue: number;
165 export interface CachedItem<ESItemMetadata, ESItemContent> {
166 metadata: ESItemMetadata;
167 content?: ESItemContent;
171 * A decrypted copy of IDB kept in memory in plaintext form. The property
172 * esCache is a map of all indexed items. The property isCacheLimited refers
173 * to content only, as metadata is assumed to always fit cache
175 export interface ESCache<ESItemMetadata, ESItemContent> {
176 esCache: Map<string, CachedItem<ESItemMetadata, ESItemContent>>;
178 isCacheLimited: boolean;
179 isCacheReady: boolean;
183 * Base type for metrics on encrypted search
185 interface ESMetrics {
187 // Note: the metrics dashboard expects a variable called "numMessagesIndexed" but
188 // it doesn't make too much sense in general to talk about "messages"
189 numMessagesIndexed: number;
193 * Type of the metrics report sent after each search
195 export interface ESSearchMetrics extends ESMetrics {
197 isFirstSearch: boolean;
198 isCacheLimited: boolean;
203 * Type of the metrics report sent after indexing
205 export interface ESIndexMetrics extends ESMetrics {
207 originalEstimate: number;
208 numInterruptions: number;
209 isRefreshed: boolean;
214 * Required fields to correctly process events and keep IDB in sync. This object
215 * instructs the code to apply Action to the item specified by ID. ItemMetadata
216 * contains the metadata of the item being changed and can be omitted only in
219 export interface ESItemEvent<ESItemMetadata> {
221 Action: ES_SYNC_ACTIONS;
222 ItemMetadata: ESItemMetadata | undefined;
226 * Overall structure of an event
228 export interface ESEvent<ESItemMetadata> {
230 Items?: ESItemEvent<ESItemMetadata>[];
231 attemptReDecryption?: boolean;
232 eventsToStore: EventsObject;
236 * Interface representing an ESItem, i.e. the combination of metadata plus
237 * content. This is the overall item that can be searched. Note that metadata
238 * must always be present, while content is optional, either because content
239 * search hasn't been activated, or because a product doesn't support content
242 export type ESItem<ESItemMetadata, ESItemContent> = ESItemMetadata & Partial<ESItemContent>;
245 * Boolean variables of the ES status useful to display correct UI
246 * @var dbExists whether an instance of IndexedDB exists
247 * @var isEnablingContentSearch whether indexing of content is ongoing
248 * @var isDBLimited whether IndexedDB has fewer than the total amount of items
249 * @var esEnabled whether ES is enabled (in case a fallback to server-side search exists)
250 * @var esSupported whether the browser supports our search engine. It's true by default until indexing fails to initialise IndexedDB
251 * @var isRefreshing whether a refresh of IndexedDB (when correcting decryption errors) is ongoing
252 * @var isSearchPartial whether the current search only has partial results. It happens when IndexedDB does not fit in cache
253 * @var isSearching whether a search is ongoing
254 * @var isCacheLimited whether the cache is limited, i.e. it doesn't contain all items that are in IndexedDB
255 * @var isCacheReady whether in-memory cache load is filled
256 * @var isEnablingEncryptedSearch whether indexing of metadata is ongoing
257 * @var isContentIndexingPaused whether content indexing is paused
258 * @var isMetadataIndexingPaused whether metadata indexing is paused
259 * @var contentIndexingDone whether content indexing is finished
261 export interface ESStatusBooleans {
263 isDBLimited: boolean;
265 esSupported: boolean;
266 isRefreshing: boolean;
267 isSearchPartial: boolean;
268 isSearching: boolean;
269 isFirstSearch: boolean;
270 isEnablingContentSearch: boolean;
271 isContentIndexingPaused: boolean;
272 isMetadataIndexingPaused: boolean;
273 isEnablingEncryptedSearch: boolean;
274 contentIndexingDone: boolean;
275 isConfigFromESDBLoaded: boolean;
279 * Internal variables on the status of ES
281 export interface ESStatus<ESItemMetadata, ESItemContent, ESSearchParameters> extends ESStatusBooleans {
282 permanentResults: ESItem<ESItemMetadata, ESItemContent>[];
283 setResultsList: ESSetResultsList<ESItemMetadata, ESItemContent>;
284 lastTimePoint: ESTimepoint | undefined;
285 previousESSearchParams: ESSearchParameters | undefined;
286 cachedIndexKey: CryptoKey | undefined;
287 getCacheStatus: () => { isCacheReady: boolean; isCacheLimited: boolean };