internxt-crypto 0.0.9-alpha → 0.0.11

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 (120) hide show
  1. package/README.md +3 -4
  2. package/dist/asymmetric-crypto-BORmLhnx.js +143 -0
  3. package/dist/asymmetric-crypto-BORmLhnx.js.map +1 -0
  4. package/dist/asymmetric-crypto-CyXsV4XT.mjs +102 -0
  5. package/dist/asymmetric-crypto-CyXsV4XT.mjs.map +1 -0
  6. package/dist/asymmetric-crypto.d.mts +47 -0
  7. package/dist/asymmetric-crypto.d.ts +47 -0
  8. package/dist/asymmetric-crypto.js +8 -0
  9. package/dist/asymmetric-crypto.mjs +3 -0
  10. package/dist/chunk-DWirmd9C.mjs +18 -0
  11. package/dist/chunk-Dt-PWiN7.js +60 -0
  12. package/dist/constants-Ccp21E03.js +208 -0
  13. package/dist/constants-Ccp21E03.js.map +1 -0
  14. package/dist/constants-kTeX-2T0.mjs +34 -0
  15. package/dist/constants-kTeX-2T0.mjs.map +1 -0
  16. package/dist/constants.d.mts +33 -0
  17. package/dist/constants.d.ts +33 -0
  18. package/dist/constants.js +31 -0
  19. package/dist/constants.mjs +3 -0
  20. package/dist/derive-key-Be7hS-cN.mjs +751 -0
  21. package/dist/derive-key-Be7hS-cN.mjs.map +1 -0
  22. package/dist/derive-key-CBf2WxJd.js +2513 -0
  23. package/dist/derive-key-CBf2WxJd.js.map +1 -0
  24. package/dist/derive-key.d.mts +97 -0
  25. package/dist/derive-key.d.ts +97 -0
  26. package/dist/derive-key.js +15 -0
  27. package/dist/derive-key.mjs +6 -0
  28. package/dist/email-crypto-BrT98taw.js +617 -0
  29. package/dist/email-crypto-BrT98taw.js.map +1 -0
  30. package/dist/email-crypto-DJUEjTxA.mjs +534 -0
  31. package/dist/email-crypto-DJUEjTxA.mjs.map +1 -0
  32. package/dist/email-crypto.d.mts +86 -0
  33. package/dist/email-crypto.d.ts +86 -0
  34. package/dist/email-crypto.js +17 -0
  35. package/dist/email-crypto.mjs +8 -0
  36. package/dist/email-search.d.mts +235 -0
  37. package/dist/email-search.d.ts +235 -0
  38. package/dist/email-search.js +637 -0
  39. package/dist/email-search.js.map +1 -0
  40. package/dist/email-search.mjs +608 -0
  41. package/dist/email-search.mjs.map +1 -0
  42. package/dist/hash-BoqwNkcd.js +190 -0
  43. package/dist/hash-BoqwNkcd.js.map +1 -0
  44. package/dist/hash-CXeGAwai.mjs +131 -0
  45. package/dist/hash-CXeGAwai.mjs.map +1 -0
  46. package/dist/hash.d.mts +65 -0
  47. package/dist/hash.d.ts +65 -0
  48. package/dist/hash.js +11 -0
  49. package/dist/hash.mjs +3 -0
  50. package/dist/index-CQqgKsbX.d.ts +50 -0
  51. package/dist/index-CintVUbp.d.ts +97 -0
  52. package/dist/index-D5pBU_A5.d.mts +50 -0
  53. package/dist/index-MaOov-ag.d.mts +97 -0
  54. package/dist/index.d.mts +52 -0
  55. package/dist/index.d.ts +52 -0
  56. package/dist/index.js +116 -2055
  57. package/dist/index.mjs +15 -8712
  58. package/dist/keystore-crypto-B4yCVo9l.js +182 -0
  59. package/dist/keystore-crypto-B4yCVo9l.js.map +1 -0
  60. package/dist/keystore-crypto-Bjgriq9h.mjs +159 -0
  61. package/dist/keystore-crypto-Bjgriq9h.mjs.map +1 -0
  62. package/dist/keystore-crypto.d.mts +40 -0
  63. package/dist/keystore-crypto.d.ts +40 -0
  64. package/dist/keystore-crypto.js +11 -0
  65. package/dist/keystore-crypto.mjs +9 -0
  66. package/dist/keystore-service.d.mts +48 -0
  67. package/dist/keystore-service.d.ts +48 -0
  68. package/dist/keystore-service.js +122 -0
  69. package/dist/keystore-service.js.map +1 -0
  70. package/dist/keystore-service.mjs +114 -0
  71. package/dist/keystore-service.mjs.map +1 -0
  72. package/dist/post-quantum-crypto-CAi-cEkV.js +189 -0
  73. package/dist/post-quantum-crypto-CAi-cEkV.js.map +1 -0
  74. package/dist/post-quantum-crypto-Vv34t6gX.mjs +154 -0
  75. package/dist/post-quantum-crypto-Vv34t6gX.mjs.map +1 -0
  76. package/dist/post-quantum-crypto.d.mts +2 -0
  77. package/dist/post-quantum-crypto.d.ts +2 -0
  78. package/dist/post-quantum-crypto.js +17 -0
  79. package/dist/post-quantum-crypto.mjs +3 -0
  80. package/dist/storage-service-BgIK2aYZ.js +82 -0
  81. package/dist/storage-service-BgIK2aYZ.js.map +1 -0
  82. package/dist/storage-service-CubCbhY2.mjs +65 -0
  83. package/dist/storage-service-CubCbhY2.mjs.map +1 -0
  84. package/dist/storage-service.d.mts +2 -0
  85. package/dist/storage-service.d.ts +2 -0
  86. package/dist/storage-service.js +14 -0
  87. package/dist/storage-service.mjs +3 -0
  88. package/dist/symmetric-crypto-CrdS1Che.mjs +197 -0
  89. package/dist/symmetric-crypto-CrdS1Che.mjs.map +1 -0
  90. package/dist/symmetric-crypto-D65zB396.js +244 -0
  91. package/dist/symmetric-crypto-D65zB396.js.map +1 -0
  92. package/dist/symmetric-crypto.d.mts +60 -0
  93. package/dist/symmetric-crypto.d.ts +60 -0
  94. package/dist/symmetric-crypto.js +10 -0
  95. package/dist/symmetric-crypto.mjs +4 -0
  96. package/dist/types-52g887Zi.js +16 -0
  97. package/dist/types-52g887Zi.js.map +1 -0
  98. package/dist/types-BiEoleqw.mjs +10 -0
  99. package/dist/types-BiEoleqw.mjs.map +1 -0
  100. package/dist/types-Ds3ivE9W.d.ts +104 -0
  101. package/dist/types-DwQJtrTx.d.mts +104 -0
  102. package/dist/types.d.mts +2 -0
  103. package/dist/types.d.ts +2 -0
  104. package/dist/types.js +3 -0
  105. package/dist/types.mjs +3 -0
  106. package/dist/utils-CNs3cyDj.js +263 -0
  107. package/dist/utils-CNs3cyDj.js.map +1 -0
  108. package/dist/utils-DS04iUcX.mjs +173 -0
  109. package/dist/utils-DS04iUcX.mjs.map +1 -0
  110. package/dist/utils.d.mts +99 -0
  111. package/dist/utils.d.ts +99 -0
  112. package/dist/utils.js +16 -0
  113. package/dist/utils.mjs +3 -0
  114. package/package.json +12 -11
  115. package/dist/__vite-browser-external-Dyvby5gX.js +0 -2
  116. package/dist/__vite-browser-external-Dyvby5gX.js.map +0 -1
  117. package/dist/__vite-browser-external-l0sNRNKZ.mjs +0 -2
  118. package/dist/__vite-browser-external-l0sNRNKZ.mjs.map +0 -1
  119. package/dist/index.js.map +0 -1
  120. package/dist/index.mjs.map +0 -1
