internxt-crypto 0.0.10-alpha → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/README.md +3 -4
  2. package/dist/aes-DSDxP8uF.mjs +184 -0
  3. package/dist/aes-DSDxP8uF.mjs.map +1 -0
  4. package/dist/aes-bOrKZuUC.js +226 -0
  5. package/dist/aes-bOrKZuUC.js.map +1 -0
  6. package/dist/asymmetric-crypto.d.mts +5 -2
  7. package/dist/asymmetric-crypto.d.mts.map +1 -0
  8. package/dist/asymmetric-crypto.d.ts +5 -2
  9. package/dist/asymmetric-crypto.d.ts.map +1 -0
  10. package/dist/asymmetric-crypto.js +9 -92
  11. package/dist/asymmetric-crypto.mjs +2 -84
  12. package/dist/chunk-DQk6qfdC.mjs +18 -0
  13. package/dist/chunk-EbLFQX5m.js +60 -0
  14. package/dist/constants.d.mts +5 -11
  15. package/dist/constants.d.mts.map +1 -0
  16. package/dist/constants.d.ts +5 -11
  17. package/dist/constants.d.ts.map +1 -0
  18. package/dist/constants.js +33 -49
  19. package/dist/constants.js.map +1 -1
  20. package/dist/constants.mjs +32 -40
  21. package/dist/constants.mjs.map +1 -1
  22. package/dist/derive-key.d.mts +11 -8
  23. package/dist/derive-key.d.mts.map +1 -0
  24. package/dist/derive-key.d.ts +11 -8
  25. package/dist/derive-key.d.ts.map +1 -0
  26. package/dist/derive-key.js +13 -795
  27. package/dist/derive-key.mjs +2 -783
  28. package/dist/deriveKeysFromPassword-DJRWZ8Rw.mjs +735 -0
  29. package/dist/deriveKeysFromPassword-DJRWZ8Rw.mjs.map +1 -0
  30. package/dist/deriveKeysFromPassword-Ko7NxkHM.js +2492 -0
  31. package/dist/deriveKeysFromPassword-Ko7NxkHM.js.map +1 -0
  32. package/dist/email-crypto.d.mts +55 -78
  33. package/dist/email-crypto.d.mts.map +1 -0
  34. package/dist/email-crypto.d.ts +55 -78
  35. package/dist/email-crypto.d.ts.map +1 -0
  36. package/dist/email-crypto.js +13 -1409
  37. package/dist/email-crypto.mjs +2 -1380
  38. package/dist/email-search.d.mts +36 -32
  39. package/dist/email-search.d.mts.map +1 -0
  40. package/dist/email-search.d.ts +36 -32
  41. package/dist/email-search.d.ts.map +1 -0
  42. package/dist/email-search.js +534 -540
  43. package/dist/email-search.js.map +1 -1
  44. package/dist/email-search.mjs +532 -538
  45. package/dist/email-search.mjs.map +1 -1
  46. package/dist/emailEncryptionKey-27mIHh18.mjs +150 -0
  47. package/dist/emailEncryptionKey-27mIHh18.mjs.map +1 -0
  48. package/dist/emailEncryptionKey-DbaDAdoW.js +167 -0
  49. package/dist/emailEncryptionKey-DbaDAdoW.js.map +1 -0
  50. package/dist/emailKeys-BJGdkLrg.js +593 -0
  51. package/dist/emailKeys-BJGdkLrg.js.map +1 -0
  52. package/dist/emailKeys-Fp9WR3wl.mjs +509 -0
  53. package/dist/emailKeys-Fp9WR3wl.mjs.map +1 -0
  54. package/dist/genID-3Er5IowC.mjs +153 -0
  55. package/dist/genID-3Er5IowC.mjs.map +1 -0
  56. package/dist/genID-YJSl3YhL.js +238 -0
  57. package/dist/genID-YJSl3YhL.js.map +1 -0
  58. package/dist/hash.d.mts +18 -15
  59. package/dist/hash.d.mts.map +1 -0
  60. package/dist/hash.d.ts +18 -15
  61. package/dist/hash.d.ts.map +1 -0
  62. package/dist/hash.js +12 -95
  63. package/dist/hash.mjs +2 -84
  64. package/dist/index.d.mts +15 -18
  65. package/dist/index.d.mts.map +1 -0
  66. package/dist/index.d.ts +15 -18
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +125 -2698
  69. package/dist/index.mjs +13 -2538
  70. package/dist/keys-BfcaiAOv.mjs +90 -0
  71. package/dist/keys-BfcaiAOv.mjs.map +1 -0
  72. package/dist/keys-CinT7kEY.js +125 -0
  73. package/dist/keys-CinT7kEY.js.map +1 -0
  74. package/dist/keystore-crypto.d.mts +17 -46
  75. package/dist/keystore-crypto.d.mts.map +1 -0
  76. package/dist/keystore-crypto.d.ts +17 -46
  77. package/dist/keystore-crypto.d.ts.map +1 -0
  78. package/dist/keystore-crypto.js +5 -529
  79. package/dist/keystore-crypto.mjs +2 -500
  80. package/dist/kyber1024-PpwE1rki.mjs +144 -0
  81. package/dist/kyber1024-PpwE1rki.mjs.map +1 -0
  82. package/dist/kyber1024-jeKS8CXf.js +173 -0
  83. package/dist/kyber1024-jeKS8CXf.js.map +1 -0
  84. package/dist/{kyber768-B87rMQ7u.d.mts → kyber768-DGBB_RS7.d.ts} +8 -6
  85. package/dist/kyber768-DGBB_RS7.d.ts.map +1 -0
  86. package/dist/{kyber768-B87rMQ7u.d.ts → kyber768-DzIcGg1i.d.mts} +8 -6
  87. package/dist/kyber768-DzIcGg1i.d.mts.map +1 -0
  88. package/dist/mac-BMb1F0dN.js +170 -0
  89. package/dist/mac-BMb1F0dN.js.map +1 -0
  90. package/dist/mac-ZpRlx8Fs.mjs +116 -0
  91. package/dist/mac-ZpRlx8Fs.mjs.map +1 -0
  92. package/dist/post-quantum-crypto.d.mts +23 -27
  93. package/dist/post-quantum-crypto.d.mts.map +1 -0
  94. package/dist/post-quantum-crypto.d.ts +23 -27
  95. package/dist/post-quantum-crypto.d.ts.map +1 -0
  96. package/dist/post-quantum-crypto.js +14 -92
  97. package/dist/post-quantum-crypto.mjs +2 -89
  98. package/dist/storage-service.d.mts +28 -34
  99. package/dist/storage-service.d.mts.map +1 -0
  100. package/dist/storage-service.d.ts +28 -34
  101. package/dist/storage-service.d.ts.map +1 -0
  102. package/dist/storage-service.js +51 -53
  103. package/dist/storage-service.js.map +1 -1
  104. package/dist/storage-service.mjs +40 -51
  105. package/dist/storage-service.mjs.map +1 -1
  106. package/dist/symmetric-crypto.d.mts +8 -7
  107. package/dist/symmetric-crypto.d.mts.map +1 -0
  108. package/dist/symmetric-crypto.d.ts +8 -7
  109. package/dist/symmetric-crypto.d.ts.map +1 -0
  110. package/dist/symmetric-crypto.js +10 -142
  111. package/dist/symmetric-crypto.mjs +2 -133
  112. package/dist/types.d.mts +71 -69
  113. package/dist/types.d.mts.map +1 -0
  114. package/dist/types.d.ts +71 -69
  115. package/dist/types.d.ts.map +1 -0
  116. package/dist/types.js +8 -10
  117. package/dist/types.js.map +1 -1
  118. package/dist/types.mjs +7 -9
  119. package/dist/types.mjs.map +1 -1
  120. package/dist/utils.d.mts +34 -78
  121. package/dist/utils.d.mts.map +1 -0
  122. package/dist/utils.d.ts +34 -78
  123. package/dist/utils.d.ts.map +1 -0
  124. package/dist/utils.js +17 -313
  125. package/dist/utils.mjs +2 -272
  126. package/package.json +21 -87
  127. package/dist/asymmetric-crypto.js.map +0 -1
  128. package/dist/asymmetric-crypto.mjs.map +0 -1
  129. package/dist/derive-key.js.map +0 -1
  130. package/dist/derive-key.mjs.map +0 -1
  131. package/dist/email-crypto.js.map +0 -1
  132. package/dist/email-crypto.mjs.map +0 -1
  133. package/dist/email-service.d.mts +0 -38
  134. package/dist/email-service.d.ts +0 -38
  135. package/dist/email-service.js +0 -154
  136. package/dist/email-service.js.map +0 -1
  137. package/dist/email-service.mjs +0 -147
  138. package/dist/email-service.mjs.map +0 -1
  139. package/dist/hash.js.map +0 -1
  140. package/dist/hash.mjs.map +0 -1
  141. package/dist/index.js.map +0 -1
  142. package/dist/index.mjs.map +0 -1
  143. package/dist/keystore-crypto.js.map +0 -1
  144. package/dist/keystore-crypto.mjs.map +0 -1
  145. package/dist/keystore-service.d.mts +0 -82
  146. package/dist/keystore-service.d.ts +0 -82
  147. package/dist/keystore-service.js +0 -349
  148. package/dist/keystore-service.js.map +0 -1
  149. package/dist/keystore-service.mjs +0 -342
  150. package/dist/keystore-service.mjs.map +0 -1
  151. package/dist/post-quantum-crypto.js.map +0 -1
  152. package/dist/post-quantum-crypto.mjs.map +0 -1
  153. package/dist/symmetric-crypto.js.map +0 -1
  154. package/dist/symmetric-crypto.mjs.map +0 -1
  155. package/dist/utils-BDaK_d6T.d.ts +0 -114
  156. package/dist/utils-v34IRTIx.d.mts +0 -114
  157. package/dist/utils.js.map +0 -1
  158. package/dist/utils.mjs.map +0 -1
