@ai-matrx/office 0.8.13 → 0.8.15
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.
- package/CHANGELOG.md +28 -0
- package/dist/docs.cjs +91 -2
- package/dist/docs.cjs.map +1 -1
- package/dist/docs.d.cts +29 -1
- package/dist/docs.d.ts +29 -1
- package/dist/docs.js +89 -0
- package/dist/docs.js.map +1 -1
- package/dist/univer-collab.cjs +1922 -27
- package/dist/univer-collab.cjs.map +1 -1
- package/dist/univer-collab.d.cts +293 -6
- package/dist/univer-collab.d.ts +293 -6
- package/dist/univer-collab.js +1937 -27
- package/dist/univer-collab.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.15
|
|
4
|
+
|
|
5
|
+
UNVERIFIED: this release has no Unreleased entry and the source comparison could not be made (the caller supplied no source comparison). Whether source changed is unknown; consumer action is unknown.
|
|
6
|
+
Check the package's gitHead on npm against this version's gitHead: `git diff <previous gitHead> <this gitHead> -- apps/shared/office/src`.
|
|
7
|
+
|
|
8
|
+
## 0.8.14
|
|
9
|
+
|
|
10
|
+
- **`/collab/sheets-transform` covers formulas (C5b; still inert, no consumer).** A formula typed on one seat now has its references rewritten by a concurrent row/column insert, removal or move and by a concurrent sheet rename, in both commit orders, exactly as Univer's own `@univerjs/sheets-formula` interceptor rewrites them: A1 references, ranges, absolute and mixed markers, whole rows and columns, cross-sheet references, references into a removed range (`#REF!`), array formulas (`ref` range moves; dynamic arrays are plain formulas). Defined names (`formula.mutation.set-defined-name` / `remove-defined-name`) are covered: their ranges follow structural edits and renames, a renamed name is renamed inside concurrent formulas, a removed one becomes `#REF!`. A rewrite a structural op carries for formulas that already existed (`derived`) never outranks a person's concurrent write to the same cell or name. Shared formulas (`si`) stay barriers (the failing case is in `sheet-formula-hard-cases.test.ts`). Rewrites match real sheets-formula 1.0.4 on 476 oracle cases (`fixtures/sheets-formula-oracle.json`, made by `spikes/c5b-probe/oracle.mjs`). Pairwise TP1 fuzz: 20 families (210 pairs) at 4,000 seeds each, both orders, 0 divergences, 0 throws. New exports: `annotateFormulas`, `forApply`, `SIDE_CAR_PARAMS`, `rewriteFormula`, `formulaBarrier`, `isFormulaText`, `refSheetsFor`, `refSheetsAfter`, `REF_ERROR` and the `RefChange`/`RefSheets`/`FormulaCtx` types. `CONTENT_KEYS` gains `ref`, `xf`, `ft`, `fd`; `SHEET_TRANSFORMER_VERSION` is `c5b-1`. `@univerjs/engine-formula` moves from devDependencies to dependencies (the lexer runs in shipped code). Consumer action: none (nothing imports this section yet). For C6: capture must call `annotateFormulas` on each group (sheet id → name, defined-name id → name, read before the command) and apply through `forApply`; the canonical sheet hash must sort the defined-names resource by id.
|
|
11
|
+
|
|
12
|
+
- **Docs co-editing: other people's carets and selections (C8), and a History restore reaches an open room (C7a).** Each seat publishes `caret = { ranges, at }` (body offsets, header/footer selections excluded) on Yjs awareness beside `quiet_hash`, on every selection change and every 2 s. A receiver keeps the last published ranges in `RemoteCaretBook` and moves them through every body edit it applies afterwards, remote or its own (`moveRangesThroughBodyEdit`), so a caret survives edits between publications; a caret not refreshed for 12 s (judged by the receiver's clock) is not listed, and a seat that leaves drops with its awareness state. `DocumentAwareness` gains `carets?: RemoteCaret[]`; `DocsOtPort` gains an optional `selection()` (the model supplies it from the first view). `restoreDocumentSnapshot` (`@ai-matrx/office/univer/collab`) is the one History restore: open in this tab, the editor swaps it in (an ordered room sends `collab_replace`); not open but the document has a room, `collab_replace` (snapshot row, `replace` op, checkpoint and frame in one transaction) so every open seat reloads; no room, a snapshot row. `hasOpenEditorContent(kind, id)` joins `showSavedSnapshot`. Consumer action: pass `displayName` to `documentOtFactory`, draw `awareness.carets` over the canvas, and call `restoreDocumentSnapshot` from History instead of `saveDocumentSnapshot` + `showSavedSnapshot`.
|
|
13
|
+
|
|
14
|
+
- Docs co-editing (C3): a collaborator's edit now moves this seat's caret with the characters (§6.8). The view port gains an optional `selection { get, set }`; `DocumentModel` moves body ranges through each applied remote edit (`moveRangesThroughBodyEdit`). Found in the live two-browser run: with the caret left at its old offset, the next keystrokes landed scattered. Consumer action: pass `selection` from Univer's `DocSelectionManagerService` in the view port.
|
|
15
|
+
|
|
16
|
+
- **Docs co-editing: two people typing at one spot keep their words whole (C3b).** A collaborator's insert that lands exactly at a collapsed caret now stays AFTER the caret: this person's next keystroke commits later, so by the one conflict rule (§6.4, later-committed sits first) it goes before it, the same side the session gives unsent and in-flight local inserts. 0.8.11 pushed the caret past it, so two people typing at one caret alternated letters ("FElbobod"). A selection never takes in a collaborator's text at either edge. The transform's tie rule is unchanged (later-committed first; Docs TP1 fuzz 20,000 seeds per pair, 0 divergences). Forcing test: `two-people-typing-at-one-caret-keep-their-words-whole.test.ts`. Consumer action: none.
|
|
17
|
+
|
|
18
|
+
### Unreleased
|
|
19
|
+
|
|
20
|
+
- **`Workbook` and `DocumentRow` carry `test_expires_at` / `test_run_id`** — the `workbench.udt_workbooks` / `udt_documents` rows gained these test-fixture columns; the hand-written types now match the generated row again (matrx-frontend `features/data-tables/office-types-agree.ts`). Consumer action: none (a literal building one of these rows must add the two fields, `null` for real records).
|
|
21
|
+
|
|
3
22
|
## 0.8.13
|
|
4
23
|
|
|
5
24
|
- **`/collab/sheets-transform` covers formulas (C5b; still inert, no consumer).** A formula typed on one seat now has its references rewritten by a concurrent row/column insert, removal or move and by a concurrent sheet rename, in both commit orders, exactly as Univer's own `@univerjs/sheets-formula` interceptor rewrites them: A1 references, ranges, absolute and mixed markers, whole rows and columns, cross-sheet references, references into a removed range (`#REF!`), array formulas (`ref` range moves; dynamic arrays are plain formulas). Defined names (`formula.mutation.set-defined-name` / `remove-defined-name`) are covered: their ranges follow structural edits and renames, a renamed name is renamed inside concurrent formulas, a removed one becomes `#REF!`. A rewrite a structural op carries for formulas that already existed (`derived`) never outranks a person's concurrent write to the same cell or name. Shared formulas (`si`) stay barriers (the failing case is in `sheet-formula-hard-cases.test.ts`). Rewrites match real sheets-formula 1.0.4 on 476 oracle cases (`fixtures/sheets-formula-oracle.json`, made by `spikes/c5b-probe/oracle.mjs`). Pairwise TP1 fuzz: 20 families (210 pairs) at 4,000 seeds each, both orders, 0 divergences, 0 throws. New exports: `annotateFormulas`, `forApply`, `SIDE_CAR_PARAMS`, `rewriteFormula`, `formulaBarrier`, `isFormulaText`, `refSheetsFor`, `refSheetsAfter`, `REF_ERROR` and the `RefChange`/`RefSheets`/`FormulaCtx` types. `CONTENT_KEYS` gains `ref`, `xf`, `ft`, `fd`; `SHEET_TRANSFORMER_VERSION` is `c5b-1`. `@univerjs/engine-formula` moves from devDependencies to dependencies (the lexer runs in shipped code). Consumer action: none (nothing imports this section yet). For C6: capture must call `annotateFormulas` on each group (sheet id → name, defined-name id → name, read before the command) and apply through `forApply`; the canonical sheet hash must sort the defined-names resource by id.
|
|
@@ -12,6 +31,15 @@
|
|
|
12
31
|
|
|
13
32
|
- **`Workbook` and `DocumentRow` carry `test_expires_at` / `test_run_id`** — the `workbench.udt_workbooks` / `udt_documents` rows gained these test-fixture columns; the hand-written types now match the generated row again (matrx-frontend `features/data-tables/office-types-agree.ts`). Consumer action: none (a literal building one of these rows must add the two fields, `null` for real records).
|
|
14
33
|
|
|
34
|
+
## 0.8.12
|
|
35
|
+
|
|
36
|
+
SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
|
|
37
|
+
so they may include breaking API changes. Consumer action is UNKNOWN: read the diff before upgrading.
|
|
38
|
+
Diff: `git diff 9061076166 6b0770b11a -- apps/shared/office/src`
|
|
39
|
+
|
|
40
|
+
Changed shipped source files (1):
|
|
41
|
+
- `apps/shared/office/src/docs/document-model.ts`
|
|
42
|
+
|
|
15
43
|
## 0.8.9
|
|
16
44
|
|
|
17
45
|
SOURCE CHANGED WITH NO RELEASE NOTE. This release shipped source changes that nobody described in an Unreleased entry,
|
package/dist/docs.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
@@ -864,6 +864,95 @@ function documentBodyWriteHandler(deps) {
|
|
|
864
864
|
};
|
|
865
865
|
}
|
|
866
866
|
|
|
867
|
+
// src/docs/remote-carets.ts
|
|
868
|
+
var CARET_HEARTBEAT_MS = 2e3;
|
|
869
|
+
var CARET_STALE_MS = 12e3;
|
|
870
|
+
var CARET_MAX_RANGES = 4;
|
|
871
|
+
function publishedCaretFromSelection(sel, now) {
|
|
872
|
+
if (!sel || sel.length === 0) return null;
|
|
873
|
+
if (sel.some((r) => r.segmentId)) return null;
|
|
874
|
+
const ranges = sel.slice(0, CARET_MAX_RANGES).map((r) => ({ start: Math.min(r.startOffset, r.endOffset), end: Math.max(r.startOffset, r.endOffset) }));
|
|
875
|
+
return { ranges, at: now };
|
|
876
|
+
}
|
|
877
|
+
var sameRanges = (a, b) => a.length === b.length && a.every((r, i) => r.start === b[i].start && r.end === b[i].end);
|
|
878
|
+
function readCaret(raw) {
|
|
879
|
+
const c = _optionalChain([raw, 'optionalAccess', _72 => _72.caret]);
|
|
880
|
+
if (!c || !Array.isArray(c.ranges) || typeof c.at !== "number") return null;
|
|
881
|
+
const ranges = [];
|
|
882
|
+
for (const r of c.ranges.slice(0, CARET_MAX_RANGES)) {
|
|
883
|
+
const s2 = _optionalChain([r, 'optionalAccess', _73 => _73.start]);
|
|
884
|
+
const e2 = _optionalChain([r, 'optionalAccess', _74 => _74.end]);
|
|
885
|
+
if (typeof s2 !== "number" || typeof e2 !== "number" || !Number.isFinite(s2) || !Number.isFinite(e2) || s2 < 0 || e2 < 0) return null;
|
|
886
|
+
ranges.push({ start: s2, end: e2 });
|
|
887
|
+
}
|
|
888
|
+
return ranges.length ? { ranges, at: c.at } : null;
|
|
889
|
+
}
|
|
890
|
+
var RemoteCaretBook = (_class2 = class {
|
|
891
|
+
constructor(selfClientId, now = Date.now) {;_class2.prototype.__init25.call(this);
|
|
892
|
+
this.selfClientId = selfClientId;
|
|
893
|
+
this.now = now;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
__init25() {this.carets = /* @__PURE__ */ new Map()}
|
|
898
|
+
/** Take the room's awareness states: new or republished carets replace ours, seats that left are dropped. Returns whether anything changed. */
|
|
899
|
+
ingest(states) {
|
|
900
|
+
let changed = false;
|
|
901
|
+
const seen = /* @__PURE__ */ new Set();
|
|
902
|
+
states.forEach((raw, id) => {
|
|
903
|
+
if (id === this.selfClientId) return;
|
|
904
|
+
const s2 = raw;
|
|
905
|
+
const caret = readCaret(raw);
|
|
906
|
+
if (!s2 || typeof s2.uid !== "string" || !caret) return;
|
|
907
|
+
const key = String(id);
|
|
908
|
+
seen.add(key);
|
|
909
|
+
const prev = this.carets.get(key);
|
|
910
|
+
const name = typeof s2.name === "string" && s2.name ? s2.name : "Someone";
|
|
911
|
+
const color = typeof s2.color === "string" && s2.color ? s2.color : "#3b82f6";
|
|
912
|
+
if (prev && prev.at === caret.at && prev.name === name && prev.color === color) return;
|
|
913
|
+
this.carets.set(key, { key, uid: s2.uid, name, color, ranges: caret.ranges, at: caret.at, seenAt: this.now() });
|
|
914
|
+
changed = true;
|
|
915
|
+
});
|
|
916
|
+
for (const key of [...this.carets.keys()]) {
|
|
917
|
+
if (!seen.has(key)) {
|
|
918
|
+
this.carets.delete(key);
|
|
919
|
+
changed = true;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
return changed;
|
|
923
|
+
}
|
|
924
|
+
/** Move every caret through one body edit that was just applied (`actions` of a rich-text mutation). Returns whether any moved. */
|
|
925
|
+
shiftThrough(actions) {
|
|
926
|
+
let moved = false;
|
|
927
|
+
for (const c of this.carets.values()) {
|
|
928
|
+
const next = moveRangesThroughBodyEdit(c.ranges.map((r) => ({ startOffset: r.start, endOffset: r.end })), actions);
|
|
929
|
+
if (!next) return false;
|
|
930
|
+
const ranges = next.map((r) => ({ start: r.startOffset, end: r.endOffset }));
|
|
931
|
+
if (!sameRanges(ranges, c.ranges)) {
|
|
932
|
+
c.ranges = ranges;
|
|
933
|
+
moved = true;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
return moved;
|
|
937
|
+
}
|
|
938
|
+
/** The carets to draw now (stale ones left out). */
|
|
939
|
+
list() {
|
|
940
|
+
const t = this.now();
|
|
941
|
+
const out = [];
|
|
942
|
+
for (const c of this.carets.values()) {
|
|
943
|
+
if (t - c.seenAt > CARET_STALE_MS) continue;
|
|
944
|
+
out.push({ key: c.key, uid: c.uid, name: c.name, color: c.color, ranges: c.ranges.map((r) => ({ ...r })) });
|
|
945
|
+
}
|
|
946
|
+
out.sort((a, b) => a.key.localeCompare(b.key));
|
|
947
|
+
return out;
|
|
948
|
+
}
|
|
949
|
+
}, _class2);
|
|
950
|
+
|
|
951
|
+
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
|
|
955
|
+
|
|
867
956
|
|
|
868
957
|
|
|
869
958
|
|
|
@@ -900,5 +989,5 @@ function documentBodyWriteHandler(deps) {
|
|
|
900
989
|
|
|
901
990
|
|
|
902
991
|
|
|
903
|
-
exports.DOCUMENT_BODY_MAX_LENGTH = DOCUMENT_BODY_MAX_LENGTH; exports.DOCUMENT_DESCRIPTION_MAX_LENGTH = DOCUMENT_DESCRIPTION_MAX_LENGTH; exports.DOCUMENT_NAME_MAX_LENGTH = DOCUMENT_NAME_MAX_LENGTH; exports.DOCUMENT_SAVE_DELAY_MS = DOCUMENT_SAVE_DELAY_MS; exports.DocumentModel = DocumentModel; exports.EMOJI_GROUPS = EMOJI_GROUPS; exports.MIN_FIT_ZOOM = MIN_FIT_ZOOM; exports.SPECIAL_GROUPS = SPECIAL_GROUPS; exports.bodyTextOf = bodyTextOf; exports.configureDocsHost = _chunkHX5TXQIXcjs.configureDocsHost; exports.copyDocument = _chunkHX5TXQIXcjs.copyDocument; exports.createDocument = _chunkHX5TXQIXcjs.createDocument; exports.deleteDocument = _chunkHX5TXQIXcjs.deleteDocument; exports.discardFailedDocument = _chunkHX5TXQIXcjs.discardFailedDocument; exports.documentBodyWriteHandler = documentBodyWriteHandler; exports.documentSourceLabel = documentSourceLabel; exports.fitZoomRatio = fitZoomRatio; exports.getDocsHost = _chunkHX5TXQIXcjs.getDocsHost; exports.getDocument = _chunkHX5TXQIXcjs.getDocument; exports.getLatestDocumentSnapshot = _chunkHX5TXQIXcjs.getLatestDocumentSnapshot; exports.listAccessibleDocuments = _chunkHX5TXQIXcjs.listAccessibleDocuments; exports.listDocumentSnapshots = _chunkHX5TXQIXcjs.listDocumentSnapshots; exports.listTrashedDocuments = _chunkHX5TXQIXcjs.listTrashedDocuments; exports.moveDocument = _chunkHX5TXQIXcjs.moveDocument; exports.moveRangesThroughBodyEdit = moveRangesThroughBodyEdit; exports.planBodyEdit = planBodyEdit; exports.renameDocument = _chunkHX5TXQIXcjs.renameDocument; exports.restoreDocument = _chunkHX5TXQIXcjs.restoreDocument; exports.sanitizeUniverDocSnapshot = _chunkHX5TXQIXcjs.sanitizeUniverDocSnapshot; exports.saveDocumentSnapshot = _chunkHX5TXQIXcjs.saveDocumentSnapshot; exports.searchSymbols = searchSymbols; exports.updateDocumentDescription = _chunkHX5TXQIXcjs.updateDocumentDescription; exports.validateDocumentBody = validateDocumentBody; exports.validateDocumentDescription = validateDocumentDescription; exports.validateDocumentName = validateDocumentName; exports.writeBodyText = writeBodyText;
|
|
992
|
+
exports.CARET_HEARTBEAT_MS = CARET_HEARTBEAT_MS; exports.CARET_MAX_RANGES = CARET_MAX_RANGES; exports.CARET_STALE_MS = CARET_STALE_MS; exports.DOCUMENT_BODY_MAX_LENGTH = DOCUMENT_BODY_MAX_LENGTH; exports.DOCUMENT_DESCRIPTION_MAX_LENGTH = DOCUMENT_DESCRIPTION_MAX_LENGTH; exports.DOCUMENT_NAME_MAX_LENGTH = DOCUMENT_NAME_MAX_LENGTH; exports.DOCUMENT_SAVE_DELAY_MS = DOCUMENT_SAVE_DELAY_MS; exports.DocumentModel = DocumentModel; exports.EMOJI_GROUPS = EMOJI_GROUPS; exports.MIN_FIT_ZOOM = MIN_FIT_ZOOM; exports.RemoteCaretBook = RemoteCaretBook; exports.SPECIAL_GROUPS = SPECIAL_GROUPS; exports.bodyTextOf = bodyTextOf; exports.configureDocsHost = _chunkHX5TXQIXcjs.configureDocsHost; exports.copyDocument = _chunkHX5TXQIXcjs.copyDocument; exports.createDocument = _chunkHX5TXQIXcjs.createDocument; exports.deleteDocument = _chunkHX5TXQIXcjs.deleteDocument; exports.discardFailedDocument = _chunkHX5TXQIXcjs.discardFailedDocument; exports.documentBodyWriteHandler = documentBodyWriteHandler; exports.documentSourceLabel = documentSourceLabel; exports.fitZoomRatio = fitZoomRatio; exports.getDocsHost = _chunkHX5TXQIXcjs.getDocsHost; exports.getDocument = _chunkHX5TXQIXcjs.getDocument; exports.getLatestDocumentSnapshot = _chunkHX5TXQIXcjs.getLatestDocumentSnapshot; exports.listAccessibleDocuments = _chunkHX5TXQIXcjs.listAccessibleDocuments; exports.listDocumentSnapshots = _chunkHX5TXQIXcjs.listDocumentSnapshots; exports.listTrashedDocuments = _chunkHX5TXQIXcjs.listTrashedDocuments; exports.moveDocument = _chunkHX5TXQIXcjs.moveDocument; exports.moveRangesThroughBodyEdit = moveRangesThroughBodyEdit; exports.planBodyEdit = planBodyEdit; exports.publishedCaretFromSelection = publishedCaretFromSelection; exports.renameDocument = _chunkHX5TXQIXcjs.renameDocument; exports.restoreDocument = _chunkHX5TXQIXcjs.restoreDocument; exports.sanitizeUniverDocSnapshot = _chunkHX5TXQIXcjs.sanitizeUniverDocSnapshot; exports.saveDocumentSnapshot = _chunkHX5TXQIXcjs.saveDocumentSnapshot; exports.searchSymbols = searchSymbols; exports.updateDocumentDescription = _chunkHX5TXQIXcjs.updateDocumentDescription; exports.validateDocumentBody = validateDocumentBody; exports.validateDocumentDescription = validateDocumentDescription; exports.validateDocumentName = validateDocumentName; exports.writeBodyText = writeBodyText;
|
|
904
993
|
//# sourceMappingURL=docs.cjs.map
|