@ai-matrx/office 0.8.26 → 0.8.28

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.
@@ -39,6 +39,7 @@ __export(collab_exports, {
39
39
  SENDER_VIEW_PARAMS: () => SENDER_VIEW_PARAMS,
40
40
  SHEETS_COLLAB_PROTO: () => SHEETS_COLLAB_PROTO,
41
41
  SHEETS_EDIT_GROUP: () => SHEETS_EDIT_GROUP,
42
+ SHEETS_READABLE_PROTOS: () => SHEETS_READABLE_PROTOS,
42
43
  WorkbookCollabSession: () => WorkbookCollabSession,
43
44
  applyDocsOp: () => applyDocsOp,
44
45
  asLoadedDocsSnapshot: () => asLoadedDocsSnapshot,
@@ -1166,6 +1167,38 @@ function stampDeterministicIds(snapshot) {
1166
1167
 
1167
1168
  // src/univer/collab/docs-ot/room.ts
1168
1169
  var import_collab2 = require("@ai-matrx/data/realtime/collab");
1170
+
1171
+ // src/docs/comment-anchors.ts
1172
+ var import_core5 = require("@univerjs/core");
1173
+ var COMMENT_ANCHOR_RANGE_TYPE = import_core5.CustomRangeType.COMMENT;
1174
+ var RETAIN_KEYS = /* @__PURE__ */ new Set(["t", "len", "body", "coverType"]);
1175
+ var RANGE_KEYS = /* @__PURE__ */ new Set(["rangeId", "rangeType", "startIndex", "endIndex", "properties"]);
1176
+ var isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
1177
+ var keysOf = (o) => Object.keys(o).filter((k) => o[k] !== void 0);
1178
+ function isDocsAnchorOnlyOp(op) {
1179
+ if (!Array.isArray(op) || op.length !== 2 || op[0] !== "body") return false;
1180
+ const x = op[1];
1181
+ if (!isObj(x) || x.et !== "text-x" || !Array.isArray(x.e) || x.e.length === 0) return false;
1182
+ if (keysOf(x).some((k) => k !== "et" && k !== "e")) return false;
1183
+ for (const c of x.e) {
1184
+ if (!isObj(c) || c.t !== "r" || typeof c.len !== "number") return false;
1185
+ if (keysOf(c).some((k) => !RETAIN_KEYS.has(k))) return false;
1186
+ if ("coverType" in c && typeof c.coverType !== "number") return false;
1187
+ if ("body" in c) {
1188
+ const b = c.body;
1189
+ if (!isObj(b) || keysOf(b).some((k) => k !== "dataStream" && k !== "customRanges")) return false;
1190
+ if (b.dataStream !== void 0 && b.dataStream !== "") return false;
1191
+ if (!Array.isArray(b.customRanges) || b.customRanges.length === 0) return false;
1192
+ for (const r of b.customRanges) {
1193
+ if (!isObj(r) || r.rangeType !== COMMENT_ANCHOR_RANGE_TYPE) return false;
1194
+ if (keysOf(r).some((k) => !RANGE_KEYS.has(k))) return false;
1195
+ }
1196
+ }
1197
+ }
1198
+ return true;
1199
+ }
1200
+
1201
+ // src/univer/collab/docs-ot/room.ts
1169
1202
  var RICH_TEXT_EDITING = "doc.mutation.rich-text-editing";
1170
1203
  var DOCS_COLLAB_PROTO = 1;
1171
1204
  function canonicalKeys(v) {
@@ -1266,6 +1299,7 @@ function openDocsOtRoom(o) {
1266
1299
  return { op: isNoopDocsOp(r.op) ? null : r.op, lost: r.lost };
1267
1300
  },
1268
1301
  compose: (a, b) => composeDocsOps(a, b),
1302
+ isAnchorOnly: (op) => isDocsAnchorOnlyOp(op),
1269
1303
  isNoop: (op) => isNoopDocsOp(op),
1270
1304
  encode: (op) => [{ cmd: "docs.edit", mutations: [{ id: RICH_TEXT_EDITING, params: { segmentId: "", actions: canonicalKeys(op) } }] }],
1271
1305
  decode(groups) {
@@ -1412,7 +1446,7 @@ var import_awareness2 = require("y-protocols/awareness");
1412
1446
  var import_collab3 = require("@ai-matrx/data/realtime/collab");
1413
1447
 
1414
1448
  // src/docs/remote-carets.ts
1415
- var import_core5 = require("@univerjs/core");
1449
+ var import_core6 = require("@univerjs/core");
1416
1450
  var CARET_HEARTBEAT_MS = 2e3;
1417
1451
  var CARET_STALE_MS = 12e3;
1418
1452
  var CARET_MAX_RANGES = 4;
@@ -1430,8 +1464,8 @@ function movePeerRangesThroughBodyEdit(ranges, actions) {
1430
1464
  const e = sub.e;
1431
1465
  return ranges.map((r) => {
1432
1466
  const collapsed = r.start === r.end;
1433
- const start = import_core5.TextX.transformPosition(e, r.start, false);
1434
- return { start, end: collapsed ? start : import_core5.TextX.transformPosition(e, r.end, true) };
1467
+ const start = import_core6.TextX.transformPosition(e, r.start, false);
1468
+ return { start, end: collapsed ? start : import_core6.TextX.transformPosition(e, r.end, true) };
1435
1469
  });
1436
1470
  }
1437
1471
  var sameRanges = (a, b) => a.length === b.length && a.every((r, i) => r.start === b[i].start && r.end === b[i].end);
@@ -1558,10 +1592,23 @@ async function loadSnapshotRow(documentId, ref) {
1558
1592
  if (!data) throw new Error(`The saved version ${ref} of this document is missing.`);
1559
1593
  return data.snapshot ?? null;
1560
1594
  }
1561
- async function documentUsesOrderedRoom(documentId, knob, isNewDocument) {
1595
+ async function deviceHoldsBuffer(key) {
1596
+ if (!key || typeof indexedDB === "undefined") return false;
1597
+ try {
1598
+ const store = (0, import_collab3.createIndexedDbOfflineStore)();
1599
+ return await store.load(key) != null || await store.load((0, import_collab3.refusedKey)(key)) != null;
1600
+ } catch {
1601
+ return false;
1602
+ }
1603
+ }
1604
+ async function documentUsesOrderedRoom(documentId, knob, isNewDocument, offlineKey) {
1562
1605
  try {
1563
1606
  if (await (0, import_collab3.collabRoomExists)(db2(), documentId)) return true;
1564
1607
  } catch (err) {
1608
+ if (await deviceHoldsBuffer(offlineKey)) {
1609
+ console.warn("[document] could not ask whether this document has a co-editing room; unsent edits on this device say it does", err);
1610
+ return true;
1611
+ }
1565
1612
  console.warn("[document] could not ask whether this document has a co-editing room; opening the relay room", err);
1566
1613
  return false;
1567
1614
  }
@@ -1840,16 +1887,17 @@ var SHEET_MUTATIONS = {
1840
1887
  "formula.mutation.remove-super-table": barrier("C5c", "table names in structured references belong to tables (C5c)"),
1841
1888
  "formula.mutation.set-super-table-option": barrier("C5c", "table names in structured references belong to tables (C5c)"),
1842
1889
  // ── barriers until C5c (ranged resources) ────────────────────────────────────────────────────────
1843
- "sheet.mutation.add-conditional-rule": barrier("C5c", RESOURCE),
1844
- "sheet.mutation.set-conditional-rule": barrier("C5c", RESOURCE),
1845
- "sheet.mutation.delete-conditional-rule": barrier("C5c", RESOURCE),
1890
+ // ── covered (C5d): ranged resources, transformed by ranged-resources.ts ──
1891
+ "sheet.mutation.add-conditional-rule": covered("cf", "rule", "derived"),
1892
+ "sheet.mutation.set-conditional-rule": covered("cf", "cfId", "rule", "derived"),
1893
+ "sheet.mutation.delete-conditional-rule": covered("cf", "cfId", "derived"),
1846
1894
  "sheet.mutation.move-conditional-rule": barrier("C5c", "conditional-format priority (ordered list)"),
1847
- "data-validation.mutation.addRule": barrier("C5c", RESOURCE),
1848
- "data-validation.mutation.updateRule": barrier("C5c", RESOURCE),
1849
- "data-validation.mutation.removeRule": barrier("C5c", RESOURCE),
1850
- "sheet.mutation.set-filter-range": barrier("C5c", RESOURCE),
1851
- "sheet.mutation.set-filter-criteria": barrier("C5c", RESOURCE),
1852
- "sheet.mutation.remove-filter": barrier("C5c", RESOURCE),
1895
+ "data-validation.mutation.addRule": covered("dv", "rule", "index", "source", "derived"),
1896
+ "data-validation.mutation.updateRule": covered("dv", "ruleId", "payload", "source", "derived"),
1897
+ "data-validation.mutation.removeRule": covered("dv", "ruleId", "source", "derived"),
1898
+ "sheet.mutation.set-filter-range": covered("filter", "range", "derived"),
1899
+ "sheet.mutation.set-filter-criteria": covered("filter", "col", "criteria", "reCalc", "derived"),
1900
+ "sheet.mutation.remove-filter": covered("filter", "derived"),
1853
1901
  "sheet.mutation.add-table": barrier("C5c", RESOURCE),
1854
1902
  "sheet.mutation.delete-table": barrier("C5c", RESOURCE),
1855
1903
  "sheet.mutation.set-sheet-table": barrier("C5c", RESOURCE),
@@ -1996,7 +2044,7 @@ function transformAxis(x, y, side) {
1996
2044
  }
1997
2045
 
1998
2046
  // src/collab/sheets/transform/formula.ts
1999
- var import_core6 = require("@univerjs/core");
2047
+ var import_core7 = require("@univerjs/core");
2000
2048
  var import_engine_formula = require("@univerjs/engine-formula");
2001
2049
  var import_sheets = require("@univerjs/sheets");
2002
2050
  var REF_ERROR = "#REF!";
@@ -2048,8 +2096,8 @@ function referencedSheetNames(text) {
2048
2096
  }
2049
2097
  return [...out];
2050
2098
  }
2051
- var fullRowsRange = (start, count) => ({ startRow: start, endRow: start + count - 1, startColumn: 0, endColumn: FULL, rangeType: import_core6.RANGE_TYPE.ROW });
2052
- var fullColsRange = (start, count) => ({ startRow: 0, endRow: FULL, startColumn: start, endColumn: start + count - 1, rangeType: import_core6.RANGE_TYPE.COLUMN });
2099
+ var fullRowsRange = (start, count) => ({ startRow: start, endRow: start + count - 1, startColumn: 0, endColumn: FULL, rangeType: import_core7.RANGE_TYPE.ROW });
2100
+ var fullColsRange = (start, count) => ({ startRow: 0, endRow: FULL, startColumn: start, endColumn: start + count - 1, rangeType: import_core7.RANGE_TYPE.COLUMN });
2053
2101
  var startV = (v) => Number.isNaN(v) || v == null ? -Infinity : v;
2054
2102
  var endV = (v) => Number.isNaN(v) || v == null ? Infinity : v;
2055
2103
  function startEnd(r) {
@@ -2058,9 +2106,9 @@ function startEnd(r) {
2058
2106
  function checkMoveEdge(origin, from) {
2059
2107
  const startRow = startV(origin.startRow), endRow = endV(origin.endRow), startColumn = startV(origin.startColumn), endColumn = endV(origin.endColumn);
2060
2108
  const fromStartRow = startV(from.startRow), fromEndRow = endV(from.endRow), fromStartColumn = startV(from.startColumn), fromEndColumn = endV(from.endColumn);
2061
- const rowsCover = () => origin.rangeType === import_core6.RANGE_TYPE.COLUMN && from.rangeType === import_core6.RANGE_TYPE.COLUMN || startRow >= fromStartRow && endRow <= fromEndRow;
2062
- const columnsCover = () => origin.rangeType === import_core6.RANGE_TYPE.ROW && from.rangeType === import_core6.RANGE_TYPE.ROW || startColumn >= fromStartColumn && endColumn <= fromEndColumn;
2063
- const allCover = () => origin.rangeType === import_core6.RANGE_TYPE.ALL && from.rangeType === import_core6.RANGE_TYPE.ALL;
2109
+ const rowsCover = () => origin.rangeType === import_core7.RANGE_TYPE.COLUMN && from.rangeType === import_core7.RANGE_TYPE.COLUMN || startRow >= fromStartRow && endRow <= fromEndRow;
2110
+ const columnsCover = () => origin.rangeType === import_core7.RANGE_TYPE.ROW && from.rangeType === import_core7.RANGE_TYPE.ROW || startColumn >= fromStartColumn && endColumn <= fromEndColumn;
2111
+ const allCover = () => origin.rangeType === import_core7.RANGE_TYPE.ALL && from.rangeType === import_core7.RANGE_TYPE.ALL;
2064
2112
  if (rowsCover() && columnsCover() || allCover()) return 4;
2065
2113
  if (columnsCover() && startRow >= fromStartRow && startRow <= fromEndRow && endRow > fromEndRow) return 0;
2066
2114
  if (columnsCover() && endRow >= fromStartRow && endRow <= fromEndRow && startRow < fromStartRow) return 1;
@@ -2071,14 +2119,14 @@ function checkMoveEdge(origin, from) {
2071
2119
  function getMoveNewRange(moveEdge, result, from, to, origin, remain) {
2072
2120
  const { startRow, endRow, startColumn, endColumn, rangeType } = startEnd(result);
2073
2121
  const f = startEnd(from);
2074
- const fromRangeType = from.rangeType ?? import_core6.RANGE_TYPE.NORMAL;
2122
+ const fromRangeType = from.rangeType ?? import_core7.RANGE_TYPE.NORMAL;
2075
2123
  const t = startEnd(to);
2076
2124
  const rm = startEnd(remain);
2077
2125
  const o = startEnd(origin);
2078
- const originRangeType = origin.rangeType ?? import_core6.RANGE_TYPE.NORMAL;
2126
+ const originRangeType = origin.rangeType ?? import_core7.RANGE_TYPE.NORMAL;
2079
2127
  const newRange = { ...origin };
2080
- const rowsCover = () => rangeType === import_core6.RANGE_TYPE.COLUMN && originRangeType === import_core6.RANGE_TYPE.COLUMN || startColumn >= o.startColumn && endColumn <= o.endColumn;
2081
- const columnsCover = () => rangeType === import_core6.RANGE_TYPE.ROW && originRangeType === import_core6.RANGE_TYPE.ROW || startRow >= o.startRow && endRow <= o.endRow;
2128
+ const rowsCover = () => rangeType === import_core7.RANGE_TYPE.COLUMN && originRangeType === import_core7.RANGE_TYPE.COLUMN || startColumn >= o.startColumn && endColumn <= o.endColumn;
2129
+ const columnsCover = () => rangeType === import_core7.RANGE_TYPE.ROW && originRangeType === import_core7.RANGE_TYPE.ROW || startRow >= o.startRow && endRow <= o.endRow;
2082
2130
  if (moveEdge === 0) {
2083
2131
  if (!rowsCover()) return void 0;
2084
2132
  if (startRow < o.startRow) newRange.startRow = startRow;
@@ -2101,7 +2149,7 @@ function getMoveNewRange(moveEdge, result, from, to, origin, remain) {
2101
2149
  else return void 0;
2102
2150
  } else if (moveEdge === 4) {
2103
2151
  Object.assign(newRange, { startRow, startColumn, endRow, endColumn });
2104
- } else if (f.startColumn <= o.startColumn && f.endColumn >= o.endColumn || fromRangeType === import_core6.RANGE_TYPE.ROW && originRangeType === import_core6.RANGE_TYPE.ROW) {
2152
+ } else if (f.startColumn <= o.startColumn && f.endColumn >= o.endColumn || fromRangeType === import_core7.RANGE_TYPE.ROW && originRangeType === import_core7.RANGE_TYPE.ROW) {
2105
2153
  const n = f.endRow - f.startRow + 1;
2106
2154
  if (from.endRow < o.startRow) {
2107
2155
  if (t.startRow >= o.startRow) newRange.startRow -= n;
@@ -2113,7 +2161,7 @@ function getMoveNewRange(moveEdge, result, from, to, origin, remain) {
2113
2161
  if (t.startRow <= o.startRow) newRange.startRow += n;
2114
2162
  else if (t.startRow >= o.endRow) newRange.endRow -= n;
2115
2163
  }
2116
- } else if (f.startRow <= o.startRow && f.endRow >= o.endRow || fromRangeType === import_core6.RANGE_TYPE.COLUMN && originRangeType === import_core6.RANGE_TYPE.COLUMN) {
2164
+ } else if (f.startRow <= o.startRow && f.endRow >= o.endRow || fromRangeType === import_core7.RANGE_TYPE.COLUMN && originRangeType === import_core7.RANGE_TYPE.COLUMN) {
2117
2165
  const n = f.endColumn - f.startColumn + 1;
2118
2166
  if (from.endColumn < o.startColumn) {
2119
2167
  if (t.startColumn >= o.startColumn) newRange.startColumn -= n;
@@ -2135,7 +2183,7 @@ function moveRange(range, axis, op) {
2135
2183
  const isRow = axis === "row";
2136
2184
  if (op.kind === "insert") {
2137
2185
  const r = isRow ? fullRowsRange(op.at, op.count) : fullColsRange(op.at, op.count);
2138
- const ops2 = isRow ? (0, import_sheets.handleInsertRow)({ id: import_sheets.EffectRefRangId.InsertRowCommandId, params: { range: r, unitId: "", subUnitId: "", direction: import_core6.Direction.DOWN } }, range) : (0, import_sheets.handleInsertCol)({ id: import_sheets.EffectRefRangId.InsertColCommandId, params: { range: r, unitId: "", subUnitId: "", direction: import_core6.Direction.RIGHT } }, range);
2186
+ const ops2 = isRow ? (0, import_sheets.handleInsertRow)({ id: import_sheets.EffectRefRangId.InsertRowCommandId, params: { range: r, unitId: "", subUnitId: "", direction: import_core7.Direction.DOWN } }, range) : (0, import_sheets.handleInsertCol)({ id: import_sheets.EffectRefRangId.InsertColCommandId, params: { range: r, unitId: "", subUnitId: "", direction: import_core7.Direction.RIGHT } }, range);
2139
2187
  const res2 = (0, import_sheets.runRefRangeMutations)(ops2, range);
2140
2188
  return res2 == null ? void 0 : { ...range, ...res2 };
2141
2189
  }
@@ -2148,11 +2196,11 @@ function moveRange(range, axis, op) {
2148
2196
  const from = isRow ? fullRowsRange(op.from, op.count) : fullColsRange(op.from, op.count);
2149
2197
  const to = isRow ? fullRowsRange(op.to, op.count) : fullColsRange(op.to, op.count);
2150
2198
  const moveEdge = checkMoveEdge(range, from);
2151
- let remain = (0, import_core6.getIntersectRange)(range, from);
2199
+ let remain = (0, import_core7.getIntersectRange)(range, from);
2152
2200
  if (isRow) {
2153
2201
  if (remain == null && (from.endRow < range.startRow && to.endRow <= range.startRow || from.startRow > range.endRow && to.startRow > range.endRow)) return void 0;
2154
2202
  } else if (remain == null && (from.endColumn < range.startColumn && to.endColumn <= range.startColumn || from.startColumn > range.endColumn && to.startColumn > range.endColumn)) return void 0;
2155
- remain ??= { startRow: range.startRow, endRow: range.endRow, startColumn: range.startColumn, endColumn: range.endColumn, rangeType: import_core6.RANGE_TYPE.NORMAL };
2203
+ remain ??= { startRow: range.startRow, endRow: range.endRow, startColumn: range.startColumn, endColumn: range.endColumn, rangeType: import_core7.RANGE_TYPE.NORMAL };
2156
2204
  const ops = isRow ? (0, import_sheets.handleMoveRows)({ id: import_sheets.EffectRefRangId.MoveRowsCommandId, params: { toRange: to, fromRange: from } }, remain) : (0, import_sheets.handleMoveCols)({ id: import_sheets.EffectRefRangId.MoveColsCommandId, params: { toRange: to, fromRange: from } }, remain);
2157
2205
  const res = (0, import_sheets.runRefRangeMutations)(ops, remain);
2158
2206
  if (res == null) return REF_ERROR;
@@ -2182,8 +2230,11 @@ function rewriteFormula(text, ctx, change) {
2182
2230
  if (change.kind === "rename") {
2183
2231
  if (!sheetName) continue;
2184
2232
  token = (0, import_engine_formula.serializeRangeToRefString)({ range, sheetName: change.name, unitId });
2233
+ } else if (change.kind === "remove-sheet") {
2234
+ if (!sheetName) continue;
2235
+ token = REF_ERROR;
2185
2236
  } else {
2186
- const moved = moveRange(import_core6.Rectangle.moveOffset(range, 0, 0), change.axis, change.op);
2237
+ const moved = moveRange(import_core7.Rectangle.moveOffset(range, 0, 0), change.axis, change.op);
2187
2238
  if (moved === void 0) continue;
2188
2239
  token = moved === REF_ERROR ? REF_ERROR : (0, import_engine_formula.serializeRangeToRefString)({ range: moved, sheetName: target === ctx.ownSheet && !ctx.keepQualifier ? "" : sheetName, unitId });
2189
2240
  }
@@ -2200,6 +2251,10 @@ function rewriteFormula(text, ctx, change) {
2200
2251
  return { text: out, changed: out !== text };
2201
2252
  }
2202
2253
  function refSheetsAfter(refSheets, change) {
2254
+ if (change.kind === "remove-sheet" && refSheets) {
2255
+ if (!Object.values(refSheets).includes(change.sheet)) return refSheets;
2256
+ return Object.fromEntries(Object.entries(refSheets).map(([n, id]) => [n, id === change.sheet ? null : id]));
2257
+ }
2203
2258
  if (change.kind !== "rename" || !refSheets) return refSheets;
2204
2259
  const entries = Object.entries(refSheets);
2205
2260
  if (!entries.some(([name, id]) => id === change.sheet || name === change.name)) return refSheets;
@@ -2217,6 +2272,9 @@ function refSheetsFor(texts, sheets) {
2217
2272
 
2218
2273
  // src/collab/sheets/comment-anchor-transform.ts
2219
2274
  var SET_SHEET_COMMENT_ANCHOR = "matrx.mutation.set-comment-anchor";
2275
+ function isSheetsAnchorOnlyOp(op) {
2276
+ return !!op && op.length > 0 && op.every((m) => m.id === SET_SHEET_COMMENT_ANCHOR);
2277
+ }
2220
2278
  var REMOVE_SHEET = "sheet.mutation.remove-sheet";
2221
2279
  function structuralAxisOp(id, params) {
2222
2280
  const p = params;
@@ -2283,8 +2341,111 @@ function transformCommentAnchor(x, y, side) {
2283
2341
  return ok([moved === cell ? x : { id: x.id, params: { ...x.params, cell: moved } }]);
2284
2342
  }
2285
2343
 
2344
+ // src/collab/sheets/transform/ranged-resources.ts
2345
+ var specs = /* @__PURE__ */ new Map();
2346
+ var byId = /* @__PURE__ */ new Map();
2347
+ function registerRangedResource(spec) {
2348
+ specs.set(spec.family, spec);
2349
+ for (const id of Object.keys(spec.ids)) byId.set(id, spec);
2350
+ }
2351
+ var rangedSpecOf = (id) => byId.get(id);
2352
+ var cfRule = (m) => m.params.rule ?? {};
2353
+ var CF_FORMULA = (r) => {
2354
+ const rule = r.rule ?? {};
2355
+ if (rule.type === "highlightCell" && rule.subType === "formula") return true;
2356
+ return JSON.stringify(rule).includes('"type":"formula"');
2357
+ };
2358
+ registerRangedResource({
2359
+ family: "cf",
2360
+ ids: { "sheet.mutation.add-conditional-rule": "add", "sheet.mutation.set-conditional-rule": "set", "sheet.mutation.delete-conditional-rule": "remove" },
2361
+ keys: (m) => [String(m.id === "sheet.mutation.add-conditional-rule" ? cfRule(m).cfId : m.params.cfId)],
2362
+ rects: (m) => cfRule(m).ranges ?? null,
2363
+ withRects: (m, rects) => ({ id: m.id, params: { ...m.params, rule: { ...cfRule(m), ranges: rects } } }),
2364
+ setFor: (m, rects) => ({
2365
+ id: "sheet.mutation.set-conditional-rule",
2366
+ params: { subUnitId: m.params.subUnitId, cfId: cfRule(m).cfId ?? m.params.cfId, rule: { ...cfRule(m), ranges: rects }, derived: true }
2367
+ }),
2368
+ removeOf: (sheet, key) => ({ id: "sheet.mutation.delete-conditional-rule", params: { subUnitId: sheet, cfId: key, derived: true } }),
2369
+ hasFormula: (m) => CF_FORMULA(cfRule(m)),
2370
+ orderedAdds: true
2371
+ });
2372
+ var DV = { add: "data-validation.mutation.addRule", update: "data-validation.mutation.updateRule", remove: "data-validation.mutation.removeRule" };
2373
+ var DV_RANGE = 1;
2374
+ var DV_FACETS = { 0: "setting", 1: "range", 2: "options", 3: "all" };
2375
+ var dvPayload = (m) => m.params.payload ?? {};
2376
+ var dvFormula = (o) => !!o && [o.formula1, o.formula2].some((f) => typeof f === "string" && f.trim().startsWith("="));
2377
+ registerRangedResource({
2378
+ family: "dv",
2379
+ ids: { [DV.add]: "add", [DV.update]: "set", [DV.remove]: "remove" },
2380
+ keys: (m) => {
2381
+ if (m.id === DV.add) return [String((m.params.rule ?? {}).uid)];
2382
+ const id = m.params.ruleId;
2383
+ return Array.isArray(id) ? id.map(String) : [String(id)];
2384
+ },
2385
+ facet: (m) => m.id === DV.update ? DV_FACETS[Number(dvPayload(m).type)] ?? "all" : "all",
2386
+ rects: (m) => {
2387
+ if (m.id === DV.add) return m.params.rule?.ranges ?? null;
2388
+ if (m.id === DV.update && dvPayload(m).type === DV_RANGE) return dvPayload(m).payload ?? null;
2389
+ if (m.id === DV.update && dvPayload(m).type === 3) return (dvPayload(m).payload ?? {}).ranges ?? null;
2390
+ return null;
2391
+ },
2392
+ withRects: (m, rects) => {
2393
+ if (m.id === DV.add) return { id: m.id, params: { ...m.params, rule: { ...m.params.rule, ranges: rects } } };
2394
+ const p = dvPayload(m);
2395
+ return { id: m.id, params: { ...m.params, payload: p.type === DV_RANGE ? { ...p, payload: rects } : { ...p, payload: { ...p.payload, ranges: rects } } } };
2396
+ },
2397
+ setFor: (m, rects) => ({
2398
+ id: DV.update,
2399
+ params: { subUnitId: m.params.subUnitId, ruleId: m.id === DV.add ? (m.params.rule ?? {}).uid : m.params.ruleId, payload: { type: DV_RANGE, payload: rects }, derived: true }
2400
+ }),
2401
+ removeOf: (sheet, key) => ({ id: DV.remove, params: { subUnitId: sheet, ruleId: key, derived: true } }),
2402
+ withoutKeys: (m, keys) => {
2403
+ const left = (Array.isArray(m.params.ruleId) ? m.params.ruleId : [m.params.ruleId]).filter((k) => !keys.includes(String(k)));
2404
+ return left.length ? { id: m.id, params: { ...m.params, ruleId: Array.isArray(m.params.ruleId) ? left : left[0] } } : null;
2405
+ },
2406
+ hasFormula: (m) => {
2407
+ if (m.id === DV.add) return dvFormula(m.params.rule);
2408
+ const p = dvPayload(m);
2409
+ return p.type === 0 || p.type === 3 ? dvFormula(p.payload) : false;
2410
+ },
2411
+ orderedAdds: true,
2412
+ // an ALL update (the ref-range handler restates the whole rule) losing to a setting/options change keeps its ranges
2413
+ narrow: (m, lost) => {
2414
+ if (m.id !== DV.update || dvPayload(m).type !== 3 || lost === "range") return null;
2415
+ const ranges = (dvPayload(m).payload ?? {}).ranges;
2416
+ return Array.isArray(ranges) ? { id: m.id, params: { ...m.params, payload: { type: DV_RANGE, payload: ranges } } } : null;
2417
+ }
2418
+ });
2419
+ var FILTER = { range: "sheet.mutation.set-filter-range", criteria: "sheet.mutation.set-filter-criteria", remove: "sheet.mutation.remove-filter" };
2420
+ var hull = (rects) => ({
2421
+ startRow: Math.min(...rects.map((r) => r.startRow)),
2422
+ endRow: Math.max(...rects.map((r) => r.endRow)),
2423
+ startColumn: Math.min(...rects.map((r) => r.startColumn)),
2424
+ endColumn: Math.max(...rects.map((r) => r.endColumn))
2425
+ });
2426
+ var filterWith = (m, rects) => m.id === FILTER.range ? { id: m.id, params: { ...m.params, range: hull(rects) } } : { id: m.id, params: { ...m.params, col: rects[0].startColumn } };
2427
+ var colRect = (col) => ({ startRow: 0, endRow: 1e9, startColumn: col, endColumn: col });
2428
+ registerRangedResource({
2429
+ family: "filter",
2430
+ ids: { [FILTER.range]: "set", [FILTER.criteria]: "set", [FILTER.remove]: "remove" },
2431
+ keys: () => ["filter"],
2432
+ facet: (m) => m.id === FILTER.criteria ? `col:${String(m.params.col)}` : "range",
2433
+ rects: (m) => m.id === FILTER.range ? [m.params.range] : m.id === FILTER.criteria ? [colRect(Number(m.params.col))] : null,
2434
+ withRects: (m, rects) => filterWith(m, rects),
2435
+ setFor: (m, rects) => {
2436
+ const f = filterWith(m, rects);
2437
+ return { id: f.id, params: { ...f.params, derived: true } };
2438
+ },
2439
+ removeOf: (sheet) => ({ id: FILTER.remove, params: { subUnitId: sheet, derived: true } }),
2440
+ /** a criteria column that was removed takes only its criteria with it, never the filter */
2441
+ emptyDrops: (m) => m.id === FILTER.criteria,
2442
+ // a column move can carry a criteria column out of the filter's range (the model refuses it): not yet
2443
+ // where a criteria column lands depends on how the filter's own range moved (Univer's rule at its edges): not yet
2444
+ barrierOver: (m, axis) => m.id === FILTER.criteria && axis === "col" ? "filter: a column's criteria against a column insert, remove or move" : null
2445
+ });
2446
+
2286
2447
  // src/collab/sheets/transform/transform.ts
2287
- var SHEET_TRANSFORMER_VERSION = "c5c-1";
2448
+ var SHEET_TRANSFORMER_VERSION = "c5d-1";
2288
2449
  var ID = {
2289
2450
  values: "sheet.mutation.set-range-values",
2290
2451
  insertRow: "sheet.mutation.insert-row",
@@ -3059,19 +3220,44 @@ function sheetPair(x, y, side) {
3059
3220
  if (ys) {
3060
3221
  if (y.id !== ID.removeSheet) return ok2([x]);
3061
3222
  const gone2 = sheetOf(y);
3062
- if (namesSheet(x, gone2)) return barrier2("a formula names a sheet removed at the same time");
3063
3223
  if (sheetOf(x) === gone2 && x.id !== ID.setName && x.id !== ID.removeName)
3064
3224
  return ok2([], [], isDerived(x) ? [] : [`${gone2}: the sheet was removed`]);
3225
+ if (namesSheet(x, gone2)) {
3226
+ const ch = { kind: "remove-sheet", sheet: gone2 };
3227
+ if (x.id === ID.values) return cellsOverChange(x, ch);
3228
+ const r = definedNameThrough(x, ch);
3229
+ return typeof r === "string" ? barrier2(r) : ok2([r.op]);
3230
+ }
3065
3231
  return ok2([x]);
3066
3232
  }
3067
3233
  if (x.id !== ID.removeSheet) return ok2([x]);
3068
3234
  const gone = sheetOf(x);
3069
- if (namesSheet(y, gone)) return barrier2("a formula names a sheet removed at the same time");
3070
- return ok2([x], sheetOf(y) === gone && !isDerived(y) && y.id !== ID.setName && y.id !== ID.removeName ? [`${gone}: the sheet was removed`] : []);
3235
+ const ry = rangedSpecOf(y.id);
3236
+ if (ry && sheetOf(y) === gone && ry.ids[y.id] !== "remove")
3237
+ return ok2([...ry.keys(y).map((k) => ({ id: ry.removeOf(gone, k).id, params: { ...ry.removeOf(gone, k).params } })), x]);
3238
+ const lost = sheetOf(y) === gone && !isDerived(y) && y.id !== ID.setName && y.id !== ID.removeName ? [`${gone}: the sheet was removed`] : [];
3239
+ if (sheetOf(y) !== gone && namesSheet(y, gone)) {
3240
+ const ch = { kind: "remove-sheet", sheet: gone };
3241
+ if (y.id === ID.values) {
3242
+ const add = rewritesOf(y, ch);
3243
+ if (typeof add === "string") return barrier2(add);
3244
+ return ok2(add ? [x, add] : [x], lost);
3245
+ }
3246
+ const r = definedNameThrough(y, ch);
3247
+ if (typeof r === "string") return barrier2(r);
3248
+ return ok2(r.changed ? [x, asDerived(r.op)] : [x], lost);
3249
+ }
3250
+ return ok2([x], lost);
3071
3251
  }
3072
3252
  function annotateSheetOps(group, sheetOrder) {
3253
+ return cleanupsBeforeSheetRemoval(annotateSheetOpsInOrder(group, sheetOrder));
3254
+ }
3255
+ function annotateSheetOpsInOrder(group, sheetOrder) {
3073
3256
  const order = [...sheetOrder];
3074
- return group.map((m) => {
3257
+ let structural = false;
3258
+ return group.map((m0) => {
3259
+ if (structuralOf(m0)) structural = true;
3260
+ const m = structural && rangedSpecOf(m0.id) && !isDerived(m0) ? { id: m0.id, params: { ...m0.params, derived: true } } : m0;
3075
3261
  if (m.id === ID.insertSheet) {
3076
3262
  const index = typeof m.params.index === "number" ? Math.min(m.params.index, order.length) : order.length;
3077
3263
  order.splice(index, 0, sheetIdOf(m));
@@ -3090,6 +3276,16 @@ function annotateSheetOps(group, sheetOrder) {
3090
3276
  return m;
3091
3277
  });
3092
3278
  }
3279
+ function cleanupsBeforeSheetRemoval(group) {
3280
+ const at = group.findIndex((m) => m.id === ID.removeSheet);
3281
+ if (at < 0) return group;
3282
+ const gone = sheetOf(group[at]);
3283
+ const moved = group.filter((m, k2) => k2 > at && rangedSpecOf(m.id) && sheetOf(m) === gone);
3284
+ if (!moved.length) return group;
3285
+ const rest = group.filter((m) => !moved.includes(m));
3286
+ const k = rest.indexOf(group[at]);
3287
+ return [...rest.slice(0, k), ...moved, ...rest.slice(k)];
3288
+ }
3093
3289
  function inlineSheetStyles(sheet, styleOf) {
3094
3290
  const out = JSON.parse(JSON.stringify(sheet));
3095
3291
  const fix = (o) => {
@@ -3219,6 +3415,59 @@ function sortPair(x, y, sx, sy) {
3219
3415
  }
3220
3416
  return ok2([x]);
3221
3417
  }
3418
+ function rangedPair(x, y, side, sx, sy) {
3419
+ const px = rangedSpecOf(x.id);
3420
+ const py = rangedSpecOf(y.id);
3421
+ if (!px && !py) return null;
3422
+ const told = (m, what) => isDerived(m) ? [] : [`${sheetOf(m)}: ${what}`];
3423
+ if (px && sy) {
3424
+ const role = px.ids[x.id];
3425
+ const rects = role === "remove" ? null : px.rects(x);
3426
+ if (!rects) return ok2([x]);
3427
+ const why = px.barrierOver?.(x, sy.axis, sy.op.kind);
3428
+ if (why) return barrier2(why);
3429
+ if (px.hasFormula?.(x)) return barrier2(`${px.family}: a rule with formula text against a row or column change (its formulas do not move yet)`);
3430
+ const moved = rectsThrough(sy, rects);
3431
+ if (moved.length) return ok2([px.withRects(x, moved)]);
3432
+ if (role === "add" || px.emptyDrops?.(x)) return ok2([], [], told(x, `${px.family} ${px.keys(x).join(",")}: its cells were removed`));
3433
+ return ok2(px.keys(x).map((k) => px.removeOf(sheetOf(x), k)), [], told(x, `${px.family} ${px.keys(x).join(",")}: its cells were removed`));
3434
+ }
3435
+ if (py && sx) {
3436
+ const role = py.ids[y.id];
3437
+ const rects = role === "remove" ? null : py.rects(y);
3438
+ if (!rects) return ok2([x]);
3439
+ const why = py.barrierOver?.(y, sx.axis, sx.op.kind);
3440
+ if (why) return barrier2(why);
3441
+ if (py.hasFormula?.(y)) return barrier2(`${py.family}: a rule with formula text against a row or column change (its formulas do not move yet)`);
3442
+ const moved = rectsThrough(sx, rects);
3443
+ if (!moved.length && py.emptyDrops?.(y)) return ok2([x], told(y, `${py.family} ${py.keys(y).join(",")}: its cells were removed`));
3444
+ return ok2([x, ...moved.length ? [py.setFor(y, moved)] : py.keys(y).map((k) => py.removeOf(sheetOf(y), k))], moved.length ? [] : told(y, `${py.family} ${py.keys(y).join(",")}: its cells were removed`));
3445
+ }
3446
+ if (!px || !py || px !== py) return ok2([x]);
3447
+ const rx = px.ids[x.id];
3448
+ const ry = py.ids[y.id];
3449
+ const ky = py.keys(y);
3450
+ const common = px.keys(x).filter((k) => ky.includes(k));
3451
+ if (!common.length) {
3452
+ if (rx === "add" && ry === "add" && px.orderedAdds) return barrier2(`${px.family}: two added to one sheet at once (their order is state)`);
3453
+ return ok2([x]);
3454
+ }
3455
+ if (rx === "remove") {
3456
+ if (ry !== "remove") return ok2([x]);
3457
+ const rest = px.withoutKeys ? px.withoutKeys(x, common) : null;
3458
+ return ok2(rest ? [rest] : []);
3459
+ }
3460
+ if (ry === "remove") return ok2([], [], told(x, `${px.family} ${common.join(",")}: removed at the same time`));
3461
+ const fx = px.facet?.(x) ?? "all";
3462
+ const fy = py.facet?.(y) ?? "all";
3463
+ if (fx !== fy && fx !== "all" && fy !== "all") return ok2([x]);
3464
+ const dx = isDerived(x);
3465
+ const dy = isDerived(y);
3466
+ const xWins = dx !== dy ? !dx : side === "left";
3467
+ if (xWins) return ok2([x], told(y, `${py.family} ${common.join(",")}`));
3468
+ const narrowed = fx === "all" && fy !== "all" ? px.narrow?.(x, fy) : null;
3469
+ return ok2(narrowed ? [narrowed] : [], [], told(x, `${px.family} ${common.join(",")}`));
3470
+ }
3222
3471
  function familyOf(id) {
3223
3472
  const e = SHEET_MUTATIONS[id];
3224
3473
  return e && e.kind === "covered" ? e.family : "";
@@ -3246,6 +3495,8 @@ function transformMutation(x, y, side) {
3246
3495
  const fy = familyOf(y.id);
3247
3496
  const sy = structuralOf(y);
3248
3497
  const sx = structuralOf(x);
3498
+ const rp = rangedPair(x, y, side, sx, sy);
3499
+ if (rp) return rp;
3249
3500
  const sortp = sortPair(x, y, sx, sy);
3250
3501
  if (sortp) return sortp;
3251
3502
  const cp = countPair(x, y, sy);
@@ -3428,6 +3679,12 @@ function parsedResource(data) {
3428
3679
  return data;
3429
3680
  }
3430
3681
  }
3682
+ function withoutComputed(name, data) {
3683
+ if (name !== "SHEET_FILTER_PLUGIN" || !data || typeof data !== "object") return data;
3684
+ const out = {};
3685
+ for (const [sheet, f] of Object.entries(data)) out[sheet] = f && typeof f === "object" ? (({ cachedFilteredOut: _c, ...rest }) => rest)(f) : f;
3686
+ return out;
3687
+ }
3431
3688
  function canonicalSheet(snapshot) {
3432
3689
  const s = structuredClone(snapshot ?? {});
3433
3690
  for (const k of SHEET_LOCAL_KEYS) delete s[k];
@@ -3455,7 +3712,7 @@ function canonicalSheet(snapshot) {
3455
3712
  sheet.mergeData = sheet.mergeData.map((m) => JSON.stringify(sortDeep2(m))).sort().map((j) => JSON.parse(j));
3456
3713
  }
3457
3714
  if (Array.isArray(s.resources))
3458
- s.resources = s.resources.map((r) => ({ name: r.name, data: sortDeep2(parsedResource(r.data)) })).filter((r) => r.data != null && r.data !== "" && !(typeof r.data === "object" && Object.keys(r.data).length === 0)).sort((a, b) => String(a.name).localeCompare(String(b.name)));
3715
+ s.resources = s.resources.map((r) => ({ name: r.name, data: sortDeep2(withoutComputed(r.name, parsedResource(r.data))) })).filter((r) => r.data != null && r.data !== "" && !(typeof r.data === "object" && Object.keys(r.data).length === 0)).sort((a, b) => String(a.name).localeCompare(String(b.name)));
3459
3716
  if (Array.isArray(s.definedNames)) s.definedNames = [...s.definedNames].sort((x, y) => String(x.id).localeCompare(String(y.id)));
3460
3717
  return sortDeep2(s);
3461
3718
  }
@@ -3467,7 +3724,8 @@ async function sheetsStateHash(snapshot) {
3467
3724
  }
3468
3725
 
3469
3726
  // src/univer/collab/sheets-ot/room.ts
3470
- var SHEETS_COLLAB_PROTO = 2;
3727
+ var SHEETS_COLLAB_PROTO = 3;
3728
+ var SHEETS_READABLE_PROTOS = [2, SHEETS_COLLAB_PROTO];
3471
3729
  var SHEETS_EDIT_GROUP = "sheets.edit";
3472
3730
  var flip2 = (side) => side === "left" ? "right" : "left";
3473
3731
  var isNoopSheetOp = (op) => op == null || op.length === 0;
@@ -3630,6 +3888,7 @@ function createSheetsOtAdapter(port, hooks = {}) {
3630
3888
  version: SHEET_TRANSFORMER_VERSION,
3631
3889
  transform: (x, y, side) => transformSheetOp(x, y, side),
3632
3890
  compose: (a, b) => [...a ?? [], ...b ?? []],
3891
+ isAnchorOnly: (op) => isSheetsAnchorOnlyOp(op),
3633
3892
  isNoop: isNoopSheetOp,
3634
3893
  encode: encodeSheetOp,
3635
3894
  decode: decodeSheetOp,
@@ -4149,6 +4408,12 @@ function univerSheetsOtPort(o) {
4149
4408
  try {
4150
4409
  const ok3 = cs.syncExecuteCommand(a.id, { ...json(a.params), unitId: u }, { fromCollab: true });
4151
4410
  if (ok3 === false) throw new Error(`"${m.id}" was refused by the editor`);
4411
+ if (a.id.startsWith("sheet.mutation.set-filter") || isStructuralMutation(a)) {
4412
+ try {
4413
+ cs.syncExecuteCommand("sheet.mutation.re-calc-filter", { unitId: u, subUnitId: a.params.subUnitId }, { onlyLocal: true });
4414
+ } catch {
4415
+ }
4416
+ }
4152
4417
  } finally {
4153
4418
  applying = false;
4154
4419
  }
@@ -4364,10 +4629,23 @@ async function loadSnapshotRow2(workbookId, ref) {
4364
4629
  if (!data) throw new Error(`The saved version ${ref} of this workbook is missing.`);
4365
4630
  return data.snapshot ?? null;
4366
4631
  }
4367
- async function workbookUsesOrderedRoom(workbookId, knob, isNewWorkbook) {
4632
+ async function deviceHoldsBuffer2(key) {
4633
+ if (!key || typeof indexedDB === "undefined") return false;
4634
+ try {
4635
+ const store = (0, import_collab6.createIndexedDbOfflineStore)();
4636
+ return await store.load(key) != null || await store.load((0, import_collab6.refusedKey)(key)) != null;
4637
+ } catch {
4638
+ return false;
4639
+ }
4640
+ }
4641
+ async function workbookUsesOrderedRoom(workbookId, knob, isNewWorkbook, offlineKey) {
4368
4642
  try {
4369
4643
  if (await (0, import_collab6.collabRoomExists)(db4(), workbookId)) return true;
4370
4644
  } catch (err) {
4645
+ if (await deviceHoldsBuffer2(offlineKey)) {
4646
+ console.warn("[workbook] could not ask whether this workbook has a co-editing room; unsent edits on this device say it does", err);
4647
+ return true;
4648
+ }
4371
4649
  console.warn("[workbook] could not ask whether this workbook has a co-editing room; opening the relay room", err);
4372
4650
  return false;
4373
4651
  }