@ai-matrx/office 0.6.0 → 0.8.0

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.
@@ -90,7 +90,7 @@ var WorkbookCollabSession = class {
90
90
  this.awareness.on("change", this.awarenessObserver);
91
91
  }
92
92
  this.commandDisposer = this.options.commandService.onMutationExecutedForCollab(
93
- (info) => this.handleLocalMutation(info)
93
+ (info, options) => this.handleLocalMutation(info, options)
94
94
  );
95
95
  await this.provider.connect();
96
96
  await this.provider.ready();
@@ -238,8 +238,9 @@ var WorkbookCollabSession = class {
238
238
  return electCollabHost(states, this.options.uid, this.options.clientId, leader, opts.tabTieBreak ?? false);
239
239
  }
240
240
  // ─── internals ────────────────────────────────────────────────────────
241
- handleLocalMutation(info) {
241
+ handleLocalMutation(info, options) {
242
242
  if (this.muted > 0) return;
243
+ if (options?.onlyLocal) return;
243
244
  if (!this.options.forwardDocumentMutations && isCellEditorScratch(info)) return;
244
245
  if (info.params && typeof info.params === "object" && !Array.isArray(info.params) && remoteOriginOf(info.params) !== null) {
245
246
  return;
@@ -247,7 +248,7 @@ var WorkbookCollabSession = class {
247
248
  if (!this.doc) return;
248
249
  let safeParams;
249
250
  try {
250
- safeParams = info.params === void 0 || info.params === null ? null : JSON.parse(JSON.stringify(info.params));
251
+ safeParams = info.params === void 0 || info.params === null ? null : stripSenderView(JSON.parse(JSON.stringify(info.params)));
251
252
  } catch (err) {
252
253
  console.warn(
253
254
  `[collab] skipping non-serializable mutation "${info.id}" \u2014 peers will not receive it`,
@@ -321,6 +322,13 @@ var WorkbookCollabSession = class {
321
322
  }
322
323
  }
323
324
  };
325
+ var SENDER_VIEW_PARAMS = ["layoutState", "textRanges", "prevTextRanges"];
326
+ function stripSenderView(params) {
327
+ if (!params || typeof params !== "object" || Array.isArray(params)) return params;
328
+ const out = { ...params };
329
+ for (const key of SENDER_VIEW_PARAMS) delete out[key];
330
+ return out;
331
+ }
324
332
  function isCellEditorScratch(info) {
325
333
  return typeof info.id === "string" && info.id.startsWith("doc.mutation.");
326
334
  }
@@ -350,11 +358,1022 @@ function pickColor(uid) {
350
358
  }
351
359
  return CURSOR_PALETTE[Math.abs(h) % CURSOR_PALETTE.length] ?? "#ec4899";
352
360
  }
361
+
362
+ // src/univer/collab/docs-ot/transform.ts
363
+ import { JSONX, TextX, getBodySliceForSplitTextXAction, normalizeTextRuns, merge as univerMerge } from "@univerjs/core";
364
+ import * as json1 from "ot-json1";
365
+ var isTextX = (c) => !!c && typeof c === "object" && c.et === "text-x" && Array.isArray(c.e);
366
+ var clone = (v) => v == null ? v : structuredClone(v);
367
+ function tableZones(a) {
368
+ const out = [];
369
+ for (const t of a.body?.tables ?? []) {
370
+ if (t.startIndex >= 0 && t.endIndex <= a.len && t.endIndex > t.startIndex) out.push([t.startIndex, t.endIndex - 1]);
371
+ }
372
+ return out;
373
+ }
374
+ function unrewind(actions) {
375
+ if (!actions.some((a) => a.len < 0)) return actions;
376
+ const segs = [];
377
+ let cur = [];
378
+ let cursor = 0;
379
+ for (const a of actions) {
380
+ if (a.len < 0) {
381
+ if (a.t !== "r") return actions;
382
+ segs.push(cur);
383
+ cursor += a.len;
384
+ cur = cursor > 0 ? [{ t: "r", len: cursor }] : [];
385
+ continue;
386
+ }
387
+ cur.push(a);
388
+ if (a.t !== "d") cursor += a.len;
389
+ }
390
+ segs.push(cur);
391
+ const out = segs.reduce((acc, s) => TextX.compose(acc, s));
392
+ return out.some((a) => a.len < 0) ? actions : out;
393
+ }
394
+ function normText(actions) {
395
+ const out = [];
396
+ for (const a of unrewind(actions)) {
397
+ if (a.t === "d") {
398
+ if (!(a.len > 0)) continue;
399
+ const d = { t: "d", len: a.len };
400
+ if (a.valueRangeId !== void 0) d.valueRangeId = a.valueRangeId;
401
+ const tz = a.tz ?? tableZones(a);
402
+ if (tz.length) d.tz = tz;
403
+ out.push(d);
404
+ continue;
405
+ }
406
+ if (a.t === "r") {
407
+ const { oldBody: _oldBody, ...rest } = a;
408
+ out.push(rest);
409
+ continue;
410
+ }
411
+ out.push(a);
412
+ }
413
+ return out;
414
+ }
415
+ function normalizeDocsOp(op) {
416
+ if (op == null) return op;
417
+ const walk = (v) => {
418
+ if (Array.isArray(v)) return v.map(walk);
419
+ if (isTextX(v)) return { ...v, e: normText(v.e) };
420
+ return v;
421
+ };
422
+ return walk(op);
423
+ }
424
+ function dropEmptyStyleRetains(op) {
425
+ if (op == null) return op;
426
+ const walk = (v) => {
427
+ if (Array.isArray(v)) return v.map(walk);
428
+ if (isTextX(v)) {
429
+ return {
430
+ ...v,
431
+ e: v.e.map((a) => {
432
+ const b = a.body;
433
+ if (a.t !== "r" || !b || a.coverType === 1) return a;
434
+ const runs = (b.textRuns ?? []).filter((r) => r.ts && Object.keys(r.ts).length);
435
+ const other = Object.keys(b).filter(
436
+ (k) => k !== "textRuns" && k !== "dataStream" && !(Array.isArray(b[k]) && b[k].length === 0)
437
+ );
438
+ if (!runs.length && !other.length && !b.dataStream && !a.rangeUpdates?.length) return { t: "r", len: a.len };
439
+ if (b.textRuns === void 0 || runs.length === b.textRuns.length) return a;
440
+ return { ...a, body: { ...b, textRuns: runs } };
441
+ })
442
+ };
443
+ }
444
+ return v;
445
+ };
446
+ return walk(op);
447
+ }
448
+ var onlyDataStream = (body) => Object.keys(body).length === 1;
449
+ var shiftZones = (tz, by) => tz.map(([s, e]) => [s + by, e + by]);
450
+ function mergeZones(tz) {
451
+ const s = [...tz].sort((x, y) => x[0] - y[0]);
452
+ const out = [];
453
+ for (const z of s) {
454
+ const l = out[out.length - 1];
455
+ if (l && l[1] + 1 >= z[0]) l[1] = Math.max(l[1], z[1]);
456
+ else out.push([z[0], z[1]]);
457
+ }
458
+ return out;
459
+ }
460
+ function push(list, action) {
461
+ let index = list.length;
462
+ let last = list[index - 1];
463
+ const a = clone(action);
464
+ if (a.t === "r" && a.len === 0 && a.body == null && !a.rangeUpdates) return;
465
+ if (last) {
466
+ if (last.t === "d" && a.t === "d" && last.valueRangeId === a.valueRangeId) {
467
+ const tz = [...last.tz ?? [], ...shiftZones(a.tz ?? [], last.len)];
468
+ last.len += a.len;
469
+ if (tz.length) last.tz = mergeZones(tz);
470
+ return;
471
+ }
472
+ if (last.t === "d" && a.t === "i") {
473
+ index -= 1;
474
+ last = list[index - 1];
475
+ if (last == null) {
476
+ list.unshift(a);
477
+ return;
478
+ }
479
+ }
480
+ if (last.t === "r" && a.t === "r" && last.body == null && a.body == null && !last.rangeUpdates && !a.rangeUpdates) {
481
+ last.len += a.len;
482
+ return;
483
+ }
484
+ if (last.t === "i" && onlyDataStream(last.body) && a.t === "i" && onlyDataStream(a.body) && last.valueRangeId === a.valueRangeId) {
485
+ last.len += a.len;
486
+ last.body.dataStream += a.body.dataStream;
487
+ return;
488
+ }
489
+ }
490
+ if (index === list.length) list.push(a);
491
+ else list.splice(index, 0, a);
492
+ }
493
+ var BODY_FIELDS = [
494
+ "textRuns",
495
+ "paragraphs",
496
+ "customRanges",
497
+ "customBlocks",
498
+ "docxRawCustomBlocks",
499
+ "docxRawBlocks",
500
+ "docxExportExcludedRanges",
501
+ "customDecorations",
502
+ "tables",
503
+ "columnGroups",
504
+ "blockRanges"
505
+ ];
506
+ var uselessRetain = (a) => !a.rangeUpdates?.length && (a.body == null || BODY_FIELDS.every((k) => a.body[k] == null));
507
+ function trimEnd(list) {
508
+ while (list.length && list[list.length - 1].t === "r" && uselessRetain(list[list.length - 1])) list.pop();
509
+ return list;
510
+ }
511
+ var It = class {
512
+ constructor(a) {
513
+ this.a = a;
514
+ }
515
+ a;
516
+ i = 0;
517
+ off = 0;
518
+ peekType() {
519
+ return this.a[this.i]?.t ?? "r";
520
+ }
521
+ peekLength() {
522
+ const x = this.a[this.i];
523
+ return x ? x.len - this.off : Number.POSITIVE_INFINITY;
524
+ }
525
+ hasNext() {
526
+ return this.peekLength() < Number.POSITIVE_INFINITY;
527
+ }
528
+ /** An insert placed now would land strictly inside a table this delete removes whole. */
529
+ inZone() {
530
+ const x = this.a[this.i];
531
+ return x?.t === "d" && (x.tz ?? []).some(([s, e]) => s < this.off && this.off <= e);
532
+ }
533
+ next(length) {
534
+ let len = length || Number.POSITIVE_INFINITY;
535
+ const x = this.a[this.i];
536
+ if (!x) return { t: "r", len: Number.POSITIVE_INFINITY };
537
+ const offset = this.off;
538
+ if (len >= x.len - offset) {
539
+ len = x.len - offset;
540
+ this.i += 1;
541
+ this.off = 0;
542
+ } else this.off += len;
543
+ if (x.t === "d") {
544
+ const piece = { ...clone(x), len };
545
+ delete piece.tz;
546
+ const tz = (x.tz ?? []).map(([s, e]) => [Math.max(s, offset) - offset, Math.min(e, offset + len - 1) - offset]).filter(([s, e]) => s <= e);
547
+ if (tz.length) piece.tz = tz;
548
+ return piece;
549
+ }
550
+ if (x.t === "r" && x.body == null) return { ...clone(x), len };
551
+ return { ...clone(x), len, body: getBodySliceForSplitTextXAction(x.body, offset, offset + len, false) };
552
+ }
553
+ };
554
+ function transformTextRuns(originTextRuns, targetTextRuns, originCoverType, targetCoverType, transformType) {
555
+ if (originTextRuns == null || targetTextRuns == null) return targetTextRuns;
556
+ if (originTextRuns.length === 0 || targetTextRuns.length === 0) return [];
557
+ targetTextRuns = clone(targetTextRuns);
558
+ originTextRuns = clone(originTextRuns);
559
+ const out = [];
560
+ const updateLength = targetTextRuns.length;
561
+ const removeLength = originTextRuns.length;
562
+ let updateIndex = 0;
563
+ let removeIndex = 0;
564
+ let pending = null;
565
+ const flush = () => {
566
+ if (pending) {
567
+ out.push(pending);
568
+ pending = null;
569
+ return true;
570
+ }
571
+ return false;
572
+ };
573
+ while (updateIndex < updateLength && removeIndex < removeLength) {
574
+ const { st: updateSt, ed: updateEd, ts: targetStyle } = targetTextRuns[updateIndex];
575
+ const { st: removeSt, ed: removeEd, ts: originStyle, sId } = originTextRuns[removeIndex];
576
+ let newTs = {};
577
+ if (transformType === 0) {
578
+ newTs = { ...targetStyle };
579
+ if (originCoverType === 0 && targetCoverType === 1 && originStyle) newTs = Object.assign({}, originStyle, newTs);
580
+ } else {
581
+ newTs = { ...targetStyle };
582
+ if (originCoverType === 1) {
583
+ if (targetCoverType === 1) newTs = { ...originStyle };
584
+ else if (targetStyle && originStyle) {
585
+ for (const key of Object.keys(targetStyle)) if (originStyle[key] !== void 0) delete newTs[key];
586
+ }
587
+ } else if (targetCoverType === 1) {
588
+ if (originStyle) {
589
+ for (const key of Object.keys(originStyle)) if (originStyle[key] !== void 0) newTs[key] = originStyle[key];
590
+ }
591
+ } else if (originStyle) {
592
+ for (const key of Object.keys(originStyle)) if (newTs[key] !== void 0) delete newTs[key];
593
+ }
594
+ }
595
+ if (updateEd < removeSt) {
596
+ if (!flush()) out.push(targetTextRuns[updateIndex]);
597
+ updateIndex++;
598
+ } else if (removeEd < updateSt) {
599
+ if (!flush()) out.push(originTextRuns[removeIndex]);
600
+ removeIndex++;
601
+ } else {
602
+ out.push({ st: Math.max(updateSt, removeSt), ed: Math.min(updateEd, removeEd), ts: newTs, sId });
603
+ if (updateEd < removeEd) {
604
+ updateIndex++;
605
+ originTextRuns[removeIndex].st = updateEd;
606
+ if (originTextRuns[removeIndex].st === originTextRuns[removeIndex].ed) removeIndex++;
607
+ } else {
608
+ removeIndex++;
609
+ targetTextRuns[updateIndex].st = removeEd;
610
+ if (targetTextRuns[updateIndex].st === targetTextRuns[updateIndex].ed) updateIndex++;
611
+ }
612
+ const p = {
613
+ st: Math.min(updateEd, removeEd),
614
+ ed: Math.max(updateEd, removeEd),
615
+ ts: updateEd < removeEd ? { ...originStyle } : { ...targetStyle },
616
+ sId: updateEd < removeEd ? sId : void 0
617
+ };
618
+ pending = p.ed > p.st ? p : null;
619
+ }
620
+ }
621
+ flush();
622
+ const top = out[out.length - 1];
623
+ const updateLast = targetTextRuns[updateLength - 1];
624
+ const removeLast = originTextRuns[removeLength - 1];
625
+ if (top.ed !== Math.max(updateLast.ed, removeLast.ed)) out.push(updateLast.ed > removeLast.ed ? updateLast : removeLast);
626
+ return normalizeTextRuns(out, true);
627
+ }
628
+ function transformCustomRanges(o, t, originCoverType, _targetCoverType, transformType) {
629
+ if (o == null || t == null) return t;
630
+ if (o.length === 0 || t.length === 0) return [];
631
+ if (o.length > 1 || t.length > 1) throw new Error("CustomRanges is only supported transform for length one now.");
632
+ if (originCoverType === 1) return transformType === 1 ? [clone(o[0])] : [clone(t[0])];
633
+ const r = clone(t[0]);
634
+ if (transformType === 1) Object.assign(r, clone(o[0]));
635
+ return [r];
636
+ }
637
+ function transformParagraph(origin, target, originCoverType, targetCoverType, transformType) {
638
+ const paragraph = { startIndex: target.startIndex, paragraphId: target.paragraphId };
639
+ const oStyle = originCoverType === 1 ? origin.paragraphStyle ?? {} : origin.paragraphStyle;
640
+ const tStyle = targetCoverType === 1 ? target.paragraphStyle ?? {} : target.paragraphStyle;
641
+ if (tStyle) {
642
+ paragraph.paragraphStyle = clone(tStyle);
643
+ if (oStyle) {
644
+ const ps = paragraph.paragraphStyle;
645
+ if (originCoverType === 1) {
646
+ if (targetCoverType === 1) {
647
+ if (transformType === 1) paragraph.paragraphStyle = { ...oStyle };
648
+ } else if (transformType === 1) {
649
+ for (const k of Object.keys(oStyle)) if (oStyle[k] !== void 0) ps[k] = oStyle[k];
650
+ } else for (const k of Object.keys(oStyle)) if (ps[k] === void 0) ps[k] = oStyle[k];
651
+ } else if (targetCoverType === 1) {
652
+ if (transformType === 1) {
653
+ for (const k of Object.keys(oStyle)) if (oStyle[k] !== void 0) ps[k] = oStyle[k];
654
+ } else for (const k of Object.keys(oStyle)) if (ps[k] === void 0) ps[k] = oStyle[k];
655
+ } else if (transformType === 1) {
656
+ for (const k of Object.keys(oStyle)) if (ps[k] !== void 0) delete ps[k];
657
+ }
658
+ }
659
+ if (targetCoverType !== 1 && Object.keys(paragraph.paragraphStyle).length === 0) delete paragraph.paragraphStyle;
660
+ }
661
+ if (originCoverType === 1 && targetCoverType === 1) paragraph.bullet = transformType === 1 ? clone(origin.bullet) : clone(target.bullet);
662
+ else if (origin.bullet === void 0) paragraph.bullet = clone(target.bullet);
663
+ else if (originCoverType === 1 || targetCoverType === 1) paragraph.bullet = transformType === 0 && target.bullet ? clone(target.bullet) : clone(origin.bullet);
664
+ else if (transformType === 0 && target.bullet !== void 0) paragraph.bullet = clone(target.bullet);
665
+ if (paragraph.bullet === void 0) delete paragraph.bullet;
666
+ if (paragraph.paragraphId === void 0) delete paragraph.paragraphId;
667
+ return paragraph;
668
+ }
669
+ function transformCustomDecorations(origin, target) {
670
+ if (origin == null || target == null) return target;
671
+ if (origin.length === 0 || target.length === 0) return clone(target);
672
+ const out = [];
673
+ for (const d of target) {
674
+ let pushed = false;
675
+ for (const o of origin) {
676
+ if (o.id === d.id) {
677
+ if (o.type === 9999 || d.type === 9999) {
678
+ pushed = true;
679
+ out.push({ ...d, type: 9999 });
680
+ }
681
+ break;
682
+ }
683
+ }
684
+ if (!pushed) out.push(d);
685
+ }
686
+ return out;
687
+ }
688
+ function transformBlockRanges(thisBlockRanges, otherBlockRanges, priority) {
689
+ if (!thisBlockRanges.length) return otherBlockRanges;
690
+ if (!otherBlockRanges.length) return [];
691
+ return otherBlockRanges.map((o) => {
692
+ const t = thisBlockRanges.find((b) => b.blockId === o.blockId);
693
+ return t && priority ? univerMerge(o, t) : o;
694
+ });
695
+ }
696
+ function transformBody(thisAction, otherAction, priority) {
697
+ const { body: thisBody, coverType: thisCoverType = 0 } = thisAction;
698
+ const { body: otherBody, coverType: otherCoverType = 0 } = otherAction;
699
+ if (thisBody == null || thisBody.dataStream !== "" || otherBody == null || otherBody.dataStream !== "") {
700
+ throw new Error("Data stream is not supported in retain transform.");
701
+ }
702
+ const ret = { dataStream: "" };
703
+ const { textRuns: tr1, paragraphs: p1 = [], blockRanges: b1 = [], customRanges: c1, customDecorations: d1 } = thisBody;
704
+ const { textRuns: tr2, paragraphs: p2 = [], blockRanges: b2 = [], customRanges: c2, customDecorations: d2 } = otherBody;
705
+ const pt = priority ? 1 : 0;
706
+ const textRuns = transformTextRuns(tr1, tr2, thisCoverType, otherCoverType, pt);
707
+ if (textRuns) ret.textRuns = textRuns;
708
+ const customRanges = transformCustomRanges(c1, c2, thisCoverType, otherCoverType, pt);
709
+ if (customRanges) ret.customRanges = customRanges;
710
+ const customDecorations = transformCustomDecorations(d1, d2);
711
+ if (customDecorations) ret.customDecorations = customDecorations;
712
+ const paragraphs = [];
713
+ let i = 0;
714
+ let j = 0;
715
+ while (i < p1.length && j < p2.length) {
716
+ const a = p1[i];
717
+ const b = p2[j];
718
+ if (a.startIndex === b.startIndex) {
719
+ paragraphs.push(transformParagraph(a, b, thisCoverType, otherCoverType, pt));
720
+ i++;
721
+ j++;
722
+ } else if (a.startIndex < b.startIndex) i++;
723
+ else {
724
+ paragraphs.push(clone(b));
725
+ j++;
726
+ }
727
+ }
728
+ if (j < p2.length) paragraphs.push(...p2.slice(j));
729
+ if (paragraphs.length) ret.paragraphs = paragraphs;
730
+ const blockRanges = transformBlockRanges(b1, b2, priority);
731
+ if (blockRanges.length) ret.blockRanges = blockRanges;
732
+ return { coverType: otherCoverType, body: ret };
733
+ }
734
+ var valueIds = (acts) => new Set(acts.flatMap((a) => a.t !== "r" && a.valueRangeId ? [a.valueRangeId] : []));
735
+ function withoutValueRangeMetadata(acts, suppressed) {
736
+ return acts.map((a) => {
737
+ if (!a.body?.customRanges?.some((r) => suppressed.has(r.rangeId))) return a;
738
+ const body = { ...a.body, customRanges: a.body.customRanges.filter((r) => !suppressed.has(r.rangeId)) };
739
+ if (!body.customRanges.length) delete body.customRanges;
740
+ return { ...a, body };
741
+ });
742
+ }
743
+ function addedDecorations(y) {
744
+ const out = [];
745
+ let pos = 0;
746
+ for (const a of y) {
747
+ if (a.t === "d") continue;
748
+ if (a.t === "r") {
749
+ for (const d of a.body?.customDecorations ?? []) if (d.type !== 9999) out.push({ id: d.id, type: d.type, ds: pos + d.startIndex, de: pos + d.endIndex });
750
+ }
751
+ pos += a.len;
752
+ }
753
+ return out;
754
+ }
755
+ var hasRangeUpdates = (acts) => acts.some((a) => a.t === "r" && a.rangeUpdates?.length);
756
+ function transformTextX(xIn, yIn, side, lost = []) {
757
+ if (hasRangeUpdates(xIn) || hasRangeUpdates(yIn)) return TextX.transform(xIn, yIn, side);
758
+ const x = normText(xIn);
759
+ const y = normText(yIn);
760
+ const xLeft = side === "left";
761
+ const yIds = valueIds(y);
762
+ const conflicts = new Set([...valueIds(x)].filter((id) => yIds.has(id)));
763
+ const X = new It(conflicts.size && !xLeft ? withoutValueRangeMetadata(x, conflicts) : x);
764
+ const Y3 = new It(conflicts.size && xLeft ? withoutValueRangeMetadata(y, conflicts) : y);
765
+ const decos = addedDecorations(y).map((d) => ({ ...d, pieces: [] }));
766
+ const out = [];
767
+ let inPos = 0;
768
+ let outPos = 0;
769
+ while (X.hasNext() || Y3.hasNext()) {
770
+ if (X.peekType() === "i" && (xLeft || Y3.peekType() !== "i")) {
771
+ const a = X.next();
772
+ if (Y3.inZone()) {
773
+ lost.push({ rule: "R1", side: "insert", len: a.len, ...a.body?.dataStream !== void 0 ? { text: a.body.dataStream } : {} });
774
+ continue;
775
+ }
776
+ if (a.valueRangeId && conflicts.has(a.valueRangeId) && !xLeft) continue;
777
+ push(out, a);
778
+ outPos += a.len;
779
+ } else if (Y3.peekType() === "i") {
780
+ const b = Y3.next();
781
+ if (X.inZone()) {
782
+ push(out, { t: "d", len: b.len, tz: [[0, b.len - 1]] });
783
+ lost.push({ rule: "R1", side: "delete", len: b.len, ...b.body?.dataStream !== void 0 ? { text: b.body.dataStream } : {} });
784
+ inPos += b.len;
785
+ continue;
786
+ }
787
+ if (b.valueRangeId && conflicts.has(b.valueRangeId) && xLeft) push(out, { t: "d", len: b.len, valueRangeId: b.valueRangeId });
788
+ else {
789
+ push(out, { t: "r", len: b.len });
790
+ outPos += b.len;
791
+ }
792
+ inPos += b.len;
793
+ } else {
794
+ const len = Math.min(X.peekLength(), Y3.peekLength());
795
+ const a = X.next(len);
796
+ const b = Y3.next(len);
797
+ if (b.t === "d") continue;
798
+ if (a.t === "d") {
799
+ push(out, a);
800
+ inPos += len;
801
+ continue;
802
+ }
803
+ for (const d of decos) {
804
+ const s = Math.max(d.ds, inPos);
805
+ const e = Math.min(d.de, inPos + len - 1);
806
+ if (s <= e) d.pieces.push([outPos + s - inPos, outPos + e - inPos]);
807
+ }
808
+ let r = a;
809
+ if (a.body != null && b.body != null) {
810
+ const { coverType, body } = transformBody(b, a, !xLeft);
811
+ r = { ...a, t: "r", coverType, body };
812
+ }
813
+ if (r.coverType === 1 && r.body) {
814
+ const keep = [];
815
+ for (const d of decos) {
816
+ if (!(d.de >= inPos && d.ds < inPos + len)) continue;
817
+ const ahead = d.de >= inPos + len ? [[outPos + len + Math.max(d.ds, inPos + len) - (inPos + len), outPos + d.de - inPos]] : [];
818
+ for (const [s, e] of [...d.pieces, ...ahead]) keep.push({ id: d.id, type: d.type, startIndex: s - outPos, endIndex: e - outPos });
819
+ }
820
+ if (keep.length) r = { ...r, body: { ...r.body, customDecorations: [...r.body.customDecorations ?? [], ...keep] } };
821
+ }
822
+ push(out, r);
823
+ inPos += len;
824
+ outPos += len;
825
+ }
826
+ }
827
+ return trimEnd(out);
828
+ }
829
+ var sink = null;
830
+ var ours = {
831
+ name: "text-x",
832
+ uri: TextX.uri,
833
+ apply: (doc, actions) => TextX.apply(doc, actions),
834
+ compose: (a, b) => TextX.compose(a, b),
835
+ isNoop: (a) => TextX.isNoop(a),
836
+ invert: (a) => TextX.invert(a),
837
+ makeInvertible: (a, doc) => TextX.makeInvertible(a, doc),
838
+ transform: (x, y, side) => transformTextX(x, y, side, sink ?? [])
839
+ };
840
+ function transformDocsOp(x, y, side) {
841
+ if (x == null) return { op: null, lost: [] };
842
+ if (y == null) return { op: x, lost: [] };
843
+ const lost = [];
844
+ sink = lost;
845
+ json1.type.registerSubtype(ours);
846
+ try {
847
+ const op = json1.type.transformNoConflict(normalizeDocsOp(x), normalizeDocsOp(y), side);
848
+ return { op: dropEmptyStyleRetains(op), lost };
849
+ } finally {
850
+ json1.type.registerSubtype(TextX);
851
+ sink = null;
852
+ }
853
+ }
854
+ function composeDocsOps(a, b) {
855
+ if (a == null) return b;
856
+ if (b == null) return a;
857
+ json1.type.registerSubtype(TextX);
858
+ return json1.type.compose(a, b);
859
+ }
860
+ function isNoopDocsOp(op) {
861
+ return op == null || Array.isArray(op) && op.length === 0 || json1.type.isNoop(op);
862
+ }
863
+ function applyDocsOp(doc, op) {
864
+ if (isNoopDocsOp(op)) return doc;
865
+ return JSONX.apply(structuredClone(doc), op);
866
+ }
867
+ function invertDocsOp(op, preDoc) {
868
+ if (isNoopDocsOp(op)) return null;
869
+ return JSONX.invertWithDoc(structuredClone(op), preDoc);
870
+ }
871
+ var DOCS_TRANSFORM_VERSION = "univer-1.0.4+docs-ot-r6";
872
+
873
+ // src/univer/collab/docs-ot/state-hash.ts
874
+ var DOC_LOCAL_KEYS = ["rev", "__matrxCollabCovered", "__collab", "disabled", "layoutState", "textRanges", "selections"];
875
+ function sortDeep(v) {
876
+ if (Array.isArray(v)) return v.map(sortDeep);
877
+ if (v && typeof v === "object") {
878
+ const out = {};
879
+ for (const k of Object.keys(v).sort()) {
880
+ const x = v[k];
881
+ if (x === void 0 || x === null) continue;
882
+ if (Array.isArray(x) && x.length === 0) continue;
883
+ if (x && typeof x === "object" && !Array.isArray(x) && Object.keys(x).length === 0) continue;
884
+ out[k] = sortDeep(x);
885
+ }
886
+ return out;
887
+ }
888
+ return v;
889
+ }
890
+ var sameTs = (a, b) => JSON.stringify(sortDeep(a ?? {})) === JSON.stringify(sortDeep(b ?? {}));
891
+ function canonicalRuns(runs) {
892
+ const out = [];
893
+ for (const r of [...runs ?? []].sort((x, y) => x.st - y.st)) {
894
+ if (r.ed <= r.st) continue;
895
+ const ts = sortDeep(r.ts ?? {});
896
+ if (Object.keys(ts).length === 0) continue;
897
+ const last = out[out.length - 1];
898
+ if (last && last.ed === r.st && sameTs(last.ts, ts)) last.ed = r.ed;
899
+ else out.push({ st: r.st, ed: r.ed, ts });
900
+ }
901
+ return out;
902
+ }
903
+ function foldPieces(items, keyOf) {
904
+ const groups = /* @__PURE__ */ new Map();
905
+ for (const it of items ?? []) {
906
+ const k = keyOf(it);
907
+ const g = groups.get(k) ?? [];
908
+ g.push(it);
909
+ groups.set(k, g);
910
+ }
911
+ const out = [];
912
+ for (const list of groups.values()) {
913
+ list.sort((a, b) => a.startIndex - b.startIndex);
914
+ let cur = null;
915
+ for (const it of list) {
916
+ if (cur && cur.endIndex + 1 >= it.startIndex) cur.endIndex = Math.max(cur.endIndex, it.endIndex);
917
+ else {
918
+ if (cur) out.push(cur);
919
+ cur = { ...it };
920
+ }
921
+ }
922
+ if (cur) out.push(cur);
923
+ }
924
+ return out;
925
+ }
926
+ var rootId = (id) => String(id).split("$")[0];
927
+ function canonicalBody(body) {
928
+ if (!body) return body;
929
+ const b = { ...body };
930
+ b.textRuns = canonicalRuns(b.textRuns);
931
+ if (Array.isArray(b.paragraphs)) b.paragraphs = b.paragraphs.map(({ paragraphId: _p, ...p }) => p);
932
+ b.customRanges = foldPieces(b.customRanges, (r) => JSON.stringify([rootId(r.rangeId), r.rangeType, sortDeep(r.properties ?? {})])).map((r) => ({
933
+ ...r,
934
+ rangeId: rootId(r.rangeId)
935
+ }));
936
+ b.customDecorations = foldPieces(b.customDecorations, (d) => JSON.stringify([d.id, d.type]));
937
+ for (const k of ["paragraphs", "customRanges", "customBlocks", "tables", "sectionBreaks", "customDecorations"]) {
938
+ if (Array.isArray(b[k])) {
939
+ b[k] = [...b[k]].sort(
940
+ (x, y) => (x.startIndex ?? 0) - (y.startIndex ?? 0) || String(x.rangeId ?? x.blockId ?? x.tableId ?? "").localeCompare(String(y.rangeId ?? y.blockId ?? y.tableId ?? ""))
941
+ );
942
+ }
943
+ }
944
+ return b;
945
+ }
946
+ function canonicalDocsSnapshot(snapshot) {
947
+ const s = structuredClone(snapshot ?? {});
948
+ delete s.id;
949
+ for (const k of DOC_LOCAL_KEYS) delete s[k];
950
+ s.body = canonicalBody(s.body);
951
+ for (const seg of ["headers", "footers", "notes"]) {
952
+ if (!s[seg]) continue;
953
+ for (const id of Object.keys(s[seg])) s[seg][id] = { ...s[seg][id], body: canonicalBody(s[seg][id].body) };
954
+ }
955
+ return sortDeep(s);
956
+ }
957
+ var canonicalDocsString = (snapshot) => JSON.stringify(canonicalDocsSnapshot(snapshot));
958
+ async function docsStateHash(snapshot) {
959
+ const bytes = new TextEncoder().encode(canonicalDocsString(snapshot));
960
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
961
+ return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("");
962
+ }
963
+ function stampDeterministicIds(snapshot) {
964
+ const s = structuredClone(snapshot);
965
+ const stamp = (body, scope) => {
966
+ if (!body) return;
967
+ for (const p of body.paragraphs ?? []) if (!p.paragraphId) p.paragraphId = `p_${scope}${p.startIndex}`;
968
+ for (const sb of body.sectionBreaks ?? []) if (!sb.sectionId) sb.sectionId = `s_${scope}${sb.startIndex}`;
969
+ };
970
+ stamp(s?.body, "");
971
+ for (const seg of ["headers", "footers", "notes"]) for (const id of Object.keys(s?.[seg] ?? {})) stamp(s[seg][id]?.body, `${id}_`);
972
+ return s;
973
+ }
974
+
975
+ // src/univer/collab/docs-ot/room.ts
976
+ import { isOpBarrier, openOpSession } from "@ai-matrx/data/realtime/collab";
977
+ var RICH_TEXT_EDITING = "doc.mutation.rich-text-editing";
978
+ var DOCS_COLLAB_PROTO = 1;
979
+ function branches(op) {
980
+ if (!Array.isArray(op) || op.length === 0) return [];
981
+ return Array.isArray(op[0]) ? op : [op];
982
+ }
983
+ var touchesPageSetup = (op) => branches(op).some((b) => b[0] === "documentStyle");
984
+ function segmentOf(branch) {
985
+ return (branch[0] === "headers" || branch[0] === "footers") && typeof branch[1] === "string" ? branch[1] : "";
986
+ }
987
+ function undoStacksOf(service) {
988
+ const s = service;
989
+ if (!s || !(s._undoStacks instanceof Map) || !(s._redoStacks instanceof Map)) return null;
990
+ return { undo: s._undoStacks, redo: s._redoStacks };
991
+ }
992
+ function rebaseUndoStack(items, remote) {
993
+ let dropped = 0;
994
+ for (let i = items.length - 1; i >= 0; i--) {
995
+ const item = items[i];
996
+ let ok = true;
997
+ for (const list of [item.undoMutations, item.redoMutations]) {
998
+ for (const m of list ?? []) {
999
+ if (m.id !== RICH_TEXT_EDITING) continue;
1000
+ try {
1001
+ if (touchesPageSetup(m.params.actions) && touchesPageSetup(remote)) throw new Error("page setup");
1002
+ const r = transformDocsOp(m.params.actions, remote, "left");
1003
+ if (isNoopDocsOp(r.op)) ok = false;
1004
+ else {
1005
+ m.params = { ...m.params, actions: r.op };
1006
+ delete m.params.textRanges;
1007
+ delete m.params.layoutState;
1008
+ }
1009
+ } catch {
1010
+ ok = false;
1011
+ }
1012
+ }
1013
+ }
1014
+ if (!ok) {
1015
+ items.splice(i, 1);
1016
+ dropped++;
1017
+ }
1018
+ }
1019
+ return dropped;
1020
+ }
1021
+ function openDocsOtRoom(o) {
1022
+ const { port } = o;
1023
+ let session = null;
1024
+ let composing = false;
1025
+ let queue = [];
1026
+ const drainWaiters = [];
1027
+ const notice = (n) => {
1028
+ try {
1029
+ o.onNotice?.(n);
1030
+ } catch (err) {
1031
+ console.warn("[docs-ot] notice handler failed", err);
1032
+ }
1033
+ };
1034
+ const applyNow = (op) => {
1035
+ for (const b of branches(op)) {
1036
+ const params = { segmentId: segmentOf(b), actions: b };
1037
+ port.applyRemote(RICH_TEXT_EDITING, params);
1038
+ }
1039
+ for (const t of port.undoTargets()) {
1040
+ const stacks = undoStacksOf(t.service);
1041
+ if (!stacks) continue;
1042
+ for (const m of [stacks.undo, stacks.redo]) {
1043
+ const items = m.get(t.unitId);
1044
+ if (items?.length) rebaseUndoStack(items, op);
1045
+ }
1046
+ }
1047
+ port.markDirty();
1048
+ };
1049
+ const drain = () => {
1050
+ const held = queue;
1051
+ queue = [];
1052
+ try {
1053
+ for (const op of held) applyNow(op);
1054
+ } catch (err) {
1055
+ console.warn("[docs-ot] a held remote edit failed after composition; reloading this seat", err);
1056
+ session?.rebuild("ime_drain_failed");
1057
+ }
1058
+ for (const w of drainWaiters.splice(0)) w();
1059
+ };
1060
+ const adapter = {
1061
+ version: DOCS_TRANSFORM_VERSION,
1062
+ transform(x, y, side) {
1063
+ if (x != null && y != null && (touchesPageSetup(x) || touchesPageSetup(y))) return { barrier: true, reason: "page_setup" };
1064
+ const r = transformDocsOp(x, y, side);
1065
+ return { op: isNoopDocsOp(r.op) ? null : r.op, lost: r.lost };
1066
+ },
1067
+ compose: (a, b) => composeDocsOps(a, b),
1068
+ isNoop: (op) => isNoopDocsOp(op),
1069
+ encode: (op) => [{ cmd: "docs.edit", mutations: [{ id: RICH_TEXT_EDITING, params: { segmentId: "", actions: op } }] }],
1070
+ decode(groups) {
1071
+ let op = null;
1072
+ for (const g of groups) {
1073
+ for (const m of g.mutations) {
1074
+ if (m.id !== RICH_TEXT_EDITING) throw new Error(`a Docs room cannot apply ${m.id}`);
1075
+ op = composeDocsOps(op, m.params.actions ?? null);
1076
+ }
1077
+ }
1078
+ return op;
1079
+ },
1080
+ apply(op) {
1081
+ if (isNoopDocsOp(op)) return true;
1082
+ if (composing) {
1083
+ queue.push(op);
1084
+ return true;
1085
+ }
1086
+ applyNow(op);
1087
+ return true;
1088
+ },
1089
+ async load(snapshot) {
1090
+ const next = stampDeterministicIds(snapshot ?? {});
1091
+ queue = [];
1092
+ const current = port.snapshot();
1093
+ if (current && canonicalDocsString(current) === canonicalDocsString(next)) return;
1094
+ port.load(next);
1095
+ for (const t of port.undoTargets()) {
1096
+ const stacks = undoStacksOf(t.service);
1097
+ stacks?.undo.delete(t.unitId);
1098
+ stacks?.redo.delete(t.unitId);
1099
+ }
1100
+ },
1101
+ snapshot: () => port.snapshot(),
1102
+ async hash() {
1103
+ if (composing || queue.length) {
1104
+ await new Promise((resolve) => {
1105
+ drainWaiters.push(resolve);
1106
+ setTimeout(resolve, 5e3);
1107
+ });
1108
+ }
1109
+ return docsStateHash(port.snapshot());
1110
+ }
1111
+ };
1112
+ const onLocal = (m) => {
1113
+ if (!session) return;
1114
+ if (m.id !== RICH_TEXT_EDITING) {
1115
+ if (!m.content) return;
1116
+ notice({ kind: "not_shared", mutationId: m.id });
1117
+ session.rebuild(`not_shared:${m.id}`);
1118
+ return;
1119
+ }
1120
+ const p = m.params ?? {};
1121
+ const applied = p.actions ?? null;
1122
+ if (isNoopDocsOp(applied)) return;
1123
+ let op = normalizeDocsOp(structuredClone(applied));
1124
+ let inverse;
1125
+ try {
1126
+ inverse = m.pre != null ? invertDocsOp(applied, m.pre) : void 0;
1127
+ } catch {
1128
+ inverse = void 0;
1129
+ }
1130
+ if (queue.length) {
1131
+ inverse = void 0;
1132
+ const next = [];
1133
+ for (const q of queue) {
1134
+ const l2 = adapter.transform(op, q, "left");
1135
+ const q2 = adapter.transform(q, op, "right");
1136
+ if (isOpBarrier(l2) || isOpBarrier(q2)) {
1137
+ queue = [];
1138
+ session.rebuild("ime_barrier");
1139
+ return;
1140
+ }
1141
+ op = l2.op;
1142
+ next.push(q2.op);
1143
+ }
1144
+ queue = next.filter((q) => !isNoopDocsOp(q));
1145
+ if (isNoopDocsOp(op)) return;
1146
+ }
1147
+ if (!session.local(op, { ...inverse !== void 0 ? { inverse } : {}, label: m.cmd ?? RICH_TEXT_EDITING })) notice({ kind: "not_live" });
1148
+ };
1149
+ const unsubLocal = port.onLocal(onLocal);
1150
+ const target = o.compositionTarget === void 0 ? typeof document !== "undefined" ? document : null : o.compositionTarget;
1151
+ const onStart = () => {
1152
+ composing = true;
1153
+ };
1154
+ const onEnd = () => {
1155
+ composing = false;
1156
+ setTimeout(() => {
1157
+ if (!composing) drain();
1158
+ }, 0);
1159
+ };
1160
+ target?.addEventListener("compositionstart", onStart, true);
1161
+ target?.addEventListener("compositionend", onEnd, true);
1162
+ session = openOpSession({
1163
+ transport: o.transport,
1164
+ adapter,
1165
+ proto: DOCS_COLLAB_PROTO,
1166
+ clientId: o.clientId,
1167
+ ...o.presence ? { presence: o.presence } : {},
1168
+ onNotice: (n) => notice(n),
1169
+ ...o.onIncident ? { onIncident: o.onIncident } : {},
1170
+ ...o.onStatus ? { onStatus: o.onStatus } : {}
1171
+ });
1172
+ const isSaver = () => {
1173
+ if (!o.presence) return true;
1174
+ return o.presence.peers().every((p) => p.clientId === o.clientId || p.clientId > o.clientId);
1175
+ };
1176
+ return {
1177
+ session,
1178
+ isSaver,
1179
+ async write(reason) {
1180
+ if (!session) return false;
1181
+ if (reason !== "manual" && !isSaver()) return false;
1182
+ const out = await session.save();
1183
+ if (out.saved) return true;
1184
+ if (out.reason === "not_quiet" || out.reason === "changed") setTimeout(() => port.markDirty(), 1500);
1185
+ return false;
1186
+ },
1187
+ async replace(snapshot) {
1188
+ port.load(stampDeterministicIds(snapshot));
1189
+ const loaded = port.snapshot();
1190
+ if (!loaded) throw new Error("The document is not open in this tab.");
1191
+ const stateHash = await docsStateHash(loaded);
1192
+ await o.replace({ snapshot: loaded, stateHash, clientId: o.clientId });
1193
+ },
1194
+ stop() {
1195
+ unsubLocal();
1196
+ target?.removeEventListener("compositionstart", onStart, true);
1197
+ target?.removeEventListener("compositionend", onEnd, true);
1198
+ session?.close();
1199
+ }
1200
+ };
1201
+ }
1202
+
1203
+ // src/docs/document-ot-room.ts
1204
+ import * as Y2 from "yjs";
1205
+ import { Awareness as Awareness2 } from "y-protocols/awareness";
1206
+ import {
1207
+ awarenessOpPresence,
1208
+ collabReplace,
1209
+ collabRoomExists,
1210
+ SupabaseYjsProvider,
1211
+ supabaseOpTransport
1212
+ } from "@ai-matrx/data/realtime/collab";
1213
+
1214
+ // src/docs/document-service.ts
1215
+ import { requireOrganizationContext } from "@ai-matrx/api";
1216
+ import { getClaimsUser } from "@ai-matrx/auth";
1217
+ import { readAllRows, tryWriteOne, writeOneRow } from "@ai-matrx/data/db";
1218
+
1219
+ // src/docs/ports.ts
1220
+ var SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.office.docs-host");
1221
+ var slot = () => {
1222
+ const g = globalThis;
1223
+ return g[SLOT] ??= {};
1224
+ };
1225
+ function getDocsHost() {
1226
+ const ports = slot().ports;
1227
+ if (!ports) throw new Error("@ai-matrx/office/docs: configureDocsHost(ports) was not called before the document service ran.");
1228
+ return ports;
1229
+ }
1230
+
1231
+ // src/docs/document-service.ts
1232
+ var db = () => getDocsHost().getSupabase();
1233
+ async function getLatestDocumentSnapshot(documentId) {
1234
+ const { data, error } = await db().schema("workbench").from("udt_document_snapshots").select("*").eq("document_id", documentId).order("created_at", { ascending: false }).limit(1).maybeSingle();
1235
+ if (error) return { success: false, error: error.message };
1236
+ return { success: true, data: data ?? null };
1237
+ }
1238
+ async function saveDocumentSnapshot(args) {
1239
+ const { data: userData } = await getClaimsUser(db());
1240
+ const { data, error } = await db().schema("workbench").from("udt_document_snapshots").insert({
1241
+ document_id: args.documentId,
1242
+ snapshot: args.snapshot,
1243
+ label: args.label ?? null,
1244
+ origin: args.origin ?? "autosave",
1245
+ created_by: userData?.user?.id ?? null
1246
+ }).select("*").single();
1247
+ if (error) return { success: false, error: error.message };
1248
+ await db().schema("workbench").from("udt_documents").update({ updated_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", args.documentId);
1249
+ return { success: true, data };
1250
+ }
1251
+
1252
+ // src/docs/document-ot-room.ts
1253
+ var db2 = () => getDocsHost().getSupabase();
1254
+ async function loadSnapshotRow(documentId, ref) {
1255
+ if (ref === "none") {
1256
+ const res = await getLatestDocumentSnapshot(documentId);
1257
+ if (!res.success) throw new Error(res.error);
1258
+ return res.data?.snapshot ?? null;
1259
+ }
1260
+ const { data, error } = await getDocsHost().getSupabase().schema("workbench").from("udt_document_snapshots").select("snapshot").eq("id", ref).maybeSingle();
1261
+ if (error) throw new Error(error.message);
1262
+ if (!data) throw new Error(`The saved version ${ref} of this document is missing.`);
1263
+ return data.snapshot ?? null;
1264
+ }
1265
+ async function documentUsesOrderedRoom(documentId, knob, isNewDocument) {
1266
+ try {
1267
+ if (await collabRoomExists(db2(), documentId)) return true;
1268
+ } catch (err) {
1269
+ console.warn("[document] could not ask whether this document has a co-editing room; opening the relay room", err);
1270
+ return false;
1271
+ }
1272
+ if (knob === "all") return true;
1273
+ if (knob === "new") return isNewDocument();
1274
+ return false;
1275
+ }
1276
+ function pickColor2(uid) {
1277
+ const palette = ["#ef4444", "#f59e0b", "#10b981", "#3b82f6", "#8b5cf6", "#ec4899", "#14b8a6", "#f97316"];
1278
+ let h = 2166136261;
1279
+ for (let i = 0; i < uid.length; i++) {
1280
+ h ^= uid.charCodeAt(i);
1281
+ h = Math.imul(h, 16777619);
1282
+ }
1283
+ return palette[Math.abs(h) % palette.length] ?? "#ec4899";
1284
+ }
1285
+ function documentOtFactory(o) {
1286
+ return async (port, onAwareness) => {
1287
+ const latest = await getLatestDocumentSnapshot(o.documentId);
1288
+ if (!latest.success) throw new Error(latest.error);
1289
+ if (!latest.data) {
1290
+ const mounted = port.snapshot();
1291
+ if (mounted) {
1292
+ const saved = await saveDocumentSnapshot({ documentId: o.documentId, snapshot: mounted, origin: "autosave" });
1293
+ if (!saved.success) throw new Error(saved.error);
1294
+ }
1295
+ }
1296
+ const doc = new Y2.Doc();
1297
+ const awareness = new Awareness2(doc);
1298
+ awareness.setLocalState({ uid: o.uid, clientId: o.clientId, name: o.displayName ?? o.uid.slice(0, 8), color: pickColor2(o.uid), ts: Date.now() });
1299
+ const publishAwareness = () => onAwareness({ states: new Map(awareness.getStates()), selfUid: o.uid });
1300
+ awareness.on("change", publishAwareness);
1301
+ const provider = new SupabaseYjsProvider({
1302
+ workbookId: o.documentId,
1303
+ channelPrefix: "document",
1304
+ clientId: o.clientId,
1305
+ doc,
1306
+ awareness,
1307
+ ...o.readAntiEntropyIntervalMs ? { readAntiEntropyIntervalMs: o.readAntiEntropyIntervalMs } : {}
1308
+ });
1309
+ await provider.connect();
1310
+ publishAwareness();
1311
+ const client = db2();
1312
+ const room = openDocsOtRoom({
1313
+ port,
1314
+ clientId: o.clientId,
1315
+ presence: awarenessOpPresence(awareness),
1316
+ transport: supabaseOpTransport({
1317
+ client,
1318
+ roomId: o.documentId,
1319
+ kind: "univer_doc",
1320
+ store: {
1321
+ loadSnapshot: (ref) => loadSnapshotRow(o.documentId, ref),
1322
+ async writeSnapshot(snapshot) {
1323
+ const res = await saveDocumentSnapshot({ documentId: o.documentId, snapshot, origin: "autosave" });
1324
+ if (!res.success) throw new Error(res.error);
1325
+ return res.data.id;
1326
+ }
1327
+ }
1328
+ }),
1329
+ replace: ({ snapshot, stateHash, clientId }) => collabReplace(client, { roomId: o.documentId, snapshot, stateHash, origin: "restore", clientId }),
1330
+ ...o.onNotice ? { onNotice: o.onNotice } : {},
1331
+ ...o.onIncident ? { onIncident: o.onIncident } : {},
1332
+ ...o.onStatus ? { onStatus: o.onStatus } : {}
1333
+ });
1334
+ await room.session.ready;
1335
+ return {
1336
+ isSaver: () => room.isSaver(),
1337
+ write: (reason) => room.write(reason),
1338
+ replace: (snapshot) => room.replace(snapshot),
1339
+ stop: () => {
1340
+ room.stop();
1341
+ awareness.off("change", publishAwareness);
1342
+ provider.disconnect();
1343
+ awareness.destroy();
1344
+ doc.destroy();
1345
+ }
1346
+ };
1347
+ };
1348
+ }
353
1349
  export {
354
1350
  COLLAB_COVERED_KEY,
1351
+ DOCS_COLLAB_PROTO,
1352
+ DOCS_TRANSFORM_VERSION,
1353
+ DOC_LOCAL_KEYS,
1354
+ RICH_TEXT_EDITING,
1355
+ SENDER_VIEW_PARAMS,
355
1356
  WorkbookCollabSession,
1357
+ applyDocsOp,
1358
+ canonicalDocsSnapshot,
1359
+ canonicalDocsString,
1360
+ composeDocsOps,
1361
+ docsStateHash,
1362
+ documentOtFactory,
1363
+ documentUsesOrderedRoom,
1364
+ dropEmptyStyleRetains,
1365
+ invertDocsOp,
356
1366
  isCellEditorScratch,
1367
+ isNoopDocsOp,
1368
+ normalizeDocsOp,
1369
+ openDocsOtRoom,
1370
+ rebaseUndoStack,
357
1371
  stampCovered,
358
- takeCovered
1372
+ stampDeterministicIds,
1373
+ stripSenderView,
1374
+ takeCovered,
1375
+ transformDocsOp,
1376
+ transformTextX,
1377
+ undoStacksOf
359
1378
  };
360
1379
  //# sourceMappingURL=univer-collab.js.map