@@ -1,580 +1,574 @@
1
- import { openDB, deleteDB } from 'idb';
2
- import { blake3 } from '@noble/hashes/blake3.js';
3
- import { utf8ToBytes } from '@noble/hashes/utils.js';
4
- import { randomBytes } from '@noble/post-quantum/utils.js';
5
- import 'uuid';
6
- import { Index } from 'flexsearch';
1
+ import { CONTEXT_INDEX, DB_LABEL, DB_VERSION, MAX_CACHE_SIZE, MAX_EMAIL_PER_BATCH } from "./constants.mjs";
2
+ import { o as deriveSymmetricCryptoKeyFromContext } from "./deriveKeysFromPassword-DJRWZ8Rw.mjs";
3
+ import { c as encryptEmailContentSymmetricallyWithKey, l as getAux, s as decryptEmailSymmetrically, u as emailToBinary } from "./emailKeys-Fp9WR3wl.mjs";
4
+ import { deleteDB, openDB } from "idb";
5
+ import { Index } from "flexsearch";
7
6
 
8
- // src/email-search/indexedDB.ts
9
-
10
- // src/constants.ts
11
- var AES_ALGORITHM = "AES-GCM";
12
- var AES_KEY_BIT_LENGTH = 256;
13
- var AUX_LEN = 128;
14
- var IV_LEN_BYTES = 16;
15
- var KEY_FORMAT = "raw";
16
- var CONTEXT_INDEX = "CRYPTO library 2025-07-30 17:20:00 key for protecting current search indices";
17
- var MAX_CACHE_SIZE = 6e8;
18
- var MAX_EMAIL_PER_BATCH = 100;
19
- var DB_LABEL = "email";
20
- var DB_VERSION = 1;
21
- function getBytesFromString(bytes, value) {
22
- return blake3(utf8ToBytes(value), { dkLen: bytes });
23
- }
24
-
25
- // src/symmetric-crypto/keys.ts
26
- async function importSymmetricCryptoKey(keyData) {
27
- return crypto.subtle.importKey(
28
- KEY_FORMAT,
29
- new Uint8Array(keyData),
30
- {
31
- name: AES_ALGORITHM,
32
- length: AES_KEY_BIT_LENGTH
33
- },
34
- true,
35
- ["encrypt", "decrypt"]
36
- );
37
- }
38
- async function createNISTbasedIV(freeField) {
39
- try {
40
- if (!freeField) {
41
- return randomBytes(IV_LEN_BYTES);
42
- }
43
- const iv = new Uint8Array(16);
44
- const randFiled = randomBytes(12);
45
- iv.set(randFiled, 0);
46
- const freeFiledFixedLength = await getBytesFromString(4, freeField);
47
- iv.set(freeFiledFixedLength, 12);
48
- return iv;
49
- } catch (error) {
50
- throw new Error("Failed to create IV", { cause: error });
51
- }
52
- }
53
- async function makeAuxFixedLength(aux) {
54
- return getBytesFromString(AUX_LEN / 8, aux);
55
- }
56
- async function encryptMessage(message, encryptionKey, iv, additionalData) {
57
- try {
58
- const encrypted = await crypto.subtle.encrypt(
59
- { name: AES_ALGORITHM, iv, additionalData },
60
- encryptionKey,
61
- message
62
- );
63
- return new Uint8Array(encrypted);
64
- } catch (error) {
65
- throw new Error("Failed to encrypt symmetrically", { cause: error });
66
- }
67
- }
68
- async function decryptMessage(ciphertext, iv, encryptionKey, additionalData) {
69
- try {
70
- const decrypted = await crypto.subtle.decrypt(
71
- { name: AES_ALGORITHM, iv, additionalData },
72
- encryptionKey,
73
- ciphertext
74
- );
75
- return new Uint8Array(decrypted);
76
- } catch (error) {
77
- throw new Error("Failed to decrypt symmetrically", { cause: error });
78
- }
79
- }
80
-
81
- // src/symmetric-crypto/aes.ts
82
- async function encryptSymmetrically(encryptionKey, message, aux, freeField) {
83
- try {
84
- const iv = await createNISTbasedIV(freeField);
85
- const additionalData = await makeAuxFixedLength(aux);
86
- const ciphertext = await encryptMessage(message, encryptionKey, iv, additionalData);
87
- return { ciphertext, iv };
88
- } catch (error) {
89
- throw new Error("Failed to encrypt symmetrically", { cause: error });
90
- }
91
- }
92
- async function decryptSymmetrically(encryptionKey, encryptedMessage, aux) {
93
- try {
94
- const additionalData = await makeAuxFixedLength(aux);
95
- const result = await decryptMessage(
96
- encryptedMessage.ciphertext,
97
- encryptedMessage.iv,
98
- encryptionKey,
99
- additionalData
100
- );
101
- return result;
102
- } catch (error) {
103
- throw new Error("Failed to decrypt symmetrically", { cause: error });
104
- }
105
- }
106
- function UTF8ToUint8(str) {
107
- return new TextEncoder().encode(str);
108
- }
109
- function uint8ToUTF8(array) {
110
- return new TextDecoder().decode(array);
111
- }
112
-
113
- // src/email-crypto/converters.ts
114
- function emailBodyToBinary(body) {
115
- try {
116
- const json = JSON.stringify(body);
117
- return UTF8ToUint8(json);
118
- } catch (error) {
119
- throw new Error("Failed to convert EmailBody to Uint8Array", { cause: error });
120
- }
121
- }
122
- function binaryToEmailBody(array) {
123
- try {
124
- const json = uint8ToUTF8(array);
125
- const email = JSON.parse(json);
126
- return email;
127
- } catch (error) {
128
- throw new Error("Failed to convert Uint8Array to EmailBody", { cause: error });
129
- }
130
- }
131
- function emailToBinary(email) {
132
- try {
133
- const json = JSON.stringify(email);
134
- return UTF8ToUint8(json);
135
- } catch (error) {
136
- throw new Error("Failed to convert EmailBody to Uint8Array", { cause: error });
137
- }
138
- }
139
- function deriveSymmetricKeyFromContext(context, baseKey) {
140
- return blake3(baseKey, { context: UTF8ToUint8(context) });
141
- }
142
- async function deriveSymmetricCryptoKeyFromContext(context, baseKey) {
143
- try {
144
- if (baseKey.length != AES_KEY_BIT_LENGTH / 8) {
145
- throw new Error(`Base key length must be exactly ${AES_KEY_BIT_LENGTH / 8} bytes`);
146
- }
147
- if (!context) ;
148
- const keyBytes = deriveSymmetricKeyFromContext(context, baseKey);
149
- const key = await importSymmetricCryptoKey(keyBytes);
150
- return key;
151
- } catch (error) {
152
- throw new Error("Failed to derive CryptoKey from base key and context", { cause: error });
153
- }
154
- }
155
-
156
- // src/email-crypto/core.ts
157
- async function encryptEmailContentSymmetricallyWithKey(emailBody, encryptionKey, aux, emailID) {
158
- try {
159
- const binaryEmail = emailBodyToBinary(emailBody);
160
- const ciphertext = await encryptSymmetrically(encryptionKey, binaryEmail, aux, emailID);
161
- return ciphertext;
162
- } catch (error) {
163
- throw new Error("Failed to symmetrically encrypt email with the given key", { cause: error });
164
- }
165
- }
166
- async function decryptEmailSymmetrically(emailCiphertext, encryptionKey, aux) {
167
- try {
168
- const binaryEmail = await decryptSymmetrically(encryptionKey, emailCiphertext, aux);
169
- const body = binaryToEmailBody(binaryEmail);
170
- return body;
171
- } catch (error) {
172
- throw new Error("Failed to symmetrically decrypt email", { cause: error });
173
- }
174
- }
175
- function getAux(params) {
176
- try {
177
- const { subject, replyToEmailID, sender, recipients } = params;
178
- const aux = JSON.stringify({ subject, replyToEmailID, sender, recipients });
179
- return aux;
180
- } catch (error) {
181
- throw new Error("Failed to create aux", { cause: error });
182
- }
183
- }
184
-
185
- // src/email-search/indexedDB.ts
186
- var getDatabaseName = (userID) => {
187
- return `ES:${userID}:DB`;
7
+ //#region src/email-search/indexedDB.ts
8
+ /**
9
+ * Returns IndexedDB database name for the given user
10
+ *
11
+ * @param userID - The user ID
12
+ * @returns The database name
13
+ */
14
+ const getDatabaseName = (userID) => {
15
+ return `ES:${userID}:DB`;
188
16
  };
189
- var openDatabase = async (userID) => {
190
- try {
191
- const dbName = getDatabaseName(userID);
192
- return openDB(dbName, DB_VERSION, {
193
- upgrade(db) {
194
- if (!db.objectStoreNames.contains(DB_LABEL)) {
195
- const store = db.createObjectStore(DB_LABEL, { keyPath: "id" });
196
- store.createIndex("byTime", "params.createdAt");
197
- }
198
- }
199
- });
200
- } catch (error) {
201
- throw new Error(`Cannot open a database for the user ${userID}`, { cause: error });
202
- }
17
+ /**
18
+ * Opens IndexedDB database for the given user
19
+ *
20
+ * @param userID - The user ID
21
+ * @returns The database
22
+ */
23
+ const openDatabase = async (userID) => {
24
+ try {
25
+ return openDB(getDatabaseName(userID), DB_VERSION, { upgrade(db) {
26
+ if (!db.objectStoreNames.contains(DB_LABEL)) db.createObjectStore(DB_LABEL, { keyPath: "id" }).createIndex("byTime", "params.createdAt");
27
+ } });
28
+ } catch (error) {
29
+ throw new Error(`Cannot open a database for the user ${userID}`, { cause: error });
30
+ }
203
31
  };
204
- var closeDatabase = (esDB) => {
205
- return esDB.close();
32
+ /**
33
+ * Closes the IndexedDB database
34
+ *
35
+ * @param esDB - The database
36
+ */
37
+ const closeDatabase = (esDB) => {
38
+ return esDB.close();
206
39
  };
207
- var deleteDatabase = async (userID) => {
208
- const dbName = getDatabaseName(userID);
209
- return deleteDB(dbName);
40
+ /**
41
+ * Deletes IndexedDB database for the given user
42
+ *
43
+ * @param userID - The user ID
44
+ * @returns The database
45
+ */
46
+ const deleteDatabase = async (userID) => {
47
+ return deleteDB(getDatabaseName(userID));
210
48
  };
211
- var deriveIndexKey = async (baseKey) => {
212
- return deriveSymmetricCryptoKeyFromContext(CONTEXT_INDEX, baseKey);
49
+ /**
50
+ * Derives database encryption key for the given user
51
+ *
52
+ * @param userID - The user ID
53
+ * @returns The symmetric CryptoKey for protecting database
54
+ */
55
+ const deriveIndexKey = async (baseKey) => {
56
+ return deriveSymmetricCryptoKeyFromContext(CONTEXT_INDEX, baseKey);
213
57
  };
214
- var encryptAndStoreEmail = async (newEmailToStore, indexKey, esDB) => {
215
- try {
216
- const aux = getAux(newEmailToStore.params);
217
- const ciphertext = await encryptEmailContentSymmetricallyWithKey(
218
- newEmailToStore.body,
219
- indexKey,
220
- aux,
221
- newEmailToStore.id
222
- );
223
- const encryptedEmail = { content: ciphertext, params: newEmailToStore.params, id: newEmailToStore.id };
224
- await esDB.put(DB_LABEL, encryptedEmail);
225
- } catch (error) {
226
- throw new Error("Cannot encrypt and add the given email to the database", { cause: error });
227
- }
58
+ /**
59
+ * Encrypts the given email and stores it in the IndexedDB database
60
+ *
61
+ * @param newEmailToStore - The email for storing
62
+ * @param indexKey - The symmetric CryptoKey key for protecting database
63
+ * @param esDB - The database
64
+ */
65
+ const encryptAndStoreEmail = async (newEmailToStore, indexKey, esDB) => {
66
+ try {
67
+ const aux = getAux(newEmailToStore.params, false);
68
+ const encryptedEmail = {
69
+ enc: await encryptEmailContentSymmetricallyWithKey(newEmailToStore.body, indexKey, aux, newEmailToStore.id),
70
+ params: newEmailToStore.params,
71
+ id: newEmailToStore.id
72
+ };
73
+ await esDB.put(DB_LABEL, encryptedEmail);
74
+ } catch (error) {
75
+ throw new Error("Cannot encrypt and add the given email to the database", { cause: error });
76
+ }
228
77
  };
229
- var encryptAndStoreManyEmail = async (newEmailsToStore, indexKey, esDB) => {
230
- try {
231
- const encryptedEmails = await Promise.all(
232
- newEmailsToStore.map(async (email) => {
233
- const aux = getAux(email.params);
234
- const ciphertext = await encryptEmailContentSymmetricallyWithKey(email.body, indexKey, aux, email.id);
235
- return { content: ciphertext, params: email.params, id: email.id };
236
- })
237
- );
238
- const tr = esDB.transaction(DB_LABEL, "readwrite");
239
- await Promise.all([...encryptedEmails.map((encEmail) => tr.store.put(encEmail)), tr.done]);
240
- } catch (error) {
241
- throw new Error("Cannot encrypt and add emails to the database", { cause: error });
242
- }
78
+ /**
79
+ * Encrypts the given set of emails and stores it in the IndexedDB database
80
+ *
81
+ * @param newEmailsToStore - The set of emails for storing
82
+ * @param indexKey - The symmetric CryptoKey key for protecting database
83
+ * @param esDB - The database
84
+ */
85
+ const encryptAndStoreManyEmail = async (newEmailsToStore, indexKey, esDB) => {
86
+ try {
87
+ const encryptedEmails = await Promise.all(newEmailsToStore.map(async (email) => {
88
+ const aux = getAux(email.params, false);
89
+ return {
90
+ enc: await encryptEmailContentSymmetricallyWithKey(email.body, indexKey, aux, email.id),
91
+ params: email.params,
92
+ id: email.id
93
+ };
94
+ }));
95
+ const tr = esDB.transaction(DB_LABEL, "readwrite");
96
+ await Promise.all([...encryptedEmails.map((encEmail) => tr.store.put(encEmail)), tr.done]);
97
+ } catch (error) {
98
+ throw new Error("Cannot encrypt and add emails to the database", { cause: error });
99
+ }
243
100
  };
244
- var decryptEmail = async (indexKey, encryptedEmail) => {
245
- try {
246
- const aux = getAux(encryptedEmail.params);
247
- const email = await decryptEmailSymmetrically(encryptedEmail.content, indexKey, aux);
248
- return { body: email, params: encryptedEmail.params, id: encryptedEmail.id };
249
- } catch (error) {
250
- throw new Error("Cannot decrypt the given email", { cause: error });
251
- }
101
+ /**
102
+ * Decrypts the given email
103
+ *
104
+ * @param indexKey - The symmetric CryptoKey key for protecting database
105
+ * @param encryptedEmail - The encrypted email
106
+ * @returns The decrypted email
107
+ */
108
+ const decryptEmail = async (indexKey, encryptedEmail) => {
109
+ try {
110
+ return {
111
+ body: await decryptEmailSymmetrically(indexKey, getAux(encryptedEmail.params, false), encryptedEmail.enc),
112
+ params: encryptedEmail.params,
113
+ id: encryptedEmail.id
114
+ };
115
+ } catch (error) {
116
+ throw new Error("Cannot decrypt the given email", { cause: error });
117
+ }
252
118
  };
253
- var getAndDecryptEmail = async (emailID, indexKey, esDB) => {
254
- try {
255
- const encryptedEmail = await esDB.get(DB_LABEL, emailID);
256
- if (!encryptedEmail) {
257
- throw new Error(`DB cannot find email with id ${emailID}`);
258
- }
259
- return decryptEmail(indexKey, encryptedEmail);
260
- } catch (error) {
261
- throw new Error(`Cannot fetch the email ${emailID} from the database`, { cause: error });
262
- }
119
+ /**
120
+ * Fetches the email from the database and decrypts it
121
+ *
122
+ * @param emailID - The email identifier
123
+ * @param indexKey - The symmetric CryptoKey key for protecting database
124
+ * @param encryptedEmail - The encrypted email
125
+ * @returns The decrypted email
126
+ */
127
+ const getAndDecryptEmail = async (emailID, indexKey, esDB) => {
128
+ try {
129
+ const encryptedEmail = await esDB.get(DB_LABEL, emailID);
130
+ if (!encryptedEmail) throw new Error(`DB cannot find email with id ${emailID}`);
131
+ return decryptEmail(indexKey, encryptedEmail);
132
+ } catch (error) {
133
+ throw new Error(`Cannot fetch the email ${emailID} from the database`, { cause: error });
134
+ }
263
135
  };
264
- var getAndDecryptAllEmails = async (indexKey, esDB) => {
265
- try {
266
- const encryptedEmails = await esDB.getAll(DB_LABEL);
267
- const decryptedEmails = await Promise.all(
268
- encryptedEmails.map(async (encEmail) => {
269
- const aux = getAux(encEmail.params);
270
- const body = await decryptEmailSymmetrically(encEmail.content, indexKey, aux);
271
- return { body, params: encEmail.params, id: encEmail.id };
272
- })
273
- );
274
- return decryptedEmails.filter((email) => email !== null);
275
- } catch (error) {
276
- throw new Error("Cannot fetch and decrypt all emails from the database", { cause: error });
277
- }
136
+ /**
137
+ * Fetches all email from the database and decrypts them
138
+ *
139
+ * @param indexKey - The symmetric CryptoKey key for protecting database
140
+ * @param esDB - The database
141
+ * @returns The decrypted emails
142
+ */
143
+ const getAndDecryptAllEmails = async (indexKey, esDB) => {
144
+ try {
145
+ const encryptedEmails = await esDB.getAll(DB_LABEL);
146
+ return (await Promise.all(encryptedEmails.map(async (encEmail) => {
147
+ return {
148
+ body: await decryptEmailSymmetrically(indexKey, getAux(encEmail.params, false), encEmail.enc),
149
+ params: encEmail.params,
150
+ id: encEmail.id
151
+ };
152
+ }))).filter((email) => email !== null);
153
+ } catch (error) {
154
+ throw new Error("Cannot fetch and decrypt all emails from the database", { cause: error });
155
+ }
278
156
  };
279
- var deleteEmail = async (emailID, esDB) => {
280
- await esDB.delete(DB_LABEL, emailID);
157
+ /**
158
+ * Deletes the email from the database
159
+ *
160
+ * @param emailID - The email identifier
161
+ * @param esDB - The database
162
+ */
163
+ const deleteEmail = async (emailID, esDB) => {
164
+ await esDB.delete(DB_LABEL, emailID);
281
165
  };
282
- var getEmailCount = async (esDB) => {
283
- return await esDB.count(DB_LABEL);
166
+ /**
167
+ * Returns the number of stored email
168
+ *
169
+ * @param esDB - The database
170
+ * @returns The number of stored emails
171
+ */
172
+ const getEmailCount = async (esDB) => {
173
+ return await esDB.count(DB_LABEL);
284
174
  };
285
- var deleteOldestEmails = async (emailsToDelete, esDB) => {
286
- try {
287
- const tx = esDB.transaction(DB_LABEL, "readwrite");
288
- const index = tx.store.index("byTime");
289
- let cursor = await index.openCursor();
290
- let deletedCount = 0;
291
- while (cursor && deletedCount < emailsToDelete) {
292
- await cursor.delete();
293
- deletedCount++;
294
- cursor = await cursor.continue();
295
- }
296
- await tx.done;
297
- } catch (error) {
298
- throw new Error(`Cannot delete ${emailsToDelete} oldests emails from the database`, { cause: error });
299
- }
175
+ /**
176
+ * Removes the given number of oldests emails from the database
177
+ *
178
+ * @param emailsToDelete - The number of emails to delete
179
+ * @param esDB - The database
180
+ */
181
+ const deleteOldestEmails = async (emailsToDelete, esDB) => {
182
+ try {
183
+ const tx = esDB.transaction(DB_LABEL, "readwrite");
184
+ let cursor = await tx.store.index("byTime").openCursor();
185
+ let deletedCount = 0;
186
+ while (cursor && deletedCount < emailsToDelete) {
187
+ await cursor.delete();
188
+ deletedCount++;
189
+ cursor = await cursor.continue();
190
+ }
191
+ await tx.done;
192
+ } catch (error) {
193
+ throw new Error(`Cannot delete ${emailsToDelete} oldests emails from the database`, { cause: error });
194
+ }
300
195
  };
301
- var enforceMaxEmailNumber = async (esDB, max) => {
302
- try {
303
- const currentCount = await getEmailCount(esDB);
304
- if (currentCount <= max) {
305
- return;
306
- }
307
- await deleteOldestEmails(currentCount - max, esDB);
308
- } catch (error) {
309
- throw new Error(`Cannot enforce the maximum of ${max} emails on the database`, { cause: error });
310
- }
196
+ /**
197
+ * Enforces the maximum email number in the database
198
+ *
199
+ * @param esDB - The database
200
+ * @param max - The maximum allowed number of emails
201
+ */
202
+ const enforceMaxEmailNumber = async (esDB, max) => {
203
+ try {
204
+ const currentCount = await getEmailCount(esDB);
205
+ if (currentCount <= max) return;
206
+ await deleteOldestEmails(currentCount - max, esDB);
207
+ } catch (error) {
208
+ throw new Error(`Cannot enforce the maximum of ${max} emails on the database`, { cause: error });
209
+ }
311
210
  };
312
- var fetchEmails = async (esDB, indexKey, direction) => {
313
- try {
314
- const tx = esDB.transaction(DB_LABEL, "readonly");
315
- const index = tx.store.index("byTime");
316
- const encryptedEmails = [];
317
- let cursor = await index.openCursor(null, direction);
318
- while (cursor) {
319
- encryptedEmails.push(cursor.value);
320
- cursor = await cursor.continue();
321
- }
322
- const emails = await Promise.all(encryptedEmails.map((encryptedEmail) => decryptEmail(indexKey, encryptedEmail)));
323
- return emails;
324
- } catch (error) {
325
- throw new Error("Cannot fetch emails from database", { cause: error });
326
- }
211
+ /**
212
+ * Fetches all emails from the database, decrypts them and sortes the results in the specified order
213
+ *
214
+ * @param esDB - The database
215
+ * @param indexKey - The symmetric CryptoKey key for protecting database
216
+ * @param direction - The order of sorting. If 'next' - oldest first, if 'prev' - newest first
217
+ * @returns Decryped emails in the specified order
218
+ */
219
+ const fetchEmails = async (esDB, indexKey, direction) => {
220
+ try {
221
+ const index = esDB.transaction(DB_LABEL, "readonly").store.index("byTime");
222
+ const encryptedEmails = [];
223
+ let cursor = await index.openCursor(null, direction);
224
+ while (cursor) {
225
+ encryptedEmails.push(cursor.value);
226
+ cursor = await cursor.continue();
227
+ }
228
+ return await Promise.all(encryptedEmails.map((encryptedEmail) => decryptEmail(indexKey, encryptedEmail)));
229
+ } catch (error) {
230
+ throw new Error("Cannot fetch emails from database", { cause: error });
231
+ }
327
232
  };
328
- var getAllEmailsSortedNewestFirst = async (esDB, indexKey) => {
329
- return fetchEmails(esDB, indexKey, "prev");
233
+ /**
234
+ * Fetches all emails from the database, decrypts them and sortes the results based on the creation time (newest first)
235
+ *
236
+ * @param esDB - The database
237
+ * @param indexKey - The symmetric CryptoKey key for protecting database
238
+ * @returns The number of stored emails
239
+ */
240
+ const getAllEmailsSortedNewestFirst = async (esDB, indexKey) => {
241
+ return fetchEmails(esDB, indexKey, "prev");
330
242
  };
331
- var getAllEmailsSortedOldestFirst = async (esDB, indexKey) => {
332
- return fetchEmails(esDB, indexKey, "next");
243
+ /**
244
+ * Fetches all emails from the database, decrypts them and sortes the results based on the creation time (oldest first)
245
+ *
246
+ * @param esDB - The database
247
+ * @param indexKey - The symmetric CryptoKey key for protecting database
248
+ * @returns The number of stored emails
249
+ */
250
+ const getAllEmailsSortedOldestFirst = async (esDB, indexKey) => {
251
+ return fetchEmails(esDB, indexKey, "next");
333
252
  };
334
- var getEmailBatch = async (esDB, indexKey, batchSize, startCursor) => {
335
- try {
336
- const tx = esDB.transaction(DB_LABEL, "readonly");
337
- const index = tx.store.index("byTime");
338
- const encryptedEmails = [];
339
- let cursor;
340
- if (startCursor) {
341
- const range = IDBKeyRange.upperBound(startCursor, true);
342
- cursor = await index.openCursor(range, "prev");
343
- } else {
344
- cursor = await index.openCursor(null, "prev");
345
- }
346
- let count = 0;
347
- let nextCursor;
348
- while (cursor && count < batchSize) {
349
- encryptedEmails.push(cursor.value);
350
- nextCursor = cursor.key;
351
- count++;
352
- cursor = await cursor.continue();
353
- }
354
- const emails = await Promise.all(encryptedEmails.map((encryptedEmail) => decryptEmail(indexKey, encryptedEmail)));
355
- return {
356
- emails,
357
- nextCursor: count === batchSize ? nextCursor : void 0
358
- };
359
- } catch (error) {
360
- throw new Error(`Cannot fetch email batch of ${batchSize} from the database`, { cause: error });
361
- }
253
+ /**
254
+ * Fetches a batch of emails from the database, decrypts them and sortes the results based on the creation time (newest first)
255
+ *
256
+ * @param esDB - The database
257
+ * @param indexKey - The symmetric CryptoKey key for protecting database
258
+ * @param batchSize - The size of the batch
259
+ * @param startCursor - The starting point (optional). If not given, starts from the beginning
260
+ * @returns The number of stored emails
261
+ */
262
+ const getEmailBatch = async (esDB, indexKey, batchSize, startCursor) => {
263
+ try {
264
+ const index = esDB.transaction(DB_LABEL, "readonly").store.index("byTime");
265
+ const encryptedEmails = [];
266
+ let cursor;
267
+ if (startCursor) {
268
+ const range = IDBKeyRange.upperBound(startCursor, true);
269
+ cursor = await index.openCursor(range, "prev");
270
+ } else cursor = await index.openCursor(null, "prev");
271
+ let count = 0;
272
+ let nextCursor;
273
+ while (cursor && count < batchSize) {
274
+ encryptedEmails.push(cursor.value);
275
+ nextCursor = cursor.key;
276
+ count++;
277
+ cursor = await cursor.continue();
278
+ }
279
+ return {
280
+ emails: await Promise.all(encryptedEmails.map((encryptedEmail) => decryptEmail(indexKey, encryptedEmail))),
281
+ nextCursor: count === batchSize ? nextCursor : void 0
282
+ };
283
+ } catch (error) {
284
+ throw new Error(`Cannot fetch email batch of ${batchSize} from the database`, { cause: error });
285
+ }
362
286
  };
363
287
 
364
- // src/email-search/mailCache.ts
288
+ //#endregion
289
+ //#region src/email-search/mailCache.ts
290
+ /**
291
+ * Estimates the email size in the memory
292
+ *
293
+ * @param email - The email
294
+ * @returns The estimation of the email size
295
+ */
365
296
  function sizeOfEmail(email) {
366
- return emailToBinary(email).byteLength;
297
+ return emailToBinary(email).byteLength;
367
298
  }
299
+ /**
300
+ * Creates an empty cache variable
301
+ *
302
+ * @returns The empty cache
303
+ */
368
304
  function createEmptyCache() {
369
- return {
370
- esCache: /* @__PURE__ */ new Map(),
371
- cacheSize: 0,
372
- isCacheLimited: false,
373
- isCacheReady: true
374
- };
305
+ return {
306
+ esCache: /* @__PURE__ */ new Map(),
307
+ cacheSize: 0,
308
+ isCacheLimited: false,
309
+ isCacheReady: true
310
+ };
375
311
  }
376
- var createCacheFromDB = async (indexKey, esDB) => {
377
- const esCache = createEmptyCache();
378
- esCache.isCacheReady = false;
379
- try {
380
- const count = await getEmailCount(esDB);
381
- if (!count) {
382
- esCache.isCacheReady = true;
383
- return esCache;
384
- }
385
- if (count <= MAX_EMAIL_PER_BATCH) {
386
- const emails = await getAllEmailsSortedNewestFirst(esDB, indexKey);
387
- addEmailsToCache(emails, esCache);
388
- } else {
389
- let nextCursor = void 0;
390
- let cacheFull = false;
391
- while (!cacheFull) {
392
- const { emails, nextCursor: newCursor } = await getEmailBatch(
393
- esDB,
394
- indexKey,
395
- MAX_EMAIL_PER_BATCH,
396
- nextCursor
397
- );
398
- if (!newCursor || !emails.length) break;
399
- nextCursor = newCursor;
400
- const success = addEmailsToCache(emails, esCache);
401
- if (!success) cacheFull = true;
402
- }
403
- }
404
- return esCache;
405
- } catch (error) {
406
- throw new Error(`Email caching failed: ${error}`);
407
- }
312
+ /**
313
+ * Fetches all emails from the database in batches and cahces them
314
+ *
315
+ * @param indexKey - The symmetric CryptoKey key for protecting database
316
+ * @param esCache - The cache to add emails too
317
+ * @param esDB - The database
318
+ */
319
+ const createCacheFromDB = async (indexKey, esDB) => {
320
+ const esCache = createEmptyCache();
321
+ esCache.isCacheReady = false;
322
+ try {
323
+ const count = await getEmailCount(esDB);
324
+ if (!count) {
325
+ esCache.isCacheReady = true;
326
+ return esCache;
327
+ }
328
+ if (count <= MAX_EMAIL_PER_BATCH) addEmailsToCache(await getAllEmailsSortedNewestFirst(esDB, indexKey), esCache);
329
+ else {
330
+ let nextCursor = void 0;
331
+ let cacheFull = false;
332
+ while (!cacheFull) {
333
+ const { emails, nextCursor: newCursor } = await getEmailBatch(esDB, indexKey, MAX_EMAIL_PER_BATCH, nextCursor);
334
+ if (!newCursor || !emails.length) break;
335
+ nextCursor = newCursor;
336
+ if (!addEmailsToCache(emails, esCache)) cacheFull = true;
337
+ }
338
+ }
339
+ return esCache;
340
+ } catch (error) {
341
+ throw new Error(`Email caching failed: ${error}`, { cause: error });
342
+ }
408
343
  };
409
- var getEmailFromCache = async (emailID, esCache) => {
410
- const email = esCache.esCache.get(emailID);
411
- if (!email) {
412
- throw new Error(`Email not found in cache for ID: ${emailID}`);
413
- }
414
- return email;
344
+ /**
345
+ * Gets an email from the cache
346
+ *
347
+ * @param emailID - The email identifier
348
+ * @param esCache - The email cache
349
+ * @returns The found email or throws an error
350
+ */
351
+ const getEmailFromCache = async (emailID, esCache) => {
352
+ const email = esCache.esCache.get(emailID);
353
+ if (!email) throw new Error(`Email not found in cache for ID: ${emailID}`);
354
+ return email;
415
355
  };
416
- var deleteEmailFromCache = async (emailID, esCache) => {
417
- try {
418
- const email = await getEmailFromCache(emailID, esCache);
419
- const size = sizeOfEmail(email);
420
- const removed = esCache.esCache.delete(emailID);
421
- if (removed) esCache.cacheSize -= size;
422
- } catch (error) {
423
- throw new Error(`Failed to delete email with ID ${emailID}`, { cause: error });
424
- }
356
+ /**
357
+ * Removes the email from cache
358
+ *
359
+ * @param emailID - The email identifier
360
+ * @param esCache - The email cache
361
+ */
362
+ const deleteEmailFromCache = async (emailID, esCache) => {
363
+ try {
364
+ const size = sizeOfEmail(await getEmailFromCache(emailID, esCache));
365
+ if (esCache.esCache.delete(emailID)) esCache.cacheSize -= size;
366
+ } catch (error) {
367
+ throw new Error(`Failed to delete email with ID ${emailID}`, { cause: error });
368
+ }
425
369
  };
370
+ /**
371
+ * Adds emails to the cache
372
+ *
373
+ * @param emails - The emails to add
374
+ * @param esCache - The email cache
375
+ * @returns TRUE if all emails were added sucessfully, or FALSE and error reason.
376
+ */
426
377
  function addEmailsToCache(emails, esCache) {
427
- try {
428
- for (const email of emails) {
429
- const result = addEmailToCache(email, esCache);
430
- if (!result.success) return result;
431
- }
432
- return { success: true };
433
- } catch (error) {
434
- throw new Error("Failed to add emails to the cache", { cause: error });
435
- }
378
+ try {
379
+ for (const email of emails) {
380
+ const result = addEmailToCache(email, esCache);
381
+ if (!result.success) return result;
382
+ }
383
+ return { success: true };
384
+ } catch (error) {
385
+ throw new Error("Failed to add emails to the cache", { cause: error });
386
+ }
436
387
  }
437
- var addEmailToCache = (email, esCache) => {
438
- try {
439
- if (esCache.esCache.has(email.id)) {
440
- return { success: false, reason: "email already exists in cache" };
441
- }
442
- const emailSize = sizeOfEmail(email);
443
- if (esCache.cacheSize + emailSize > MAX_CACHE_SIZE) {
444
- esCache.isCacheLimited = true;
445
- return { success: false, reason: "hit cache limit" };
446
- }
447
- esCache.esCache.set(email.id, email);
448
- esCache.cacheSize += emailSize;
449
- return { success: true };
450
- } catch (error) {
451
- throw new Error("Failed to add email to the cache", { cause: error });
452
- }
388
+ /**
389
+ * Adds email to the cache
390
+ *
391
+ * @param email - The email to add
392
+ * @param esCache - The email cache
393
+ * @returns TRUE if the email was added sucessfully, or FALSE and error reason.
394
+ */
395
+ const addEmailToCache = (email, esCache) => {
396
+ try {
397
+ if (esCache.esCache.has(email.id)) return {
398
+ success: false,
399
+ reason: "email already exists in cache"
400
+ };
401
+ const emailSize = sizeOfEmail(email);
402
+ if (esCache.cacheSize + emailSize > MAX_CACHE_SIZE) {
403
+ esCache.isCacheLimited = true;
404
+ return {
405
+ success: false,
406
+ reason: "hit cache limit"
407
+ };
408
+ }
409
+ esCache.esCache.set(email.id, email);
410
+ esCache.cacheSize += emailSize;
411
+ return { success: true };
412
+ } catch (error) {
413
+ throw new Error("Failed to add email to the cache", { cause: error });
414
+ }
453
415
  };
454
- var SUBJECT_OPTIONS = {
455
- preset: "match",
456
- tokenize: "forward",
457
- resolution: 9,
458
- minlength: 2,
459
- optimize: true,
460
- fastupdate: true,
461
- cache: true
416
+
417
+ //#endregion
418
+ //#region src/email-search/search.ts
419
+ const SUBJECT_OPTIONS = {
420
+ preset: "match",
421
+ tokenize: "forward",
422
+ resolution: 9,
423
+ minlength: 2,
424
+ optimize: true,
425
+ fastupdate: true,
426
+ cache: true
462
427
  };
463
- var BODY_OPTIONS = {
464
- ...SUBJECT_OPTIONS,
465
- minlength: 3,
466
- resolution: 6
428
+ const BODY_OPTIONS = {
429
+ ...SUBJECT_OPTIONS,
430
+ minlength: 3,
431
+ resolution: 6
467
432
  };
468
- var FROM_OPTIONS = {
469
- ...SUBJECT_OPTIONS,
470
- tokenize: "strict",
471
- minlength: 1
433
+ const FROM_OPTIONS = {
434
+ ...SUBJECT_OPTIONS,
435
+ tokenize: "strict",
436
+ minlength: 1
472
437
  };
473
- var TO_OPTIONS = {
474
- ...SUBJECT_OPTIONS,
475
- tokenize: "strict",
476
- minlength: 1
438
+ const TO_OPTIONS = {
439
+ ...SUBJECT_OPTIONS,
440
+ tokenize: "strict",
441
+ minlength: 1
477
442
  };
478
- var createSearchIndex = () => ({
479
- subjectIndex: new Index(SUBJECT_OPTIONS),
480
- bodyIndex: new Index(BODY_OPTIONS),
481
- fromIndex: new Index(FROM_OPTIONS),
482
- toIndex: new Index(TO_OPTIONS),
483
- isReady: false
443
+ /**
444
+ * Creates new email search index
445
+ *
446
+ * @returns The email search index
447
+ */
448
+ const createSearchIndex = () => ({
449
+ subjectIndex: new Index(SUBJECT_OPTIONS),
450
+ bodyIndex: new Index(BODY_OPTIONS),
451
+ fromIndex: new Index(FROM_OPTIONS),
452
+ toIndex: new Index(TO_OPTIONS),
453
+ isReady: false
484
454
  });
485
- var addEmailToSearchIndex = (email, searchIndex) => {
486
- try {
487
- const emailId = email.id;
488
- if (email.params.subject) {
489
- searchIndex.subjectIndex.add(emailId, email.params.subject);
490
- }
491
- if (email.body?.text) {
492
- searchIndex.bodyIndex.add(emailId, email.body.text);
493
- }
494
- if (email.params.sender) {
495
- const senderText = `${email.params.sender.name || ""} ${email.params.sender.email || ""}`.trim();
496
- searchIndex.fromIndex.add(emailId, senderText);
497
- }
498
- const recipientsList = email.params.recipients?.length ? email.params.recipients : [email.params.recipient];
499
- const recipientsText = recipientsList.map((recipient) => `${recipient.name || ""} ${recipient.email || ""}`.trim()).join(" ");
500
- searchIndex.toIndex.add(emailId, recipientsText);
501
- } catch (error) {
502
- throw new Error("Failed to add email to the search index", { cause: error });
503
- }
455
+ /**
456
+ * Adds the given email to the email search index
457
+ *
458
+ * @param email - The email to add
459
+ * @param searchIndex - The email search index
460
+ */
461
+ const addEmailToSearchIndex = (email, searchIndex) => {
462
+ try {
463
+ const emailId = email.id;
464
+ if (email.params.subject) searchIndex.subjectIndex.add(emailId, email.params.subject);
465
+ if (email.body?.text) searchIndex.bodyIndex.add(emailId, email.body.text);
466
+ if (email.params.sender) {
467
+ const senderText = `${email.params.sender.name || ""} ${email.params.sender.email || ""}`.trim();
468
+ searchIndex.fromIndex.add(emailId, senderText);
469
+ }
470
+ const recipientsText = (email.params.recipients?.length ? email.params.recipients : [email.params.recipient]).map((recipient) => `${recipient.name || ""} ${recipient.email || ""}`.trim()).join(" ");
471
+ searchIndex.toIndex.add(emailId, recipientsText);
472
+ } catch (error) {
473
+ throw new Error("Failed to add email to the search index", { cause: error });
474
+ }
504
475
  };
505
- var removeEmailFromSearchIndex = (emailID, searchIndex) => {
506
- try {
507
- searchIndex.subjectIndex.remove(emailID);
508
- searchIndex.bodyIndex.remove(emailID);
509
- searchIndex.fromIndex.remove(emailID);
510
- searchIndex.toIndex.remove(emailID);
511
- } catch (error) {
512
- throw new Error(`Failed to remove email with ID ${emailID} from the search index`, { cause: error });
513
- }
476
+ /**
477
+ * Removes the email from the email search index
478
+ *
479
+ * @param emailID - The email identifier
480
+ * @param searchIndex - The email search index
481
+ */
482
+ const removeEmailFromSearchIndex = (emailID, searchIndex) => {
483
+ try {
484
+ searchIndex.subjectIndex.remove(emailID);
485
+ searchIndex.bodyIndex.remove(emailID);
486
+ searchIndex.fromIndex.remove(emailID);
487
+ searchIndex.toIndex.remove(emailID);
488
+ } catch (error) {
489
+ throw new Error(`Failed to remove email with ID ${emailID} from the search index`, { cause: error });
490
+ }
514
491
  };
515
- var buildSearchIndexFromCache = async (esCache) => {
516
- try {
517
- const searchIndex = createSearchIndex();
518
- searchIndex.isReady = false;
519
- for (const email of esCache.esCache.values()) {
520
- addEmailToSearchIndex(email, searchIndex);
521
- }
522
- searchIndex.isReady = true;
523
- return searchIndex;
524
- } catch (error) {
525
- throw new Error("Failed build an email search index from the cache", { cause: error });
526
- }
492
+ /**
493
+ * Buils the email search index from the email cache
494
+ *
495
+ * @param esCache - The email cache
496
+ * @returns The email search index
497
+ */
498
+ const buildSearchIndexFromCache = async (esCache) => {
499
+ try {
500
+ const searchIndex = createSearchIndex();
501
+ searchIndex.isReady = false;
502
+ for (const email of esCache.esCache.values()) addEmailToSearchIndex(email, searchIndex);
503
+ searchIndex.isReady = true;
504
+ return searchIndex;
505
+ } catch (error) {
506
+ throw new Error("Failed build an email search index from the cache", { cause: error });
507
+ }
527
508
  };
528
- var searchEmails = async (query, esCache, searchIndex, options = {}) => {
529
- try {
530
- if (!searchIndex.isReady || !query.trim()) {
531
- return [];
532
- }
533
- const {
534
- fields = ["subject", "body", "from", "to"],
535
- limit = 50,
536
- boost = { subject: 3, body: 1, from: 2, to: 2 }
537
- } = options;
538
- const results = /* @__PURE__ */ new Map();
539
- const searchPromises = fields.map(async (field) => {
540
- let fieldResults;
541
- switch (field) {
542
- case "subject":
543
- fieldResults = await searchIndex.subjectIndex.searchAsync(query);
544
- break;
545
- case "body":
546
- fieldResults = await searchIndex.bodyIndex.searchAsync(query);
547
- break;
548
- case "from":
549
- fieldResults = await searchIndex.fromIndex.searchAsync(query);
550
- break;
551
- case "to":
552
- fieldResults = await searchIndex.toIndex.searchAsync(query);
553
- break;
554
- default:
555
- return;
556
- }
557
- const fieldBoost = boost[field] || 1;
558
- fieldResults.forEach((emailId) => {
559
- const currentScore = results.get(String(emailId)) || 0;
560
- results.set(String(emailId), currentScore + fieldBoost);
561
- });
562
- });
563
- await Promise.all(searchPromises);
564
- const emailResults = [];
565
- for (const [emailId, score] of results) {
566
- const email = esCache.esCache.get(emailId);
567
- if (email) {
568
- emailResults.push({ email, score });
569
- }
570
- }
571
- emailResults.sort((a, b) => (b.score || 0) - (a.score || 0));
572
- return emailResults.slice(0, limit);
573
- } catch (error) {
574
- throw new Error("Email search failed", { cause: error });
575
- }
509
+ /**
510
+ * Searches in teh
511
+ *
512
+ * @param query - The string to search for
513
+ * @param esCache - The email cache
514
+ * @param searchIndex - The email search index
515
+ * @param opetions - The optional search limitations
516
+ * @returns The result of the email search (emails ans their corresponding result weights)
517
+ */
518
+ const searchEmails = async (query, esCache, searchIndex, options = {}) => {
519
+ try {
520
+ if (!searchIndex.isReady || !query.trim()) return [];
521
+ const { fields = [
522
+ "subject",
523
+ "body",
524
+ "from",
525
+ "to"
526
+ ], limit = 50, boost = {
527
+ subject: 3,
528
+ body: 1,
529
+ from: 2,
530
+ to: 2
531
+ } } = options;
532
+ const results = /* @__PURE__ */ new Map();
533
+ const searchPromises = fields.map(async (field) => {
534
+ let fieldResults;
535
+ switch (field) {
536
+ case "subject":
537
+ fieldResults = await searchIndex.subjectIndex.searchAsync(query);
538
+ break;
539
+ case "body":
540
+ fieldResults = await searchIndex.bodyIndex.searchAsync(query);
541
+ break;
542
+ case "from":
543
+ fieldResults = await searchIndex.fromIndex.searchAsync(query);
544
+ break;
545
+ case "to":
546
+ fieldResults = await searchIndex.toIndex.searchAsync(query);
547
+ break;
548
+ default: return;
549
+ }
550
+ const fieldBoost = boost[field] || 1;
551
+ fieldResults.forEach((emailId) => {
552
+ const currentScore = results.get(String(emailId)) || 0;
553
+ results.set(String(emailId), currentScore + fieldBoost);
554
+ });
555
+ });
556
+ await Promise.all(searchPromises);
557
+ const emailResults = [];
558
+ for (const [emailId, score] of results) {
559
+ const email = esCache.esCache.get(emailId);
560
+ if (email) emailResults.push({
561
+ email,
562
+ score
563
+ });
564
+ }
565
+ emailResults.sort((a, b) => (b.score || 0) - (a.score || 0));
566
+ return emailResults.slice(0, limit);
567
+ } catch (error) {
568
+ throw new Error("Email search failed", { cause: error });
569
+ }
576
570
  };
577
571
 
572
+ //#endregion
578
573
  export { addEmailToCache, addEmailToSearchIndex, addEmailsToCache, buildSearchIndexFromCache, closeDatabase, createCacheFromDB, deleteDatabase, deleteEmail, deleteEmailFromCache, deleteOldestEmails, deriveIndexKey, encryptAndStoreEmail, encryptAndStoreManyEmail, enforceMaxEmailNumber, getAllEmailsSortedNewestFirst, getAllEmailsSortedOldestFirst, getAndDecryptAllEmails, getAndDecryptEmail, getEmailBatch, getEmailCount, getEmailFromCache, openDatabase, removeEmailFromSearchIndex, searchEmails };
579
- //# sourceMappingURL=email-search.mjs.map
580
574
  //# sourceMappingURL=email-search.mjs.map