@fileverse-dev/dsheet 4.1.21 → 4.1.22

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.
@@ -44376,7 +44376,14 @@ class iv {
44376
44376
  Ye(this, "encryptMirror", null);
44377
44377
  Ye(this, "fileKeyEpoch", 0);
44378
44378
  Ye(this, "mirrorIdleTimer", null);
44379
+ // Latched by rekey(): a room rotation means the host's fileKey may have rotated too, and a
44380
+ // mirror under the old key would be readable by a removed member through the open mirror
44381
+ // GET. Never cleared on this instance — a page reload recovers the current key.
44382
+ Ye(this, "mirrorDisabled", !1);
44379
44383
  Ye(this, "MIRROR_IDLE_MS", 4e3);
44384
+ // Headroom under the server's 10 MB Socket.IO maxHttpBufferSize: an oversized emit drops
44385
+ // the socket. Matches the ddoc engine's MAX_WIRE_UPDATE_CHARS.
44386
+ Ye(this, "MAX_MIRROR_CHARS", 9e6);
44380
44387
  Ye(this, "isOwner", !1);
44381
44388
  Ye(this, "joinOnly", !1);
44382
44389
  Ye(this, "updateQueue", []);
@@ -44465,7 +44472,7 @@ class iv {
44465
44472
  async connect(t) {
44466
44473
  var n, i, o;
44467
44474
  if (this._status !== "idle") return;
44468
- this.roomKey = t.roomKey, this.roomKeyBytes = Wl(t.roomKey), this.isOwner = t.isOwner, this.joinOnly = t.joinOnly ?? !1, this.encryptMirror = t.encryptMirror ?? null, this.fileKeyEpoch = t.fileKeyEpoch ?? 0, this.socketClient = new Mm({
44475
+ this.roomKey = t.roomKey, this.roomKeyBytes = Wl(t.roomKey), this.isOwner = t.isOwner, this.joinOnly = t.joinOnly ?? !1, this.encryptMirror = this.mirrorDisabled ? null : t.encryptMirror ?? null, this.fileKeyEpoch = t.fileKeyEpoch ?? 0, this.socketClient = new Mm({
44469
44476
  wsUrl: t.wsUrl,
44470
44477
  roomKey: t.roomKey,
44471
44478
  roomId: t.roomId,
@@ -44568,7 +44575,7 @@ class iv {
44568
44575
  var o, c;
44569
44576
  if (this.rotating || this._status !== "ready" && this._status !== "syncing" && this._status !== "connecting" && this._status !== "reconnecting")
44570
44577
  return;
44571
- this.rotating = !0;
44578
+ this.rotating = !0, this.mirrorDisabled = !0, this.encryptMirror = null, this.mirrorIdleTimer && (clearTimeout(this.mirrorIdleTimer), this.mirrorIdleTimer = null);
44572
44579
  const i = this.roomKey;
44573
44580
  this.roomKeyBytesPrev = this.roomKeyBytes, this.roomKey = t, this.roomKeyBytes = Wl(t);
44574
44581
  try {
@@ -44797,7 +44804,7 @@ class iv {
44797
44804
  // editing-idle debounce (trailing) — active editing keeps resetting the timer, so exactly
44798
44805
  // one write lands once typing pauses. Best-effort; NOT owner-gated (unlike authorSnapshot).
44799
44806
  scheduleMirror() {
44800
- this.encryptMirror && (this.mirrorIdleTimer && clearTimeout(this.mirrorIdleTimer), this.mirrorIdleTimer = setTimeout(() => {
44807
+ this.mirrorDisabled || !this.encryptMirror || (this.mirrorIdleTimer && clearTimeout(this.mirrorIdleTimer), this.mirrorIdleTimer = setTimeout(() => {
44801
44808
  this.authorMirror().catch(
44802
44809
  (t) => console.error("SyncManager: mirror authoring failed", t)
44803
44810
  );
@@ -44805,12 +44812,20 @@ class iv {
44805
44812
  }
44806
44813
  async authorMirror() {
44807
44814
  var l;
44808
- if (!this.encryptMirror || !this.isConnected) return;
44815
+ if (this.mirrorDisabled || !this.encryptMirror || !this.isConnected) return;
44809
44816
  const t = await this.encryptMirror(Ne.encodeStateAsUpdate(this.ydoc));
44810
- await ((l = this.socketClient) == null ? void 0 : l.sendMirrorSnapshot({
44811
- data: t,
44812
- fileKeyEpoch: this.fileKeyEpoch
44813
- }));
44817
+ if (!(t === null || this.mirrorDisabled)) {
44818
+ if (t.length > this.MAX_MIRROR_CHARS) {
44819
+ console.error(
44820
+ `SyncManager: mirror skipped, ${t.length} chars exceeds ${this.MAX_MIRROR_CHARS}`
44821
+ );
44822
+ return;
44823
+ }
44824
+ await ((l = this.socketClient) == null ? void 0 : l.sendMirrorSnapshot({
44825
+ data: t,
44826
+ fileKeyEpoch: this.fileKeyEpoch
44827
+ }));
44828
+ }
44814
44829
  }
44815
44830
  // The final merged delta for a hard tab-close beacon: any queued-but-unsent updates,
44816
44831
  // merged and encrypted. Returns null when there is nothing pending.
@@ -44824,6 +44839,14 @@ class iv {
44824
44839
  const t = this.buildPendingBeaconPayload();
44825
44840
  t && ((l = this.socketClient) == null || l.flushBeacon(t));
44826
44841
  }
44842
+ // Tab hidden / app backgrounded: write the debounced mirror now, while the socket is still
44843
+ // up — forceCleanup would otherwise clear the timer and drop the last ~4s of edits. Best
44844
+ // effort on an outright close (the write is async and the page may die first).
44845
+ flushPendingMirror() {
44846
+ this.mirrorDisabled || !this.mirrorIdleTimer || (clearTimeout(this.mirrorIdleTimer), this.mirrorIdleTimer = null, this.authorMirror().catch(
44847
+ (t) => console.error("SyncManager: mirror flush failed", t)
44848
+ ));
44849
+ }
44827
44850
  forceCleanup() {
44828
44851
  var l;
44829
44852
  this.flushTimer && (clearTimeout(this.flushTimer), this.flushTimer = null), this.mirrorIdleTimer && (clearTimeout(this.mirrorIdleTimer), this.mirrorIdleTimer = null), this.fireBeacon(), this.updateQueue = [], this._awareness && ci(this._awareness, [this.ydoc.clientID], "cleanup"), this.cleanupAwareness(), (l = this.socketClient) == null || l.disconnect(), this.resetInternalState(), this._status = "idle", this._context = { ...Qn };
@@ -45333,6 +45356,16 @@ const ov = { status: "idle" }, sv = (e) => {
45333
45356
  return typeof window < "u" && typeof window.addEventListener == "function" && window.addEventListener("pagehide", I), () => {
45334
45357
  typeof window < "u" && typeof window.removeEventListener == "function" && window.removeEventListener("pagehide", I);
45335
45358
  };
45359
+ }, []), Se(() => {
45360
+ if (typeof document > "u" || typeof document.addEventListener != "function")
45361
+ return;
45362
+ const I = () => {
45363
+ var g;
45364
+ document.visibilityState === "hidden" && ((g = n.current) == null || g.flushPendingMirror());
45365
+ };
45366
+ return document.addEventListener("visibilitychange", I), () => {
45367
+ document.removeEventListener("visibilitychange", I);
45368
+ };
45336
45369
  }, []);
45337
45370
  const r = We(
45338
45371
  (I) => {
@@ -50765,10 +50798,10 @@ const i7 = ({
50765
50798
  }, V.readAsText(b);
50766
50799
  });
50767
50800
  }, wZ = async (e, t, l, n) => {
50768
- const { handleExportToXLSX: i } = await import("./xlsx-export-impl-8QvOUcjc.js");
50801
+ const { handleExportToXLSX: i } = await import("./xlsx-export-impl-DXyQpmMi.js");
50769
50802
  return i(e, t, l, n);
50770
50803
  }, LZ = async (e, t, l, n) => {
50771
- const { handleExportToODS: i } = await import("./xlsx-export-impl-8QvOUcjc.js");
50804
+ const { handleExportToODS: i } = await import("./xlsx-export-impl-DXyQpmMi.js");
50772
50805
  return i(e, t, l, n);
50773
50806
  }, Td = (e) => {
50774
50807
  Jh({
@@ -50859,7 +50892,7 @@ const i7 = ({
50859
50892
  }) => {
50860
50893
  const [s, r] = Xe(!1), u = We(
50861
50894
  async (h, m, b) => {
50862
- const { runXlsxFileUpload: Z } = await import("./use-xlsx-import-impl-Bzyh3J-h.js");
50895
+ const { runXlsxFileUpload: Z } = await import("./use-xlsx-import-impl-xphBNZu3.js");
50863
50896
  return Z(
50864
50897
  {
50865
50898
  sheetEditorRef: e,
@@ -50890,7 +50923,7 @@ const i7 = ({
50890
50923
  ), d = We(
50891
50924
  async (h, m, b) => {
50892
50925
  var y;
50893
- const { convertOdsFileToXlsxFile: Z } = await import("./ods-to-xlsx-DeJAYBkD.js"), { runXlsxFileUpload: I } = await import("./use-xlsx-import-impl-Bzyh3J-h.js"), g = h == null ? void 0 : h.target, V = ((y = g == null ? void 0 : g.files) == null ? void 0 : y[0]) || m;
50926
+ const { convertOdsFileToXlsxFile: Z } = await import("./ods-to-xlsx-DeJAYBkD.js"), { runXlsxFileUpload: I } = await import("./use-xlsx-import-impl-xphBNZu3.js"), g = h == null ? void 0 : h.target, V = ((y = g == null ? void 0 : g.files) == null ? void 0 : y[0]) || m;
50894
50927
  if (!V) return;
50895
50928
  const f = await Z(V);
50896
50929
  return I(
@@ -56566,7 +56599,7 @@ async function sz(e, t) {
56566
56599
  const { convertOdsFileToXlsxFile: b } = await import("./ods-to-xlsx-DeJAYBkD.js");
56567
56600
  h = await b(e);
56568
56601
  }
56569
- const { runXlsxFileUpload: m } = await import("./use-xlsx-import-impl-Bzyh3J-h.js");
56602
+ const { runXlsxFileUpload: m } = await import("./use-xlsx-import-impl-xphBNZu3.js");
56570
56603
  await m(
56571
56604
  {
56572
56605
  sheetEditorRef: c,
package/dist/index.es.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C as s, d as o, f as t, S as r, g as l, h as n, j as d, T as S, k as c, l as i, n as m, o as h, p, q as C, t as u, u as E, v as F, w as g, x, z as R, A, B as f, D as I, E as L, F as T, G as w, H as y, I as v, J as D, K as M, L as b, M as k, N as z, O, P } from "./index-BZbTaVjU.js";
1
+ import { C as s, d as o, f as t, S as r, g as l, h as n, j as d, T as S, k as c, l as i, n as m, o as h, p, q as C, t as u, u as E, v as F, w as g, x, z as R, A, B as f, D as I, E as L, F as T, G as w, H as y, I as v, J as D, K as M, L as b, M as k, N as z, O, P } from "./index-DhQTrCQd.js";
2
2
  import { cy as G, cz as K, cA as U, cG as X, bs as _, e as j, f as B, l as H, a as J, dj as N, dk as q, bb as Y, dl as Z, dm as Q, dr as W, ds as $, du as ee, I as ae, dJ as se, eg as oe, b4 as te } from "./executeStringFunction-CQ922vEp.js";
3
3
  import { FLVURL as le } from "@fileverse-dev/formulajs";
4
4
  import { E as de, S as Se } from "./constants-8Ij49Lxv.js";
@@ -18,7 +18,9 @@ export declare class SyncManager {
18
18
  private encryptMirror;
19
19
  private fileKeyEpoch;
20
20
  private mirrorIdleTimer;
21
+ private mirrorDisabled;
21
22
  private readonly MIRROR_IDLE_MS;
23
+ private readonly MAX_MIRROR_CHARS;
22
24
  private isOwner;
23
25
  private joinOnly;
24
26
  private updateQueue;
@@ -90,6 +92,7 @@ export declare class SyncManager {
90
92
  private authorMirror;
91
93
  buildPendingBeaconPayload(): string | null;
92
94
  fireBeacon(): void;
95
+ flushPendingMirror(): void;
93
96
  forceCleanup(): void;
94
97
  private handleConnectionError;
95
98
  private handleReconnection;
@@ -0,0 +1 @@
1
+ export {};
@@ -68,8 +68,9 @@ export interface CollabConnectionConfig {
68
68
  joinOnly?: boolean;
69
69
  /** Host signal (editor): produces the view-plane mirror ciphertext from the live Yjs state. The app
70
70
  * AES-GCM-encrypts `{ file: base64(yjsUpdate), source }` under the fileKey in the publish wire
71
- * format. Absent ⇒ the mirror is not written. The package never sees the fileKey or the crypto. */
72
- encryptMirror?: (yjsUpdate: Uint8Array) => Promise<string>;
71
+ * format. Absent ⇒ the mirror is not written. Resolving to null ⇒ this write is skipped (e.g.
72
+ * the host has no fileKey yet). The package never sees the fileKey or the crypto. */
73
+ encryptMirror?: (yjsUpdate: Uint8Array) => Promise<string | null>;
73
74
  /** Host signal: the fileKey's rotation epoch (the gate `currentEpoch` / fileKey version — NOT
74
75
  * `editGrantEpoch`; default 0 for non-rotating plain-public docs). */
75
76
  fileKeyEpoch?: number;
@@ -1,10 +1,10 @@
1
1
  import * as BZ from "yjs";
2
- import { i as Yl, a as hl, s as eZ, r as ul, y as Il, b as pl, m as Rl } from "./index-BZbTaVjU.js";
2
+ import { i as Yl, a as hl, s as eZ, r as ul, y as Il, b as pl, m as Rl } from "./index-DhQTrCQd.js";
3
3
  import { g as sl } from "./executeStringFunction-CQ922vEp.js";
4
4
  import { Workbook as al } from "exceljs";
5
5
  import Kl from "luckyexcel";
6
- import { e as Jl, b as xl, n as Ml } from "./xlsx-hyperlink-inline-CEmgXple.js";
7
- import { parseDefinedNamesFromXlsxBuffer as Sl, excelEntriesToDefinedNames as OZ } from "./xlsx-defined-names-CGkkDs3a.js";
6
+ import { e as Jl, b as xl, n as Ml } from "./xlsx-hyperlink-inline-Cl9CbP5N.js";
7
+ import { parseDefinedNamesFromXlsxBuffer as Sl, excelEntriesToDefinedNames as OZ } from "./xlsx-defined-names-3g5n40BA.js";
8
8
  import { toast as fZ } from "@fileverse/ui";
9
9
  var Zl = { exports: {} };
10
10
  (function(m) {
@@ -1,5 +1,5 @@
1
1
  import { i as w } from "./executeStringFunction-CQ922vEp.js";
2
- import { J as x } from "./xlsx-hyperlink-inline-CEmgXple.js";
2
+ import { J as x } from "./xlsx-hyperlink-inline-Cl9CbP5N.js";
3
3
  function g(o) {
4
4
  return o.startsWith("_xlnm.");
5
5
  }
@@ -1,9 +1,9 @@
1
1
  import { utils as S, write as nt } from "xlsx-js-style";
2
2
  import { Workbook as pt } from "exceljs";
3
3
  import { toast as rt } from "@fileverse/ui";
4
- import { J as dt, c as X, g as ht, a as mt } from "./xlsx-hyperlink-inline-CEmgXple.js";
4
+ import { J as dt, c as X, g as ht, a as mt } from "./xlsx-hyperlink-inline-Cl9CbP5N.js";
5
5
  import { b as gt } from "./executeStringFunction-CQ922vEp.js";
6
- import { e as bt } from "./index-BZbTaVjU.js";
6
+ import { e as bt } from "./index-DhQTrCQd.js";
7
7
  const xt = {
8
8
  1: "thin",
9
9
  2: "hair",
@@ -854,7 +854,7 @@ const Z = (t) => {
854
854
  O
855
855
  );
856
856
  });
857
- const { applyDefinedNamesToExcelWorkbook: ct } = await import("./xlsx-defined-names-CGkkDs3a.js");
857
+ const { applyDefinedNamesToExcelWorkbook: ct } = await import("./xlsx-defined-names-3g5n40BA.js");
858
858
  ct(
859
859
  B,
860
860
  (k = (C = (s = t.current).getWorkbookContext) == null ? void 0 : C.call(s)) == null ? void 0 : k.definedNames,
@@ -1,5 +1,5 @@
1
1
  import { g as Rt, c as yt } from "./executeStringFunction-CQ922vEp.js";
2
- import { c as wt } from "./index-BZbTaVjU.js";
2
+ import { c as wt } from "./index-DhQTrCQd.js";
3
3
  function jt(J, nt) {
4
4
  const g = J.getImages();
5
5
  if (!g.length) return [];
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@fileverse-dev/dsheet",
3
3
  "private": false,
4
4
  "description": "DSheet",
5
- "version": "4.1.21",
5
+ "version": "4.1.22",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/fileverse/fileverse-dsheets.git"