@@ -0,0 +1,637 @@
1
+ const require_chunk = require('./chunk-Dt-PWiN7.js');
2
+ const require_constants = require('./constants-Ccp21E03.js');
3
+ require('./utils-CNs3cyDj.js');
4
+ require('./hash-BoqwNkcd.js');
5
+ require('./symmetric-crypto-D65zB396.js');
6
+ const require_derive_key = require('./derive-key-CBf2WxJd.js');
7
+ require('./post-quantum-crypto-CAi-cEkV.js');
8
+ const require_email_crypto = require('./email-crypto-BrT98taw.js');
9
+ let idb = require("idb");
10
+ let flexsearch = require("flexsearch");
11
+
12
+ //#region src/email-search/indexedDB.ts
13
+ /**
14
+ * Returns IndexedDB database name for the given user
15
+ *
16
+ * @param userID - The user ID
17
+ * @returns The database name
18
+ */
19
+ const getDatabaseName = (userID) => {
20
+ return `ES:${userID}:DB`;
21
+ };
22
+ /**
23
+ * Opens IndexedDB database for the given user
24
+ *
25
+ * @param userID - The user ID
26
+ * @returns The database
27
+ */
28
+ const openDatabase = async (userID) => {
29
+ try {
30
+ return (0, idb.openDB)(getDatabaseName(userID), require_constants.DB_VERSION, { upgrade(db) {
31
+ if (!db.objectStoreNames.contains(require_constants.DB_LABEL)) db.createObjectStore(require_constants.DB_LABEL, { keyPath: "id" }).createIndex("byTime", "params.createdAt");
32
+ } });
33
+ } catch (error) {
34
+ throw new Error(`Cannot open a database for the user ${userID}`, { cause: error });
35
+ }
36
+ };
37
+ /**
38
+ * Closes the IndexedDB database
39
+ *
40
+ * @param esDB - The database
41
+ */
42
+ const closeDatabase = (esDB) => {
43
+ return esDB.close();
44
+ };
45
+ /**
46
+ * Deletes IndexedDB database for the given user
47
+ *
48
+ * @param userID - The user ID
49
+ * @returns The database
50
+ */
51
+ const deleteDatabase = async (userID) => {
52
+ return (0, idb.deleteDB)(getDatabaseName(userID));
53
+ };
54
+ /**
55
+ * Derives database encryption key for the given user
56
+ *
57
+ * @param userID - The user ID
58
+ * @returns The symmetric CryptoKey for protecting database
59
+ */
60
+ const deriveIndexKey = async (baseKey) => {
61
+ return require_derive_key.deriveSymmetricCryptoKeyFromContext(require_constants.CONTEXT_INDEX, baseKey);
62
+ };
63
+ /**
64
+ * Encrypts the given email and stores it in the IndexedDB database
65
+ *
66
+ * @param newEmailToStore - The email for storing
67
+ * @param indexKey - The symmetric CryptoKey key for protecting database
68
+ * @param esDB - The database
69
+ */
70
+ const encryptAndStoreEmail = async (newEmailToStore, indexKey, esDB) => {
71
+ try {
72
+ const aux = require_email_crypto.getAux(newEmailToStore.params, false);
73
+ const encryptedEmail = {
74
+ enc: await require_email_crypto.encryptEmailContentSymmetricallyWithKey(newEmailToStore.body, indexKey, aux, newEmailToStore.id),
75
+ params: newEmailToStore.params,
76
+ id: newEmailToStore.id
77
+ };
78
+ await esDB.put(require_constants.DB_LABEL, encryptedEmail);
79
+ } catch (error) {
80
+ throw new Error("Cannot encrypt and add the given email to the database", { cause: error });
81
+ }
82
+ };
83
+ /**
84
+ * Encrypts the given set of emails and stores it in the IndexedDB database
85
+ *
86
+ * @param newEmailsToStore - The set of emails for storing
87
+ * @param indexKey - The symmetric CryptoKey key for protecting database
88
+ * @param esDB - The database
89
+ */
90
+ const encryptAndStoreManyEmail = async (newEmailsToStore, indexKey, esDB) => {
91
+ try {
92
+ const encryptedEmails = await Promise.all(newEmailsToStore.map(async (email) => {
93
+ const aux = require_email_crypto.getAux(email.params, false);
94
+ return {
95
+ enc: await require_email_crypto.encryptEmailContentSymmetricallyWithKey(email.body, indexKey, aux, email.id),
96
+ params: email.params,
97
+ id: email.id
98
+ };
99
+ }));
100
+ const tr = esDB.transaction(require_constants.DB_LABEL, "readwrite");
101
+ await Promise.all([...encryptedEmails.map((encEmail) => tr.store.put(encEmail)), tr.done]);
102
+ } catch (error) {
103
+ throw new Error("Cannot encrypt and add emails to the database", { cause: error });
104
+ }
105
+ };
106
+ /**
107
+ * Decrypts the given email
108
+ *
109
+ * @param indexKey - The symmetric CryptoKey key for protecting database
110
+ * @param encryptedEmail - The encrypted email
111
+ * @returns The decrypted email
112
+ */
113
+ const decryptEmail = async (indexKey, encryptedEmail) => {
114
+ try {
115
+ return {
116
+ body: await require_email_crypto.decryptEmailSymmetrically(indexKey, require_email_crypto.getAux(encryptedEmail.params, false), encryptedEmail.enc),
117
+ params: encryptedEmail.params,
118
+ id: encryptedEmail.id
119
+ };
120
+ } catch (error) {
121
+ throw new Error("Cannot decrypt the given email", { cause: error });
122
+ }
123
+ };
124
+ /**
125
+ * Fetches the email from the database and decrypts it
126
+ *
127
+ * @param emailID - The email identifier
128
+ * @param indexKey - The symmetric CryptoKey key for protecting database
129
+ * @param encryptedEmail - The encrypted email
130
+ * @returns The decrypted email
131
+ */
132
+ const getAndDecryptEmail = async (emailID, indexKey, esDB) => {
133
+ try {
134
+ const encryptedEmail = await esDB.get(require_constants.DB_LABEL, emailID);
135
+ if (!encryptedEmail) throw new Error(`DB cannot find email with id ${emailID}`);
136
+ return decryptEmail(indexKey, encryptedEmail);
137
+ } catch (error) {
138
+ throw new Error(`Cannot fetch the email ${emailID} from the database`, { cause: error });
139
+ }
140
+ };
141
+ /**
142
+ * Fetches all email from the database and decrypts them
143
+ *
144
+ * @param indexKey - The symmetric CryptoKey key for protecting database
145
+ * @param esDB - The database
146
+ * @returns The decrypted emails
147
+ */
148
+ const getAndDecryptAllEmails = async (indexKey, esDB) => {
149
+ try {
150
+ const encryptedEmails = await esDB.getAll(require_constants.DB_LABEL);
151
+ return (await Promise.all(encryptedEmails.map(async (encEmail) => {
152
+ return {
153
+ body: await require_email_crypto.decryptEmailSymmetrically(indexKey, require_email_crypto.getAux(encEmail.params, false), encEmail.enc),
154
+ params: encEmail.params,
155
+ id: encEmail.id
156
+ };
157
+ }))).filter((email) => email !== null);
158
+ } catch (error) {
159
+ throw new Error("Cannot fetch and decrypt all emails from the database", { cause: error });
160
+ }
161
+ };
162
+ /**
163
+ * Deletes the email from the database
164
+ *
165
+ * @param emailID - The email identifier
166
+ * @param esDB - The database
167
+ */
168
+ const deleteEmail = async (emailID, esDB) => {
169
+ await esDB.delete(require_constants.DB_LABEL, emailID);
170
+ };
171
+ /**
172
+ * Returns the number of stored email
173
+ *
174
+ * @param esDB - The database
175
+ * @returns The number of stored emails
176
+ */
177
+ const getEmailCount = async (esDB) => {
178
+ return await esDB.count(require_constants.DB_LABEL);
179
+ };
180
+ /**
181
+ * Removes the given number of oldests emails from the database
182
+ *
183
+ * @param emailsToDelete - The number of emails to delete
184
+ * @param esDB - The database
185
+ */
186
+ const deleteOldestEmails = async (emailsToDelete, esDB) => {
187
+ try {
188
+ const tx = esDB.transaction(require_constants.DB_LABEL, "readwrite");
189
+ let cursor = await tx.store.index("byTime").openCursor();
190
+ let deletedCount = 0;
191
+ while (cursor && deletedCount < emailsToDelete) {
192
+ await cursor.delete();
193
+ deletedCount++;
194
+ cursor = await cursor.continue();
195
+ }
196
+ await tx.done;
197
+ } catch (error) {
198
+ throw new Error(`Cannot delete ${emailsToDelete} oldests emails from the database`, { cause: error });
199
+ }
200
+ };
201
+ /**
202
+ * Enforces the maximum email number in the database
203
+ *
204
+ * @param esDB - The database
205
+ * @param max - The maximum allowed number of emails
206
+ */
207
+ const enforceMaxEmailNumber = async (esDB, max) => {
208
+ try {
209
+ const currentCount = await getEmailCount(esDB);
210
+ if (currentCount <= max) return;
211
+ await deleteOldestEmails(currentCount - max, esDB);
212
+ } catch (error) {
213
+ throw new Error(`Cannot enforce the maximum of ${max} emails on the database`, { cause: error });
214
+ }
215
+ };
216
+ /**
217
+ * Fetches all emails from the database, decrypts them and sortes the results in the specified order
218
+ *
219
+ * @param esDB - The database
220
+ * @param indexKey - The symmetric CryptoKey key for protecting database
221
+ * @param direction - The order of sorting. If 'next' - oldest first, if 'prev' - newest first
222
+ * @returns Decryped emails in the specified order
223
+ */
224
+ const fetchEmails = async (esDB, indexKey, direction) => {
225
+ try {
226
+ const index = esDB.transaction(require_constants.DB_LABEL, "readonly").store.index("byTime");
227
+ const encryptedEmails = [];
228
+ let cursor = await index.openCursor(null, direction);
229
+ while (cursor) {
230
+ encryptedEmails.push(cursor.value);
231
+ cursor = await cursor.continue();
232
+ }
233
+ return await Promise.all(encryptedEmails.map((encryptedEmail) => decryptEmail(indexKey, encryptedEmail)));
234
+ } catch (error) {
235
+ throw new Error("Cannot fetch emails from database", { cause: error });
236
+ }
237
+ };
238
+ /**
239
+ * Fetches all emails from the database, decrypts them and sortes the results based on the creation time (newest first)
240
+ *
241
+ * @param esDB - The database
242
+ * @param indexKey - The symmetric CryptoKey key for protecting database
243
+ * @returns The number of stored emails
244
+ */
245
+ const getAllEmailsSortedNewestFirst = async (esDB, indexKey) => {
246
+ return fetchEmails(esDB, indexKey, "prev");
247
+ };
248
+ /**
249
+ * Fetches all emails from the database, decrypts them and sortes the results based on the creation time (oldest first)
250
+ *
251
+ * @param esDB - The database
252
+ * @param indexKey - The symmetric CryptoKey key for protecting database
253
+ * @returns The number of stored emails
254
+ */
255
+ const getAllEmailsSortedOldestFirst = async (esDB, indexKey) => {
256
+ return fetchEmails(esDB, indexKey, "next");
257
+ };
258
+ /**
259
+ * Fetches a batch of emails from the database, decrypts them and sortes the results based on the creation time (newest first)
260
+ *
261
+ * @param esDB - The database
262
+ * @param indexKey - The symmetric CryptoKey key for protecting database
263
+ * @param batchSize - The size of the batch
264
+ * @param startCursor - The starting point (optional). If not given, starts from the beginning
265
+ * @returns The number of stored emails
266
+ */
267
+ const getEmailBatch = async (esDB, indexKey, batchSize, startCursor) => {
268
+ try {
269
+ const index = esDB.transaction(require_constants.DB_LABEL, "readonly").store.index("byTime");
270
+ const encryptedEmails = [];
271
+ let cursor;
272
+ if (startCursor) {
273
+ const range = IDBKeyRange.upperBound(startCursor, true);
274
+ cursor = await index.openCursor(range, "prev");
275
+ } else cursor = await index.openCursor(null, "prev");
276
+ let count = 0;
277
+ let nextCursor;
278
+ while (cursor && count < batchSize) {
279
+ encryptedEmails.push(cursor.value);
280
+ nextCursor = cursor.key;
281
+ count++;
282
+ cursor = await cursor.continue();
283
+ }
284
+ return {
285
+ emails: await Promise.all(encryptedEmails.map((encryptedEmail) => decryptEmail(indexKey, encryptedEmail))),
286
+ nextCursor: count === batchSize ? nextCursor : void 0
287
+ };
288
+ } catch (error) {
289
+ throw new Error(`Cannot fetch email batch of ${batchSize} from the database`, { cause: error });
290
+ }
291
+ };
292
+
293
+ //#endregion
294
+ //#region src/email-search/mailCache.ts
295
+ /**
296
+ * Estimates the email size in the memory
297
+ *
298
+ * @param email - The email
299
+ * @returns The estimation of the email size
300
+ */
301
+ function sizeOfEmail(email) {
302
+ return require_email_crypto.emailToBinary(email).byteLength;
303
+ }
304
+ /**
305
+ * Creates an empty cache variable
306
+ *
307
+ * @returns The empty cache
308
+ */
309
+ function createEmptyCache() {
310
+ return {
311
+ esCache: /* @__PURE__ */ new Map(),
312
+ cacheSize: 0,
313
+ isCacheLimited: false,
314
+ isCacheReady: true
315
+ };
316
+ }
317
+ /**
318
+ * Fetches all emails from the database in batches and cahces them
319
+ *
320
+ * @param indexKey - The symmetric CryptoKey key for protecting database
321
+ * @param esCache - The cache to add emails too
322
+ * @param esDB - The database
323
+ */
324
+ const createCacheFromDB = async (indexKey, esDB) => {
325
+ const esCache = createEmptyCache();
326
+ esCache.isCacheReady = false;
327
+ try {
328
+ const count = await getEmailCount(esDB);
329
+ if (!count) {
330
+ esCache.isCacheReady = true;
331
+ return esCache;
332
+ }
333
+ if (count <= require_constants.MAX_EMAIL_PER_BATCH) addEmailsToCache(await getAllEmailsSortedNewestFirst(esDB, indexKey), esCache);
334
+ else {
335
+ let nextCursor = void 0;
336
+ let cacheFull = false;
337
+ while (!cacheFull) {
338
+ const { emails, nextCursor: newCursor } = await getEmailBatch(esDB, indexKey, require_constants.MAX_EMAIL_PER_BATCH, nextCursor);
339
+ if (!newCursor || !emails.length) break;
340
+ nextCursor = newCursor;
341
+ if (!addEmailsToCache(emails, esCache)) cacheFull = true;
342
+ }
343
+ }
344
+ return esCache;
345
+ } catch (error) {
346
+ throw new Error(`Email caching failed: ${error}`);
347
+ }
348
+ };
349
+ /**
350
+ * Gets an email from the cache
351
+ *
352
+ * @param emailID - The email identifier
353
+ * @param esCache - The email cache
354
+ * @returns The found email or throws an error
355
+ */
356
+ const getEmailFromCache = async (emailID, esCache) => {
357
+ const email = esCache.esCache.get(emailID);
358
+ if (!email) throw new Error(`Email not found in cache for ID: ${emailID}`);
359
+ return email;
360
+ };
361
+ /**
362
+ * Removes the email from cache
363
+ *
364
+ * @param emailID - The email identifier
365
+ * @param esCache - The email cache
366
+ */
367
+ const deleteEmailFromCache = async (emailID, esCache) => {
368
+ try {
369
+ const size = sizeOfEmail(await getEmailFromCache(emailID, esCache));
370
+ if (esCache.esCache.delete(emailID)) esCache.cacheSize -= size;
371
+ } catch (error) {
372
+ throw new Error(`Failed to delete email with ID ${emailID}`, { cause: error });
373
+ }
374
+ };
375
+ /**
376
+ * Adds emails to the cache
377
+ *
378
+ * @param emails - The emails to add
379
+ * @param esCache - The email cache
380
+ * @returns TRUE if all emails were added sucessfully, or FALSE and error reason.
381
+ */
382
+ function addEmailsToCache(emails, esCache) {
383
+ try {
384
+ for (const email of emails) {
385
+ const result = addEmailToCache(email, esCache);
386
+ if (!result.success) return result;
387
+ }
388
+ return { success: true };
389
+ } catch (error) {
390
+ throw new Error("Failed to add emails to the cache", { cause: error });
391
+ }
392
+ }
393
+ /**
394
+ * Adds email to the cache
395
+ *
396
+ * @param email - The email to add
397
+ * @param esCache - The email cache
398
+ * @returns TRUE if the email was added sucessfully, or FALSE and error reason.
399
+ */
400
+ const addEmailToCache = (email, esCache) => {
401
+ try {
402
+ if (esCache.esCache.has(email.id)) return {
403
+ success: false,
404
+ reason: "email already exists in cache"
405
+ };
406
+ const emailSize = sizeOfEmail(email);
407
+ if (esCache.cacheSize + emailSize > require_constants.MAX_CACHE_SIZE) {
408
+ esCache.isCacheLimited = true;
409
+ return {
410
+ success: false,
411
+ reason: "hit cache limit"
412
+ };
413
+ }
414
+ esCache.esCache.set(email.id, email);
415
+ esCache.cacheSize += emailSize;
416
+ return { success: true };
417
+ } catch (error) {
418
+ throw new Error("Failed to add email to the cache", { cause: error });
419
+ }
420
+ };
421
+
422
+ //#endregion
423
+ //#region src/email-search/search.ts
424
+ const SUBJECT_OPTIONS = {
425
+ preset: "match",
426
+ tokenize: "forward",
427
+ resolution: 9,
428
+ minlength: 2,
429
+ optimize: true,
430
+ fastupdate: true,
431
+ cache: true
432
+ };
433
+ const BODY_OPTIONS = {
434
+ ...SUBJECT_OPTIONS,
435
+ minlength: 3,
436
+ resolution: 6
437
+ };
438
+ const FROM_OPTIONS = {
439
+ ...SUBJECT_OPTIONS,
440
+ tokenize: "strict",
441
+ minlength: 1
442
+ };
443
+ const TO_OPTIONS = {
444
+ ...SUBJECT_OPTIONS,
445
+ tokenize: "strict",
446
+ minlength: 1
447
+ };
448
+ /**
449
+ * Creates new email search index
450
+ *
451
+ * @returns The email search index
452
+ */
453
+ const createSearchIndex = () => ({
454
+ subjectIndex: new flexsearch.Index(SUBJECT_OPTIONS),
455
+ bodyIndex: new flexsearch.Index(BODY_OPTIONS),
456
+ fromIndex: new flexsearch.Index(FROM_OPTIONS),
457
+ toIndex: new flexsearch.Index(TO_OPTIONS),
458
+ isReady: false
459
+ });
460
+ /**
461
+ * Adds the given email to the email search index
462
+ *
463
+ * @param email - The email to add
464
+ * @param searchIndex - The email search index
465
+ */
466
+ const addEmailToSearchIndex = (email, searchIndex) => {
467
+ try {
468
+ const emailId = email.id;
469
+ if (email.params.subject) searchIndex.subjectIndex.add(emailId, email.params.subject);
470
+ if (email.body?.text) searchIndex.bodyIndex.add(emailId, email.body.text);
471
+ if (email.params.sender) {
472
+ const senderText = `${email.params.sender.name || ""} ${email.params.sender.email || ""}`.trim();
473
+ searchIndex.fromIndex.add(emailId, senderText);
474
+ }
475
+ const recipientsText = (email.params.recipients?.length ? email.params.recipients : [email.params.recipient]).map((recipient) => `${recipient.name || ""} ${recipient.email || ""}`.trim()).join(" ");
476
+ searchIndex.toIndex.add(emailId, recipientsText);
477
+ } catch (error) {
478
+ throw new Error("Failed to add email to the search index", { cause: error });
479
+ }
480
+ };
481
+ /**
482
+ * Removes the email from the email search index
483
+ *
484
+ * @param emailID - The email identifier
485
+ * @param searchIndex - The email search index
486
+ */
487
+ const removeEmailFromSearchIndex = (emailID, searchIndex) => {
488
+ try {
489
+ searchIndex.subjectIndex.remove(emailID);
490
+ searchIndex.bodyIndex.remove(emailID);
491
+ searchIndex.fromIndex.remove(emailID);
492
+ searchIndex.toIndex.remove(emailID);
493
+ } catch (error) {
494
+ throw new Error(`Failed to remove email with ID ${emailID} from the search index`, { cause: error });
495
+ }
496
+ };
497
+ /**
498
+ * Buils the email search index from the email cache
499
+ *
500
+ * @param esCache - The email cache
501
+ * @returns The email search index
502
+ */
503
+ const buildSearchIndexFromCache = async (esCache) => {
504
+ try {
505
+ const searchIndex = createSearchIndex();
506
+ searchIndex.isReady = false;
507
+ for (const email of esCache.esCache.values()) addEmailToSearchIndex(email, searchIndex);
508
+ searchIndex.isReady = true;
509
+ return searchIndex;
510
+ } catch (error) {
511
+ throw new Error("Failed build an email search index from the cache", { cause: error });
512
+ }
513
+ };
514
+ /**
515
+ * Searches in teh
516
+ *
517
+ * @param query - The string to search for
518
+ * @param esCache - The email cache
519
+ * @param searchIndex - The email search index
520
+ * @param opetions - The optional search limitations
521
+ * @returns The result of the email search (emails ans their corresponding result weights)
522
+ */
523
+ const searchEmails = async (query, esCache, searchIndex, options = {}) => {
524
+ try {
525
+ if (!searchIndex.isReady || !query.trim()) return [];
526
+ const { fields = [
527
+ "subject",
528
+ "body",
529
+ "from",
530
+ "to"
531
+ ], limit = 50, boost = {
532
+ subject: 3,
533
+ body: 1,
534
+ from: 2,
535
+ to: 2
536
+ } } = options;
537
+ const results = /* @__PURE__ */ new Map();
538
+ const searchPromises = fields.map(async (field) => {
539
+ let fieldResults;
540
+ switch (field) {
541
+ case "subject":
542
+ fieldResults = await searchIndex.subjectIndex.searchAsync(query);
543
+ break;
544
+ case "body":
545
+ fieldResults = await searchIndex.bodyIndex.searchAsync(query);
546
+ break;
547
+ case "from":
548
+ fieldResults = await searchIndex.fromIndex.searchAsync(query);
549
+ break;
550
+ case "to":
551
+ fieldResults = await searchIndex.toIndex.searchAsync(query);
552
+ break;
553
+ default: return;
554
+ }
555
+ const fieldBoost = boost[field] || 1;
556
+ fieldResults.forEach((emailId) => {
557
+ const currentScore = results.get(String(emailId)) || 0;
558
+ results.set(String(emailId), currentScore + fieldBoost);
559
+ });
560
+ });
561
+ await Promise.all(searchPromises);
562
+ const emailResults = [];
563
+ for (const [emailId, score] of results) {
564
+ const email = esCache.esCache.get(emailId);
565
+ if (email) emailResults.push({
566
+ email,
567
+ score
568
+ });
569
+ }
570
+ emailResults.sort((a, b) => (b.score || 0) - (a.score || 0));
571
+ return emailResults.slice(0, limit);
572
+ } catch (error) {
573
+ throw new Error("Email search failed", { cause: error });
574
+ }
575
+ };
576
+
577
+ //#endregion
578
+ //#region src/email-search/index.ts
579
+ var email_search_exports = /* @__PURE__ */ require_chunk.__exportAll({
580
+ addEmailToCache: () => addEmailToCache,
581
+ addEmailToSearchIndex: () => addEmailToSearchIndex,
582
+ addEmailsToCache: () => addEmailsToCache,
583
+ buildSearchIndexFromCache: () => buildSearchIndexFromCache,
584
+ closeDatabase: () => closeDatabase,
585
+ createCacheFromDB: () => createCacheFromDB,
586
+ deleteDatabase: () => deleteDatabase,
587
+ deleteEmail: () => deleteEmail,
588
+ deleteEmailFromCache: () => deleteEmailFromCache,
589
+ deleteOldestEmails: () => deleteOldestEmails,
590
+ deriveIndexKey: () => deriveIndexKey,
591
+ encryptAndStoreEmail: () => encryptAndStoreEmail,
592
+ encryptAndStoreManyEmail: () => encryptAndStoreManyEmail,
593
+ enforceMaxEmailNumber: () => enforceMaxEmailNumber,
594
+ getAllEmailsSortedNewestFirst: () => getAllEmailsSortedNewestFirst,
595
+ getAllEmailsSortedOldestFirst: () => getAllEmailsSortedOldestFirst,
596
+ getAndDecryptAllEmails: () => getAndDecryptAllEmails,
597
+ getAndDecryptEmail: () => getAndDecryptEmail,
598
+ getEmailBatch: () => getEmailBatch,
599
+ getEmailCount: () => getEmailCount,
600
+ getEmailFromCache: () => getEmailFromCache,
601
+ openDatabase: () => openDatabase,
602
+ removeEmailFromSearchIndex: () => removeEmailFromSearchIndex,
603
+ searchEmails: () => searchEmails
604
+ });
605
+
606
+ //#endregion
607
+ exports.addEmailToCache = addEmailToCache;
608
+ exports.addEmailToSearchIndex = addEmailToSearchIndex;
609
+ exports.addEmailsToCache = addEmailsToCache;
610
+ exports.buildSearchIndexFromCache = buildSearchIndexFromCache;
611
+ exports.closeDatabase = closeDatabase;
612
+ exports.createCacheFromDB = createCacheFromDB;
613
+ exports.deleteDatabase = deleteDatabase;
614
+ exports.deleteEmail = deleteEmail;
615
+ exports.deleteEmailFromCache = deleteEmailFromCache;
616
+ exports.deleteOldestEmails = deleteOldestEmails;
617
+ exports.deriveIndexKey = deriveIndexKey;
618
+ Object.defineProperty(exports, 'email_search_exports', {
619
+ enumerable: true,
620
+ get: function () {
621
+ return email_search_exports;
622
+ }
623
+ });
624
+ exports.encryptAndStoreEmail = encryptAndStoreEmail;
625
+ exports.encryptAndStoreManyEmail = encryptAndStoreManyEmail;
626
+ exports.enforceMaxEmailNumber = enforceMaxEmailNumber;
627
+ exports.getAllEmailsSortedNewestFirst = getAllEmailsSortedNewestFirst;
628
+ exports.getAllEmailsSortedOldestFirst = getAllEmailsSortedOldestFirst;
629
+ exports.getAndDecryptAllEmails = getAndDecryptAllEmails;
630
+ exports.getAndDecryptEmail = getAndDecryptEmail;
631
+ exports.getEmailBatch = getEmailBatch;
632
+ exports.getEmailCount = getEmailCount;
633
+ exports.getEmailFromCache = getEmailFromCache;
634
+ exports.openDatabase = openDatabase;
635
+ exports.removeEmailFromSearchIndex = removeEmailFromSearchIndex;
636
+ exports.searchEmails = searchEmails;
637
+ //# sourceMappingURL=email-search.js.map