@ai-matrx/office 0.8.44 → 0.8.46

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.
@@ -1165,26 +1165,77 @@ function rebaseUndoStack(items, remote, stack) {
1165
1165
  const first = stack === "undo" ? "undoMutations" : "redoMutations";
1166
1166
  const second = stack === "undo" ? "redoMutations" : "undoMutations";
1167
1167
  let dropped = 0;
1168
- for (let i = items.length - 1; i >= 0; i--) {
1168
+ let R = remote;
1169
+ for (let i = items.length - 1; i >= 0 && !isNoopDocsOp(R); i--) {
1169
1170
  const item = items[i];
1170
1171
  try {
1171
- const a = threadThrough(item[first], remote);
1172
+ const a = threadThrough(item[first], R);
1172
1173
  const b = threadThrough(item[second], a.after);
1173
1174
  if (a.next) item[first] = a.next;
1174
1175
  if (b.next) item[second] = b.next;
1176
+ R = a.after;
1175
1177
  } catch {
1176
1178
  items.splice(i, 1);
1177
1179
  dropped++;
1180
+ R = carryPast(item[first], R);
1178
1181
  }
1179
1182
  }
1180
1183
  return dropped;
1181
1184
  }
1185
+ function carryPast(list, remote) {
1186
+ let R = remote;
1187
+ for (const m of list ?? []) {
1188
+ if (m.id !== RICH_TEXT_EDITING || isNoopDocsOp(R)) continue;
1189
+ const own = m.params.actions;
1190
+ if (touchesPageSetup(own) && touchesPageSetup(R)) continue;
1191
+ R = transformDocsOp(R, own, "right").op;
1192
+ }
1193
+ return R;
1194
+ }
1195
+ var UNDO_COMMAND = "univer.command.undo";
1196
+ var REDO_COMMAND = "univer.command.redo";
1182
1197
  function openDocsOtRoom(o) {
1183
1198
  const { port } = o;
1184
1199
  let session = null;
1185
1200
  let composing = false;
1186
1201
  let queue = [];
1187
1202
  const drainWaiters = [];
1203
+ let replay = null;
1204
+ const noteHistoryStep = (m, inverse) => {
1205
+ const side = m.cmd === UNDO_COMMAND ? "undo" : m.cmd === REDO_COMMAND ? "redo" : null;
1206
+ if (!side) {
1207
+ replay = null;
1208
+ return;
1209
+ }
1210
+ for (const t of port.undoTargets()) {
1211
+ const stacks = undoStacksOf(t.service);
1212
+ const stack = stacks ? (side === "undo" ? stacks.undo : stacks.redo).get(t.unitId) : void 0;
1213
+ const item = stack?.[stack.length - 1];
1214
+ const list = item ? side === "undo" ? item.undoMutations : item.redoMutations : void 0;
1215
+ const k = list ? list.findIndex((x) => x.params === m.params) : -1;
1216
+ if (!item || !list || k < 0) continue;
1217
+ if (k === 0 || !replay || replay.item !== item || replay.side !== side) {
1218
+ const other = (side === "undo" ? item.redoMutations : item.undoMutations)?.[0]?.params ?? {};
1219
+ const { textRanges: _t, layoutState: _l, actions: _a, ...template } = other;
1220
+ replay = { item, side, inverses: [], template };
1221
+ }
1222
+ if (inverse === void 0 || list.some((x) => x.id !== RICH_TEXT_EDITING)) {
1223
+ replay = null;
1224
+ return;
1225
+ }
1226
+ replay.inverses.unshift(inverse);
1227
+ if (k === list.length - 1) {
1228
+ const rewritten = replay.inverses.filter((op) => !isNoopDocsOp(op)).map((op) => ({ id: RICH_TEXT_EDITING, params: { ...replay.template, segmentId: m.params?.segmentId ?? "", actions: op } }));
1229
+ if (rewritten.length) {
1230
+ if (side === "undo") item.redoMutations = rewritten;
1231
+ else item.undoMutations = rewritten;
1232
+ }
1233
+ replay = null;
1234
+ }
1235
+ return;
1236
+ }
1237
+ replay = null;
1238
+ };
1188
1239
  const notice = (n) => {
1189
1240
  try {
1190
1241
  o.onNotice?.(n);
@@ -1282,7 +1333,10 @@ function openDocsOtRoom(o) {
1282
1333
  }
1283
1334
  const p = m.params ?? {};
1284
1335
  const applied = p.actions ?? null;
1285
- if (isNoopDocsOp(applied)) return;
1336
+ if (isNoopDocsOp(applied)) {
1337
+ noteHistoryStep(m, null);
1338
+ return;
1339
+ }
1286
1340
  let op = normalizeDocsOp(structuredClone(applied));
1287
1341
  let inverse;
1288
1342
  try {
@@ -1290,6 +1344,7 @@ function openDocsOtRoom(o) {
1290
1344
  } catch {
1291
1345
  inverse = void 0;
1292
1346
  }
1347
+ noteHistoryStep(m, inverse === void 0 ? void 0 : normalizeDocsOp(inverse));
1293
1348
  if (queue.length) {
1294
1349
  inverse = void 0;
1295
1350
  const next = [];
@@ -2781,6 +2836,18 @@ function transformCell(X, Y4, side) {
2781
2836
  if (styleKeys(xs).length !== styleKeys(kept ?? {}).length) xLost = true;
2782
2837
  }
2783
2838
  }
2839
+ if (hasContent(X) && hasContent(Y4)) {
2840
+ const has = (s) => !!s && typeof s === "object" && "n" in s;
2841
+ const outS = out.s;
2842
+ if (side === "left" && !has(X.s) && has(Y4.s) && X.s !== null) {
2843
+ out.s = { ...outS && typeof outS === "object" ? outS : {}, n: null };
2844
+ } else if (side === "right" && outS && typeof outS === "object" && "n" in outS) {
2845
+ const rest = withoutStyleKeys(outS, /* @__PURE__ */ new Set(["n"]));
2846
+ if (rest) out.s = rest;
2847
+ else delete out.s;
2848
+ xLost = true;
2849
+ }
2850
+ }
2784
2851
  return { entries: Object.keys(out).length ? [out, ...tail] : tail, xLost, yLost };
2785
2852
  }
2786
2853
  function transformCellsOverCells(x, y, side) {
@@ -3869,6 +3936,12 @@ function rebaseSheetUndoStack(items, remote, unitId) {
3869
3936
  function createSheetsOtAdapter(port, hooks = {}) {
3870
3937
  let queue = [];
3871
3938
  let draining = false;
3939
+ const sameOp = (a, b) => JSON.stringify(canonicalKeys(a ?? [])) === JSON.stringify(canonicalKeys(b ?? []));
3940
+ const commutesWithHeld = (op) => queue.every((q) => {
3941
+ const a = transformSheetOp(op, q.op, "left");
3942
+ const b = transformSheetOp(q.op, op, "right");
3943
+ return !("barrier" in a) && !("barrier" in b) && sameOp(a.op, op) && sameOp(b.op, q.op);
3944
+ });
3872
3945
  const lazy = typeof port.beforeUndo === "function";
3873
3946
  let pending = [];
3874
3947
  let pendingBase = 0;
@@ -3941,15 +4014,16 @@ function createSheetsOtAdapter(port, hooks = {}) {
3941
4014
  decode: decodeSheetOp,
3942
4015
  apply(op) {
3943
4016
  if (isNoopSheetOp(op)) return true;
3944
- if (port.busy() || queue.length) {
3945
- queue.push(op);
4017
+ const hold = port.busy() || !!port.defers?.(op) || queue.length > 0 && !commutesWithHeld(op);
4018
+ if (hold) {
4019
+ queue.push({ op, rev: hooks.rev?.() ?? 0 });
3946
4020
  if (!draining) {
3947
4021
  draining = true;
3948
4022
  port.whenIdle(() => {
3949
4023
  draining = false;
3950
4024
  const held = queue;
3951
4025
  queue = [];
3952
- for (const q of held) applyNow(q);
4026
+ for (const q of held) applyNow(q.op);
3953
4027
  });
3954
4028
  }
3955
4029
  return true;
@@ -3974,9 +4048,9 @@ function createSheetsOtAdapter(port, hooks = {}) {
3974
4048
  async hash() {
3975
4049
  if (port.busy() || queue.length) {
3976
4050
  await new Promise((resolve) => {
3977
- const done = setTimeout(resolve, 5e3);
4051
+ const done = queue.length ? null : setTimeout(resolve, 5e3);
3978
4052
  port.whenIdle(() => {
3979
- clearTimeout(done);
4053
+ if (done) clearTimeout(done);
3980
4054
  setTimeout(resolve, 0);
3981
4055
  });
3982
4056
  });
@@ -3987,15 +4061,17 @@ function createSheetsOtAdapter(port, hooks = {}) {
3987
4061
  rebaseLocalOverHeld(local) {
3988
4062
  let op = local;
3989
4063
  const next = [];
4064
+ const overrode = [];
3990
4065
  for (const q of queue) {
3991
- const l2 = transformSheetOp(op, q, "left");
3992
- const q2 = transformSheetOp(q, op, "right");
4066
+ const l2 = transformSheetOp(op, q.op, "left");
4067
+ const q2 = transformSheetOp(q.op, op, "right");
3993
4068
  if ("barrier" in l2 || "barrier" in q2) return "barrier";
4069
+ if (l2.lost.length && q.rev > 0) overrode.push({ rev: q.rev, lost: l2.lost });
3994
4070
  op = l2.op ?? [];
3995
- if (q2.op?.length) next.push(q2.op);
4071
+ if (q2.op?.length) next.push({ op: q2.op, rev: q.rev });
3996
4072
  }
3997
4073
  queue = next;
3998
- return op;
4074
+ return { op, overrode };
3999
4075
  },
4000
4076
  clearHeld() {
4001
4077
  queue = [];
@@ -4006,7 +4082,6 @@ function createSheetsOtAdapter(port, hooks = {}) {
4006
4082
  function openSheetsOtRoom(o) {
4007
4083
  const { port } = o;
4008
4084
  let session = null;
4009
- const adapter = createSheetsOtAdapter(port);
4010
4085
  const notice = (n) => {
4011
4086
  try {
4012
4087
  o.onNotice?.(n);
@@ -4014,6 +4089,29 @@ function openSheetsOtRoom(o) {
4014
4089
  console.warn("[sheets-ot] notice handler failed", err);
4015
4090
  }
4016
4091
  };
4092
+ const adapter = createSheetsOtAdapter(port, { rev: () => session?.rev() ?? 0 });
4093
+ let healing = null;
4094
+ const HEALS = /* @__PURE__ */ new Set(["hash_mismatch", "save_hash_mismatch", "ack_mismatch"]);
4095
+ const screen = () => {
4096
+ try {
4097
+ const s = port.snapshot();
4098
+ return s ? canonicalSheetString(s) : null;
4099
+ } catch {
4100
+ return null;
4101
+ }
4102
+ };
4103
+ const onIncident = (i) => {
4104
+ if (HEALS.has(i.kind) && !healing) healing = { reason: i.kind, before: screen() };
4105
+ o.onIncident?.(i);
4106
+ };
4107
+ const onStatus = (st) => {
4108
+ if (st === "live" && healing) {
4109
+ const h = healing;
4110
+ healing = null;
4111
+ if (h.before !== null && screen() !== h.before) notice({ kind: "resynced", reason: h.reason });
4112
+ } else if (st === "read_only" || st === "closed") healing = null;
4113
+ o.onStatus?.(st);
4114
+ };
4017
4115
  const onLocal = (e) => {
4018
4116
  if (!session) return;
4019
4117
  if (e.kind === "not_shared") {
@@ -4033,6 +4131,7 @@ function openSheetsOtRoom(o) {
4033
4131
  }
4034
4132
  let op = e.mutations;
4035
4133
  let inverse = e.inverse;
4134
+ let overrode = [];
4036
4135
  if (adapter.held()) {
4037
4136
  inverse = void 0;
4038
4137
  const r = adapter.rebaseLocalOverHeld(op);
@@ -4041,10 +4140,11 @@ function openSheetsOtRoom(o) {
4041
4140
  session.rebuild("held_barrier");
4042
4141
  return;
4043
4142
  }
4044
- op = r;
4143
+ op = r.op;
4144
+ overrode = r.overrode;
4045
4145
  if (!op.length) return;
4046
4146
  }
4047
- if (!session.local(op, { ...inverse !== void 0 ? { inverse } : {}, label: e.label ?? SHEETS_EDIT_GROUP })) notice({ kind: "not_live" });
4147
+ if (!session.local(op, { ...inverse !== void 0 ? { inverse } : {}, label: e.label ?? SHEETS_EDIT_GROUP, ...overrode.length ? { overrode } : {} })) notice({ kind: "not_live" });
4048
4148
  };
4049
4149
  const unsubLocal = port.onLocal(onLocal);
4050
4150
  session = openOpSession2({
@@ -4054,8 +4154,8 @@ function openSheetsOtRoom(o) {
4054
4154
  clientId: o.clientId,
4055
4155
  ...o.presence ? { presence: o.presence } : {},
4056
4156
  onNotice: (n) => notice(n),
4057
- ...o.onIncident ? { onIncident: o.onIncident } : {},
4058
- ...o.onStatus ? { onStatus: o.onStatus } : {},
4157
+ onIncident,
4158
+ onStatus,
4059
4159
  ...o.offline ? { offline: o.offline } : {},
4060
4160
  ...o.onOffline ? { onOffline: o.onOffline } : {}
4061
4161
  });
@@ -4148,6 +4248,23 @@ function releaseUnitPluginState(cs, unitId, saved) {
4148
4248
  }
4149
4249
 
4150
4250
  // src/univer/collab/sheets-ot/univer-port.ts
4251
+ function filterServiceRange(service) {
4252
+ return (unitId, subUnitId) => {
4253
+ try {
4254
+ const r = service()?.getFilterModel(unitId, subUnitId)?.getRange();
4255
+ return r ? { startRow: r.startRow, endRow: r.endRow, startColumn: r.startColumn, endColumn: r.endColumn, ...r.rangeType !== void 0 ? { rangeType: r.rangeType } : {} } : null;
4256
+ } catch {
4257
+ return null;
4258
+ }
4259
+ };
4260
+ }
4261
+ function editorBridgeCell(bridge) {
4262
+ return () => {
4263
+ if (!bridge.isVisible()?.visible) return null;
4264
+ const at = bridge.getEditLocation();
4265
+ return at ? { sheetId: at.sheetId, row: at.row, col: at.column } : null;
4266
+ };
4267
+ }
4151
4268
  var COMMAND = 0;
4152
4269
  var MUTATION = 2;
4153
4270
  var VALUES = "sheet.mutation.set-range-values";
@@ -4155,6 +4272,7 @@ var ADD_MERGE = "sheet.mutation.add-worksheet-merge";
4155
4272
  var REMOVE_MERGE = "sheet.mutation.remove-worksheet-merge";
4156
4273
  var SHEET_NAME = "sheet.mutation.set-worksheet-name";
4157
4274
  var INSERT_SHEET = "sheet.mutation.insert-sheet";
4275
+ var REMOVE_SHEET2 = "sheet.mutation.remove-sheet";
4158
4276
  var FILTER_RANGE = "sheet.mutation.set-filter-range";
4159
4277
  var RESHAPE = /* @__PURE__ */ new Set(["sheet.mutation.set-worksheet-row-count", "sheet.mutation.set-worksheet-column-count", "sheet.mutation.remove-sheet", INSERT_SHEET]);
4160
4278
  var UNDO = "univer.command.undo";
@@ -4174,6 +4292,18 @@ function univerSheetsOtPort(o) {
4174
4292
  const tracker = { stack: [], settle: () => settle() };
4175
4293
  let group = null;
4176
4294
  let applying = false;
4295
+ let editorHold = false;
4296
+ const edited = () => {
4297
+ try {
4298
+ return o.cellEditor?.() ?? null;
4299
+ } catch {
4300
+ return null;
4301
+ }
4302
+ };
4303
+ const holding = () => {
4304
+ if (editorHold && !edited()) editorHold = false;
4305
+ return editorHold;
4306
+ };
4177
4307
  const unitId = () => o.workbook()?.getUnitId() ?? null;
4178
4308
  const mine = (params) => {
4179
4309
  const u = unitId();
@@ -4202,7 +4332,7 @@ function univerSheetsOtPort(o) {
4202
4332
  if (!u || !o.filterRange) return null;
4203
4333
  try {
4204
4334
  const r = o.filterRange(u, sheet);
4205
- return r ? { startRow: r.startRow, endRow: r.endRow, startColumn: r.startColumn, endColumn: r.endColumn } : null;
4335
+ return r ? { startRow: r.startRow, endRow: r.endRow, startColumn: r.startColumn, endColumn: r.endColumn, ...r.rangeType !== void 0 ? { rangeType: r.rangeType } : {} } : null;
4206
4336
  } catch {
4207
4337
  return null;
4208
4338
  }
@@ -4218,10 +4348,45 @@ function univerSheetsOtPort(o) {
4218
4348
  }
4219
4349
  }
4220
4350
  };
4351
+ const sweepRemovedSheetRefs = (g) => {
4352
+ const removed = g.mutations.filter((m) => m.id === REMOVE_SHEET2).map((m) => String(m.params.subUnitId ?? ""));
4353
+ const wb = o.workbook();
4354
+ const u = unitId();
4355
+ if (!removed.length || !wb || !u) return;
4356
+ const refSheets = {};
4357
+ for (const [id, name] of Object.entries(g.sheets)) refSheets[name] = id;
4358
+ for (const gone of removed) {
4359
+ const name = g.sheets[gone];
4360
+ if (!name) continue;
4361
+ for (const ws of wb.getSheets()) {
4362
+ const sheet = ws.getSheetId();
4363
+ const cells = {};
4364
+ ws.getCellMatrix?.().forValue((r, c, cell) => {
4365
+ const f = cell?.f;
4366
+ if (typeof f !== "string" || !f.includes(name)) return;
4367
+ const out = rewriteFormula(f, { ownSheet: sheet, refSheets }, { kind: "remove-sheet", sheet: gone });
4368
+ if (typeof out !== "string" && out.changed) (cells[r] ??= {})[c] = { f: out.text, si: null };
4369
+ });
4370
+ if (!Object.keys(cells).length) continue;
4371
+ applying = true;
4372
+ try {
4373
+ cs.syncExecuteCommand(VALUES, { unitId: u, subUnitId: sheet, cellValue: json(cells) });
4374
+ } finally {
4375
+ applying = false;
4376
+ }
4377
+ const done = {};
4378
+ for (const r of Object.keys(cells))
4379
+ for (const c of Object.keys(cells[r])) (done[r] ??= {})[c] = completeCellContent(cells[r][c], json(ws.getCellRaw(Number(r), Number(c)) ?? null));
4380
+ g.mutations.push({ id: VALUES, params: { subUnitId: sheet, cellValue: done } });
4381
+ g.inverses.push(void 0);
4382
+ }
4383
+ }
4384
+ };
4221
4385
  const flush = () => {
4222
4386
  const g = group;
4223
4387
  group = null;
4224
4388
  if (!g) return;
4389
+ if (!g.notShared) sweepRemovedSheetRefs(g);
4225
4390
  if (g.notShared) emit({ kind: "not_shared", mutationId: g.notShared, label: g.label });
4226
4391
  else if (g.mutations.length) {
4227
4392
  const mutations = annotateSheetOps(annotateFormulas(g.mutations, g.sheets, g.names), g.order);
@@ -4233,7 +4398,7 @@ function univerSheetsOtPort(o) {
4233
4398
  };
4234
4399
  function settle() {
4235
4400
  if (tracker.stack.length === 0) flush();
4236
- if (tracker.stack.length === 0 && !group) for (const fn of idle.splice(0)) fn();
4401
+ if (tracker.stack.length === 0 && !group && !holding()) for (const fn of idle.splice(0)) fn();
4237
4402
  }
4238
4403
  const before = cs.beforeCommandExecuted((info, options) => {
4239
4404
  if (info.id === UNDO || info.id === REDO) for (const fn of [...undoWatchers]) fn();
@@ -4247,6 +4412,7 @@ function univerSheetsOtPort(o) {
4247
4412
  const ws = o.workbook()?.getSheetBySheetId(String(p.subUnitId ?? ""));
4248
4413
  if (!ws) return;
4249
4414
  const record = { merges: json(ws.getMergeData() ?? []) };
4415
+ if (!group) record.lone = openGroup(null);
4250
4416
  if (info.id === VALUES) {
4251
4417
  record.cells = /* @__PURE__ */ new Map();
4252
4418
  const cells = p.cellValue ?? {};
@@ -4283,6 +4449,7 @@ function univerSheetsOtPort(o) {
4283
4449
  }
4284
4450
  };
4285
4451
  const after = cs.onCommandExecuted((info) => {
4452
+ if (editorHold && tracker.stack.length === 0 && !group && !edited()) settle();
4286
4453
  if (info.type !== COMMAND) return;
4287
4454
  const at = tracker.stack.lastIndexOf(info.id);
4288
4455
  if (at >= 0) tracker.stack.splice(at, 1);
@@ -4364,7 +4531,7 @@ function univerSheetsOtPort(o) {
4364
4531
  else {
4365
4532
  inv = {};
4366
4533
  if (CONTENT_KEYS.some((k) => k !== "t" && k in done)) Object.assign(inv, fullContent(p));
4367
- if ("s" in done) inv.s = p?.s ?? null;
4534
+ if ("s" in done) inv.s = inverseStyle(p?.s, done.s);
4368
4535
  }
4369
4536
  (invCells[r] ??= {})[c] = inv;
4370
4537
  }
@@ -4402,7 +4569,7 @@ function univerSheetsOtPort(o) {
4402
4569
  };
4403
4570
  const collab = cs.onMutationExecutedForCollab((info, options) => {
4404
4571
  if (applying || flagged(options) || !mine(info.params)) return;
4405
- if (!group) group = openGroup(null);
4572
+ if (!group) group = pre.get(info.params)?.lone ?? openGroup(null);
4406
4573
  const g = group;
4407
4574
  if (!g.notShared) {
4408
4575
  const r = capture(info);
@@ -4483,11 +4650,18 @@ function univerSheetsOtPort(o) {
4483
4650
  listeners.add(listener);
4484
4651
  return () => void listeners.delete(listener);
4485
4652
  },
4653
+ // the editor hold is not "busy": only the ops that touch its cell wait (defers), the rest apply live
4486
4654
  busy: () => tracker.stack.length > 0 || group !== null,
4655
+ defers(op) {
4656
+ const at = edited();
4657
+ if (!at || !op.some((m) => touchesEditedCell(m, at))) return false;
4658
+ editorHold = true;
4659
+ return true;
4660
+ },
4487
4661
  /** The outermost commands still running here (why the port is busy), for logs. */
4488
4662
  running: () => [...tracker.stack, ...group && tracker.stack.length === 0 ? ["(group)"] : []],
4489
4663
  whenIdle(fn) {
4490
- if (tracker.stack.length === 0 && !group) fn();
4664
+ if (tracker.stack.length === 0 && !group && !holding()) fn();
4491
4665
  else idle.push(fn);
4492
4666
  },
4493
4667
  applyRemote(m) {
@@ -4547,6 +4721,55 @@ function univerSheetsOtPort(o) {
4547
4721
  }
4548
4722
  };
4549
4723
  }
4724
+ function inverseStyle(prev, wrote) {
4725
+ if (!prev || typeof prev !== "object") return null;
4726
+ if (!wrote || typeof wrote !== "object") return prev;
4727
+ const out = { ...prev };
4728
+ for (const k of Object.keys(wrote)) if (!(k in out)) out[k] = null;
4729
+ return out;
4730
+ }
4731
+ function touchesEditedCell(m, at) {
4732
+ const p = m.params;
4733
+ const sheet = String(p.subUnitId ?? p.sheetId ?? "");
4734
+ if (sheet !== at.sheetId) return false;
4735
+ if (m.id === VALUES) {
4736
+ const row = p.cellValue?.[at.row];
4737
+ return !!row && Object.prototype.hasOwnProperty.call(row, at.col);
4738
+ }
4739
+ if (m.id === REMOVE_SHEET2) return true;
4740
+ if (m.id === "sheet.mutation.set-worksheet-row-count") return !(Number(p.rowCount) > at.row);
4741
+ if (m.id === "sheet.mutation.set-worksheet-column-count") return !(Number(p.columnCount) > at.col);
4742
+ const axis = axisOpOf(m);
4743
+ if (axis) {
4744
+ const i = axis.axis === "row" ? at.row : at.col;
4745
+ return mapIndex(axis.op, i) !== i;
4746
+ }
4747
+ const ranges = [];
4748
+ let unreadable = false;
4749
+ const walk = (v, depth) => {
4750
+ if (!v || typeof v !== "object" || depth > 6) return;
4751
+ if (Array.isArray(v)) {
4752
+ for (const x of v) walk(x, depth + 1);
4753
+ return;
4754
+ }
4755
+ const o = v;
4756
+ if (["startRow", "endRow", "startColumn", "endColumn"].some((k) => k in o)) {
4757
+ const r = o;
4758
+ if (![r.startRow, r.endRow, r.startColumn, r.endColumn].every((n) => typeof n === "number" && Number.isFinite(n)) && !(r.rangeType && r.rangeType > 0)) unreadable = true;
4759
+ else ranges.push(r);
4760
+ return;
4761
+ }
4762
+ if (typeof o.row === "number" && typeof o.col === "number") ranges.push({ startRow: o.row, endRow: o.row, startColumn: o.col, endColumn: o.col });
4763
+ for (const x of Object.values(o)) walk(x, depth + 1);
4764
+ };
4765
+ walk(p, 0);
4766
+ return unreadable || ranges.some((r) => covers(r, at));
4767
+ }
4768
+ function covers(r, at) {
4769
+ const rows = r.rangeType === 2 || r.rangeType === 3 || r.startRow <= at.row && at.row <= r.endRow;
4770
+ const cols = r.rangeType === 1 || r.rangeType === 3 || r.startColumn <= at.col && at.col <= r.endColumn;
4771
+ return rows && cols;
4772
+ }
4550
4773
  function fullContent(cell) {
4551
4774
  const out = {};
4552
4775
  for (const k of CONTENT_KEYS) out[k] = cell && cell[k] !== void 0 ? cell[k] : null;
@@ -4857,6 +5080,7 @@ export {
4857
5080
  DOCS_COLLAB_PROTO,
4858
5081
  DOCS_TRANSFORM_VERSION,
4859
5082
  DOC_LOCAL_KEYS,
5083
+ REDO_COMMAND,
4860
5084
  RICH_TEXT_EDITING,
4861
5085
  SENDER_VIEW_PARAMS,
4862
5086
  SHEETS_COLLAB_PROTO,
@@ -4864,6 +5088,7 @@ export {
4864
5088
  SHEETS_READABLE_PROTOS,
4865
5089
  SHEET_ROOM_EDITOR_PRESETS,
4866
5090
  SHEET_ROOM_PLUGIN_PACKAGES,
5091
+ UNDO_COMMAND,
4867
5092
  WorkbookCollabSession,
4868
5093
  applyDocsOp,
4869
5094
  asLoadedDocsSnapshot,
@@ -4879,7 +5104,9 @@ export {
4879
5104
  documentOtFactory,
4880
5105
  documentUsesOrderedRoom,
4881
5106
  dropEmptyStyleRetains,
5107
+ editorBridgeCell,
4882
5108
  encodeSheetOp,
5109
+ filterServiceRange,
4883
5110
  invertDocsOp,
4884
5111
  isCellEditorScratch,
4885
5112
  isNoopDocsOp,
@@ -4897,6 +5124,7 @@ export {
4897
5124
  startWorkbookOtRoom,
4898
5125
  stripSenderView,
4899
5126
  takeCovered,
5127
+ touchesEditedCell,
4900
5128
  transformDocsOp,
4901
5129
  transformSheetOp,
4902
5130
  transformTextX,