@vex-chat/libvex 6.3.0 → 6.3.1

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.
@@ -28,6 +28,13 @@ import type { Device, PreKeysSQL, SessionSQL } from "@vex-chat/types";
28
28
  *
29
29
  * This replaces three separate storage classes (Storage.ts, TauriStorage,
30
30
  * ExpoStorage) with a single implementation.
31
+ *
32
+ * **One database file today** holds both `sessions` (Double Ratchet /
33
+ * X3DH state — required to decrypt *new* traffic) and `messages` (history).
34
+ * If the file is lost or corrupted you lose both; restoring from backup
35
+ * re-seeds device keys but cannot reconstruct dropped ratchet chains from
36
+ * the server alone. A future split could park `sessions` + OTKs in a
37
+ * smaller “crypto state” store separate from bulk message history.
31
38
  */
32
39
  import {
33
40
  getCryptoProfile,
@@ -44,6 +51,7 @@ import {
44
51
  import { EventEmitter } from "eventemitter3";
45
52
  import { type Kysely, sql } from "kysely";
46
53
 
54
+ import { effectiveMessageRetentionHintDays } from "../retention.js";
47
55
  import { parseSkippedKeysStrict } from "../utils/ratchet.js";
48
56
 
49
57
  export class SqliteStorage extends EventEmitter implements Storage {
@@ -436,7 +444,9 @@ export class SqliteStorage extends EventEmitter implements Storage {
436
444
  const msPerDay = 86_400_000;
437
445
  const toDelete: string[] = [];
438
446
  for (const r of rows) {
439
- const hintDays = r.retentionHintDays ?? 30;
447
+ const hintDays = effectiveMessageRetentionHintDays(
448
+ r.retentionHintDays,
449
+ );
440
450
  const maxDays = Math.min(30, cap, hintDays);
441
451
  const ts = new Date(r.timestamp).getTime();
442
452
  if (!Number.isFinite(ts)) {
@@ -668,6 +678,14 @@ export class SqliteStorage extends EventEmitter implements Storage {
668
678
  ): Promise<Message[]> {
669
679
  const fips = getCryptoProfile() === "fips";
670
680
  const out: Message[] = [];
681
+ let processed = 0;
682
+ /** Yield so RN / web UIs can paint between at-rest decrypt blocks. */
683
+ const yieldToHost = (): Promise<void> =>
684
+ new Promise((resolve) => {
685
+ setTimeout(resolve, 0);
686
+ });
687
+ const yieldEvery = 28;
688
+
671
689
  for (const msg of messages) {
672
690
  const decryptedFlag = msg.decrypted !== 0;
673
691
  let plaintext = msg.message;
@@ -707,6 +725,11 @@ export class SqliteStorage extends EventEmitter implements Storage {
707
725
  rowMessage.retentionHintDays = msg.retentionHintDays;
708
726
  }
709
727
  out.push(rowMessage);
728
+
729
+ processed += 1;
730
+ if (processed % yieldEvery === 0) {
731
+ await yieldToHost();
732
+ }
710
733
  }
711
734
  return out;
712
735
  }