@ai-matrx/office 0.4.0 → 0.5.2
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 +36 -0
- package/dist/chunk-2UBGQUXW.cjs +37 -0
- package/dist/chunk-2UBGQUXW.cjs.map +1 -0
- package/dist/chunk-BWMAYLW4.cjs +272 -0
- package/dist/chunk-BWMAYLW4.cjs.map +1 -0
- package/dist/chunk-IDEA5UXK.js +272 -0
- package/dist/chunk-IDEA5UXK.js.map +1 -0
- package/dist/chunk-MPKXXZZV.js +37 -0
- package/dist/chunk-MPKXXZZV.js.map +1 -0
- package/dist/chunk-O6FTSXHE.cjs +463 -0
- package/dist/chunk-O6FTSXHE.cjs.map +1 -0
- package/dist/chunk-PI473GES.js +463 -0
- package/dist/chunk-PI473GES.js.map +1 -0
- package/dist/docs-io.cjs +496 -0
- package/dist/docs-io.cjs.map +1 -0
- package/dist/docs-io.d.cts +147 -0
- package/dist/docs-io.d.ts +147 -0
- package/dist/docs-io.js +496 -0
- package/dist/docs-io.js.map +1 -0
- package/dist/docs-tools.cjs +217 -0
- package/dist/docs-tools.cjs.map +1 -0
- package/dist/docs-tools.d.cts +150 -0
- package/dist/docs-tools.d.ts +150 -0
- package/dist/docs-tools.js +217 -0
- package/dist/docs-tools.js.map +1 -0
- package/dist/docs.cjs +657 -0
- package/dist/docs.cjs.map +1 -0
- package/dist/docs.d.cts +582 -0
- package/dist/docs.d.ts +582 -0
- package/dist/docs.js +657 -0
- package/dist/docs.js.map +1 -0
- package/dist/univer-collab.cjs +3 -0
- package/dist/univer-collab.cjs.map +1 -1
- package/dist/univer-collab.d.cts +7 -0
- package/dist/univer-collab.d.ts +7 -0
- package/dist/univer-collab.js +3 -0
- package/dist/univer-collab.js.map +1 -1
- package/package.json +40 -6
package/dist/docs.d.cts
ADDED
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
import { ServiceResult } from '@ai-matrx/records/core';
|
|
3
|
+
import { IDocumentData } from '@univerjs/core';
|
|
4
|
+
import { WorkingCopyHandle, CommitReason } from '@ai-matrx/kit/working-copy';
|
|
5
|
+
import { AwarenessState } from '@ai-matrx/data/realtime/collab';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The host ports of the Docs model and io.
|
|
9
|
+
*
|
|
10
|
+
* The package owns the document service, the open-document model and the converters, but two things
|
|
11
|
+
* belong to the app that mounts them: the database client (a package owns no client) and the server
|
|
12
|
+
* request that converts a .docx to .odt / .rtf (the app owns the server URL, auth and error capture).
|
|
13
|
+
* The host states them once at start-up with `configureDocsHost`. State sits on a `globalThis` slot
|
|
14
|
+
* so a dual-bundled copy of the package still sees one host. An unconfigured port THROWS naming
|
|
15
|
+
* itself (nothing fails silently).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** A Supabase client over any schema: the package cannot import the app's generated database types. */
|
|
19
|
+
type DocsSupabase = SupabaseClient<any, any, any>;
|
|
20
|
+
interface DocsHostPorts {
|
|
21
|
+
/** The app's database client (signed in as the person). */
|
|
22
|
+
getSupabase(): DocsSupabase;
|
|
23
|
+
/** An authenticated request to the Matrx server returning the raw `Response` (the open-format converter). */
|
|
24
|
+
requestRaw(path: string, init: {
|
|
25
|
+
method: "POST";
|
|
26
|
+
body: FormData;
|
|
27
|
+
}): Promise<Response>;
|
|
28
|
+
}
|
|
29
|
+
declare function configureDocsHost(ports: DocsHostPorts): void;
|
|
30
|
+
declare function getDocsHost(): DocsHostPorts;
|
|
31
|
+
|
|
32
|
+
type DocumentSource = "created" | "imported_docx" | "imported_md" | "imported_txt" | "linked_gdoc";
|
|
33
|
+
/** `platform.shown_to`. */
|
|
34
|
+
type ShownTo = "only_me" | "my_team" | "everyone" | "everyone_on_ai_matrx";
|
|
35
|
+
/** `platform.visibility`. */
|
|
36
|
+
type Visibility = "personal" | "internal" | "link" | "public";
|
|
37
|
+
/** Origin of a snapshot. Free text in the database; this union is advisory. */
|
|
38
|
+
type WorkbookSnapshotOrigin = "autosave" | "manual" | "imported" | "restored" | "named";
|
|
39
|
+
/** Same advisory union as workbooks: a string column in the database. */
|
|
40
|
+
type DocumentSnapshotOrigin = WorkbookSnapshotOrigin;
|
|
41
|
+
/** A row of `workbench.udt_documents`. */
|
|
42
|
+
interface DocumentRow {
|
|
43
|
+
created_at: string;
|
|
44
|
+
created_by: string;
|
|
45
|
+
custom_fields: unknown;
|
|
46
|
+
deleted_at: string | null;
|
|
47
|
+
description: string | null;
|
|
48
|
+
document_name: string;
|
|
49
|
+
id: string;
|
|
50
|
+
is_public: boolean;
|
|
51
|
+
metadata: unknown;
|
|
52
|
+
organization_id: string | null;
|
|
53
|
+
original_file_id: string | null;
|
|
54
|
+
project_id: string | null;
|
|
55
|
+
published_to_web: boolean;
|
|
56
|
+
published_to_web_at: string | null;
|
|
57
|
+
published_to_web_by: string | null;
|
|
58
|
+
shown_to: ShownTo | null;
|
|
59
|
+
source: DocumentSource;
|
|
60
|
+
task_id: string | null;
|
|
61
|
+
updated_at: string;
|
|
62
|
+
updated_by: string | null;
|
|
63
|
+
user_id: string;
|
|
64
|
+
version: number;
|
|
65
|
+
visibility: Visibility;
|
|
66
|
+
}
|
|
67
|
+
/** A row of `workbench.udt_document_snapshots`. */
|
|
68
|
+
interface DocumentSnapshot {
|
|
69
|
+
created_at: string;
|
|
70
|
+
created_by: string | null;
|
|
71
|
+
custom_fields: unknown;
|
|
72
|
+
document_id: string;
|
|
73
|
+
id: string;
|
|
74
|
+
label: string | null;
|
|
75
|
+
metadata: unknown;
|
|
76
|
+
origin: string;
|
|
77
|
+
snapshot: unknown;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
type CreateDocumentArgs = {
|
|
81
|
+
name: string;
|
|
82
|
+
description?: string | null;
|
|
83
|
+
/** Origin label for the document itself, mirrors `udt_documents.source`. */
|
|
84
|
+
source?: "created" | "imported_docx" | "imported_md" | "imported_txt" | "linked_gdoc";
|
|
85
|
+
organizationId: string;
|
|
86
|
+
projectId?: string | null;
|
|
87
|
+
taskId?: string | null;
|
|
88
|
+
isPublic?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* cld_files.id of the source upload (DOCX / MD / TXT blob). Set on the
|
|
91
|
+
* import flow so the lossless original is recoverable; FK is ON DELETE SET
|
|
92
|
+
* NULL, so deleting the file just nulls the link — the document survives.
|
|
93
|
+
*/
|
|
94
|
+
originalFileId?: string | null;
|
|
95
|
+
};
|
|
96
|
+
declare function createDocument(args: CreateDocumentArgs): Promise<ServiceResult<DocumentRow>>;
|
|
97
|
+
declare function listAccessibleDocuments(): Promise<ServiceResult<DocumentRow[]>>;
|
|
98
|
+
declare function getDocument(documentId: string): Promise<ServiceResult<DocumentRow>>;
|
|
99
|
+
declare function renameDocument(documentId: string, name: string): Promise<ServiceResult<DocumentRow>>;
|
|
100
|
+
/**
|
|
101
|
+
* Move the document into a project (or out of one with `null`). Sibling of
|
|
102
|
+
* `renameDocument`: the one named setter for `project_id`.
|
|
103
|
+
*/
|
|
104
|
+
declare function moveDocument(documentId: string, projectId: string | null): Promise<ServiceResult<DocumentRow>>;
|
|
105
|
+
/**
|
|
106
|
+
* Rewrite the document's description. Sibling of `renameDocument` — the two
|
|
107
|
+
* human-authored fields on `udt_documents` each get a named setter so callers
|
|
108
|
+
* never hand-roll a `.from("udt_documents").update(...)`. Pass `null` (or an
|
|
109
|
+
* empty string) to clear it.
|
|
110
|
+
*
|
|
111
|
+
* Added when the documents surface became agent-writable: the
|
|
112
|
+
* `document_description` write target on `/documents/[id]` is its caller, the
|
|
113
|
+
* same way `updateWorkbookDescription` serves `workbook_description`. Keeping
|
|
114
|
+
* the pair symmetric is this file's standing contract with `workbook-service`
|
|
115
|
+
* (see the module header).
|
|
116
|
+
*/
|
|
117
|
+
declare function updateDocumentDescription(documentId: string, description: string | null): Promise<ServiceResult<DocumentRow>>;
|
|
118
|
+
/**
|
|
119
|
+
* Soft delete — the document is tombstoned, not destroyed, and its snapshots stay
|
|
120
|
+
* with it. Every read path filters `deleted_at is null`. Pair with
|
|
121
|
+
* restoreDocument for undo. (aidream migration 0458.)
|
|
122
|
+
*/
|
|
123
|
+
declare function restoreDocument(documentId: string): Promise<ServiceResult<true>>;
|
|
124
|
+
/**
|
|
125
|
+
* Archive (delete means archive: never a hard delete) — only for rolling back a document this very flow just created and
|
|
126
|
+
* failed to populate. Never use for a user-initiated delete: that is
|
|
127
|
+
* deleteDocument, which tombstones and stays recoverable.
|
|
128
|
+
*/
|
|
129
|
+
declare function discardFailedDocument(documentId: string): Promise<ServiceResult<true>>;
|
|
130
|
+
declare function deleteDocument(documentId: string): Promise<ServiceResult<true>>;
|
|
131
|
+
/**
|
|
132
|
+
* Latest-snapshot fetch — what an opened document hydrates from. Returns
|
|
133
|
+
* `data: null` (success path) when the document has no snapshots yet (newly
|
|
134
|
+
* created, never saved). Distinguish "no snapshot" from "load error" by
|
|
135
|
+
* checking `result.data === null`.
|
|
136
|
+
*/
|
|
137
|
+
declare function getLatestDocumentSnapshot(documentId: string): Promise<ServiceResult<DocumentSnapshot | null>>;
|
|
138
|
+
type SaveDocumentSnapshotArgs = {
|
|
139
|
+
documentId: string;
|
|
140
|
+
snapshot: unknown;
|
|
141
|
+
label?: string | null;
|
|
142
|
+
origin?: DocumentSnapshotOrigin;
|
|
143
|
+
};
|
|
144
|
+
declare function saveDocumentSnapshot(args: SaveDocumentSnapshotArgs): Promise<ServiceResult<DocumentSnapshot>>;
|
|
145
|
+
/**
|
|
146
|
+
* An independent copy of a document: its own row, with the latest snapshot copied over, so editing the copy never
|
|
147
|
+
* touches the original. The copy lives in the original's organization and project. Used by a board-template use.
|
|
148
|
+
*/
|
|
149
|
+
declare function copyDocument(documentId: string, name?: string): Promise<ServiceResult<DocumentRow>>;
|
|
150
|
+
/** Trash view: the caller's own archived documents (RLS decides what is readable). */
|
|
151
|
+
declare function listTrashedDocuments(): Promise<ServiceResult<DocumentRow[]>>;
|
|
152
|
+
declare function listDocumentSnapshots(documentId: string, limit?: number): Promise<ServiceResult<DocumentSnapshot[]>>;
|
|
153
|
+
|
|
154
|
+
type MutationParams = Record<string, unknown> | unknown[] | null;
|
|
155
|
+
type CollabMutationInfo = {
|
|
156
|
+
id: string;
|
|
157
|
+
type: number;
|
|
158
|
+
params: MutationParams;
|
|
159
|
+
/** Who made it (the person's uid), so a peer can tell its own other tab's edit from a stranger's. */
|
|
160
|
+
uid?: string;
|
|
161
|
+
};
|
|
162
|
+
type ExecuteOptions = {
|
|
163
|
+
/** Per-Univer convention: when true, the command runs locally only and is
|
|
164
|
+
* NOT broadcast to other plugins. We set this on inbound-apply so the
|
|
165
|
+
* subsequent onMutationExecutedForCollab does NOT re-fire on our peer. */
|
|
166
|
+
onlyLocal?: boolean;
|
|
167
|
+
fromCollab?: boolean;
|
|
168
|
+
};
|
|
169
|
+
type CommandServiceLike = {
|
|
170
|
+
onMutationExecutedForCollab(listener: (info: CollabMutationInfo, options?: ExecuteOptions) => void): {
|
|
171
|
+
dispose: () => void;
|
|
172
|
+
};
|
|
173
|
+
syncExecuteCommand(id: string, params: MutationParams, options?: ExecuteOptions): unknown;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* THE DOCUMENT MODEL — the engine of one cloud document per tab.
|
|
178
|
+
*
|
|
179
|
+
* Before this, the document lived only inside each `DocumentEditor`'s Univer
|
|
180
|
+
* instance. A remount (a board tile waking, a tile removed and undone, a route
|
|
181
|
+
* change and back) rebuilt the editor from the SERVER copy, so whatever the
|
|
182
|
+
* last save had not carried yet was gone; two mounts of one document were two
|
|
183
|
+
* editors, each saving full snapshots of its own copy (last write wins), each
|
|
184
|
+
* with its own realtime channel and its own collab room.
|
|
185
|
+
*
|
|
186
|
+
* The document is a record on THE one working-copy primitive
|
|
187
|
+
* (`@ai-matrx/kit/working-copy`, kind `udt_document`,
|
|
188
|
+
* `./documentModels.ts`): its save status, dirty and view count are Redux state
|
|
189
|
+
* (`workingCopies["udt_document:<id>"]`), its one coalesced save is the kind's.
|
|
190
|
+
* What Redux cannot hold — Univer's body — is this engine, registered on the
|
|
191
|
+
* record's session under the same key:
|
|
192
|
+
*
|
|
193
|
+
* - BODY. Every local mutation in one view is replayed into every other view
|
|
194
|
+
* of the document (the same mutation stream collab sends between machines),
|
|
195
|
+
* so two views show one document. A new view boots from the engine's latest
|
|
196
|
+
* state — a live view's snapshot, or the snapshot the last view left behind
|
|
197
|
+
* — never the stale server copy while the record's session is alive.
|
|
198
|
+
* - SIDE EFFECTS, ONCE. The snapshot realtime channel, the collab room, and
|
|
199
|
+
* the pagehide / visibility / beforeunload flush are opened once per
|
|
200
|
+
* document and closed once.
|
|
201
|
+
* - THE EDITOR ITSELF, KEPT. Univer keeps its undo / redo history inside the
|
|
202
|
+
* editor instance, so rebuilding the editor on a remount threw the history
|
|
203
|
+
* away. When the last view leaves, its editor (a Univer instance with its
|
|
204
|
+
* own DOM host) is parked here — off the page, alive — and the next view of
|
|
205
|
+
* the document RE-ATTACHES that same instance to its own container instead
|
|
206
|
+
* of booting a new one (`parkEditor` / `takeParkedEditor`). Undo and redo
|
|
207
|
+
* therefore work across hide / show, a remount and a removed tile undone,
|
|
208
|
+
* for as long as the record's session is warm; `close()` disposes it.
|
|
209
|
+
*/
|
|
210
|
+
|
|
211
|
+
/** Debounce from the last edit to the save. */
|
|
212
|
+
declare const DOCUMENT_SAVE_DELAY_MS = 2500;
|
|
213
|
+
type DocumentSnapshotData = Partial<IDocumentData>;
|
|
214
|
+
/** What a view lends the model while it is mounted. */
|
|
215
|
+
interface DocumentViewPort {
|
|
216
|
+
/** Univer's command service for this view's instance. */
|
|
217
|
+
commandService: CommandServiceLike;
|
|
218
|
+
/** The live document of this view (`doc.save()`), or null if it has none. */
|
|
219
|
+
snapshot: () => DocumentSnapshotData | null;
|
|
220
|
+
/** Replace the whole document in this view (a collaborator's snapshot). */
|
|
221
|
+
remount: (snapshot: DocumentSnapshotData) => void;
|
|
222
|
+
/** Whether this view may change the document (read at edit time). */
|
|
223
|
+
editable: () => boolean;
|
|
224
|
+
/**
|
|
225
|
+
* The Univer unit id of this view's mounted document. Every seat mounts its own unit, so a
|
|
226
|
+
* mutation carries the SENDER's id and must be re-addressed to this view's unit before it is
|
|
227
|
+
* applied. Falls back to the id of `snapshot()` when a view does not state it.
|
|
228
|
+
*/
|
|
229
|
+
unitId?: () => string | null;
|
|
230
|
+
}
|
|
231
|
+
/** Everything the engine reaches outside itself — injected so it is testable. */
|
|
232
|
+
interface DocumentModelDeps {
|
|
233
|
+
/** The newest stored snapshot (its row id + body), or null for a document never saved. */
|
|
234
|
+
loadLatest: (documentId: string) => Promise<{
|
|
235
|
+
id: string;
|
|
236
|
+
snapshot: DocumentSnapshotData;
|
|
237
|
+
} | null>;
|
|
238
|
+
save: (input: {
|
|
239
|
+
documentId: string;
|
|
240
|
+
snapshot: DocumentSnapshotData;
|
|
241
|
+
origin: "autosave" | "manual";
|
|
242
|
+
}) => Promise<{
|
|
243
|
+
id: string;
|
|
244
|
+
createdBy: string | null;
|
|
245
|
+
}>;
|
|
246
|
+
onSaved?: (documentId: string, origin: "autosave" | "manual") => void;
|
|
247
|
+
/** Window-level listeners (pagehide, visibilitychange, beforeunload). */
|
|
248
|
+
listenToPage?: (handlers: {
|
|
249
|
+
flush: () => void;
|
|
250
|
+
hasUnsaved: () => boolean;
|
|
251
|
+
}) => () => void;
|
|
252
|
+
/** A mutation could not be applied to a view: the app says so (a notice); the model re-syncs from the saved version. */
|
|
253
|
+
onApplyFailed?: (documentId: string, mutationId: string, error: unknown) => void;
|
|
254
|
+
}
|
|
255
|
+
/** A collab room (WorkbookCollabSession) bound to the model's command stream. */
|
|
256
|
+
interface DocumentCollabHandle {
|
|
257
|
+
stop: () => void;
|
|
258
|
+
isHost: () => boolean;
|
|
259
|
+
/** This tab replaced the whole document and saved it as `snapshotId`: peers reload it. */
|
|
260
|
+
announceReplaced: (snapshotId: string) => void;
|
|
261
|
+
}
|
|
262
|
+
/** Who else is in the document's room (shared by every view of it). */
|
|
263
|
+
interface DocumentAwareness {
|
|
264
|
+
states: Map<number, AwarenessState>;
|
|
265
|
+
selfUid: string;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* An editor instance kept alive between views of the document: its DOM host
|
|
269
|
+
* (re-parented into the next view's container) and the instance behind it,
|
|
270
|
+
* whose undo history survives because the instance does. Opaque to the model
|
|
271
|
+
* apart from what it calls.
|
|
272
|
+
*/
|
|
273
|
+
interface ParkedDocumentEditor<T = unknown> {
|
|
274
|
+
/** The element the editor renders into; the next view appends it to its container. */
|
|
275
|
+
element: HTMLElement;
|
|
276
|
+
instance: T;
|
|
277
|
+
/** Replace the whole document (a collaborator's snapshot arrived while parked). */
|
|
278
|
+
remount: (snapshot: DocumentSnapshotData) => void;
|
|
279
|
+
/** Throw the instance away (the record's session closed). */
|
|
280
|
+
dispose: () => void;
|
|
281
|
+
}
|
|
282
|
+
type DocumentCollabFactory = (commandService: CommandServiceLike, onAwareness: (awareness: DocumentAwareness) => void,
|
|
283
|
+
/** A peer replaced the whole document (history restore, Google update). */
|
|
284
|
+
onReplaced: () => void) => Promise<DocumentCollabHandle | null>;
|
|
285
|
+
declare class DocumentModel {
|
|
286
|
+
readonly documentId: string;
|
|
287
|
+
private readonly deps;
|
|
288
|
+
private readonly handle;
|
|
289
|
+
private readonly views;
|
|
290
|
+
private lastEditedView;
|
|
291
|
+
/** The document as the last view left it, or as last loaded / saved. */
|
|
292
|
+
private stored;
|
|
293
|
+
private loading;
|
|
294
|
+
private relaying;
|
|
295
|
+
/** Snapshot rows this tab already holds (loaded or written) — never re-applied. */
|
|
296
|
+
private readonly knownSnapshots;
|
|
297
|
+
private readonly collabListeners;
|
|
298
|
+
private collab;
|
|
299
|
+
private collabStarting;
|
|
300
|
+
private awareness;
|
|
301
|
+
private readonly awarenessListeners;
|
|
302
|
+
private realtimeClose;
|
|
303
|
+
private pageClose;
|
|
304
|
+
/** The last view's editor, alive and off the page until a view takes it back. */
|
|
305
|
+
private parked;
|
|
306
|
+
constructor(handle: WorkingCopyHandle, deps: DocumentModelDeps);
|
|
307
|
+
/** The newest state of the body this tab holds, without a network read. */
|
|
308
|
+
latest(): DocumentSnapshotData | null;
|
|
309
|
+
/**
|
|
310
|
+
* What a NEW view should boot from: the model's latest state, or (only when
|
|
311
|
+
* this tab holds none) the newest server snapshot. Null = an empty document.
|
|
312
|
+
* Re-read `latest()` synchronously right before mounting — another view may
|
|
313
|
+
* have typed while the server read was in flight.
|
|
314
|
+
*/
|
|
315
|
+
openingSnapshot(createEmpty: () => DocumentSnapshotData): Promise<DocumentSnapshotData>;
|
|
316
|
+
/** A view's Univer instance is ready: it shares the document from now on. */
|
|
317
|
+
attachView(port: DocumentViewPort): () => void;
|
|
318
|
+
/**
|
|
319
|
+
* The last view of the document is leaving: keep its editor (and Univer's
|
|
320
|
+
* undo history inside it) for the next view. Call AFTER the view's
|
|
321
|
+
* `attachView` detach. Refused — the caller disposes its editor — while
|
|
322
|
+
* another view is still attached (it carries the document) or one is
|
|
323
|
+
* already kept.
|
|
324
|
+
*/
|
|
325
|
+
parkEditor(editor: ParkedDocumentEditor): boolean;
|
|
326
|
+
/** The kept editor, handed to the view that mounts next (null when none is kept). */
|
|
327
|
+
takeParkedEditor(): ParkedDocumentEditor | null;
|
|
328
|
+
private onViewMutation;
|
|
329
|
+
/** The unit id a view's document has (what a replayed mutation must be addressed to). */
|
|
330
|
+
private unitIdOf;
|
|
331
|
+
/** Replay one mutation into every view except `exceptViewId`, addressed to each view's own unit. */
|
|
332
|
+
private relay;
|
|
333
|
+
/** A view could not follow an edit: say so, then show the saved version (unless this tab has unsaved edits of its own). */
|
|
334
|
+
private applyFailed;
|
|
335
|
+
private markDirty;
|
|
336
|
+
private saving;
|
|
337
|
+
/**
|
|
338
|
+
* The content of the version the server holds (loaded or last written). A
|
|
339
|
+
* save of the same content is no save: attaching, detaching, waking or a
|
|
340
|
+
* flush of an unchanged document never writes a snapshot row.
|
|
341
|
+
*/
|
|
342
|
+
private savedFingerprint;
|
|
343
|
+
/**
|
|
344
|
+
* Write the body as it is now. Returns false when this tab is a collab peer
|
|
345
|
+
* that does not write (the elected host writes the canonical snapshot; a
|
|
346
|
+
* peer's edits reach it through the room). An explicit Save always writes.
|
|
347
|
+
*/
|
|
348
|
+
write(reason: CommitReason): Promise<boolean>;
|
|
349
|
+
private hasUnsaved;
|
|
350
|
+
hasViews(): boolean;
|
|
351
|
+
/** Opened once per document by the first view that asks; idempotent. */
|
|
352
|
+
connectRealtime(open: (onSnapshot: (snapshotId: string) => void) => () => void): void;
|
|
353
|
+
/**
|
|
354
|
+
* A snapshot was committed (here or elsewhere): show a foreign one in every
|
|
355
|
+
* view. Over unsaved edits it is a CONFLICT — the working copy holds it and
|
|
356
|
+
* no save runs (one would overwrite the collaborator's snapshot) until the
|
|
357
|
+
* person chooses; `overUnsaved` is "Take theirs" (`./documentModels.ts`).
|
|
358
|
+
*/
|
|
359
|
+
onRemoteSnapshot(snapshotId: string, { overUnsaved }?: {
|
|
360
|
+
overUnsaved?: boolean;
|
|
361
|
+
}): Promise<void>;
|
|
362
|
+
/**
|
|
363
|
+
* THE content swap (see @ai-matrx/office/univer openEditorContent): a SAVED snapshot
|
|
364
|
+
* replaces the document in every view and the kept editor. It is the saved
|
|
365
|
+
* version from now on, so the pending save compares equal and writes
|
|
366
|
+
* nothing (it would put the old content back over the new). In a collab
|
|
367
|
+
* room the peers reload it and the shared log is emptied.
|
|
368
|
+
*/
|
|
369
|
+
replaceContent(row: {
|
|
370
|
+
id: string;
|
|
371
|
+
snapshot: DocumentSnapshotData;
|
|
372
|
+
}): void;
|
|
373
|
+
/** A peer replaced the document: show the newest save (once). */
|
|
374
|
+
private onPeerReplaced;
|
|
375
|
+
private show;
|
|
376
|
+
/**
|
|
377
|
+
* The model's command stream as ONE command service — what the collab room
|
|
378
|
+
* binds to. Local edits from any view go out once; a peer's edit is applied
|
|
379
|
+
* to every view.
|
|
380
|
+
*/
|
|
381
|
+
private readonly virtualCommandService;
|
|
382
|
+
/** Join the document's collab room once (the first view that asks). */
|
|
383
|
+
startCollab(factory: DocumentCollabFactory): Promise<void>;
|
|
384
|
+
isCollabHost(): boolean;
|
|
385
|
+
getAwareness(): DocumentAwareness | null;
|
|
386
|
+
subscribeAwareness(listener: () => void): () => void;
|
|
387
|
+
/** A view arrived on a document with none. */
|
|
388
|
+
wake(): void;
|
|
389
|
+
/**
|
|
390
|
+
* The last view left: leave the collab room (presence must not outlive the
|
|
391
|
+
* person). The snapshot channel stays open while the session is kept alive,
|
|
392
|
+
* so a collaborator's save still reaches the body a returning view boots from.
|
|
393
|
+
*/
|
|
394
|
+
rest(): void;
|
|
395
|
+
private closed;
|
|
396
|
+
close(): void;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Pure validation for the `matrx-user/documents` write targets.
|
|
401
|
+
*
|
|
402
|
+
* Deliberately OUTSIDE the React updater. `applySurfaceWrite`
|
|
403
|
+
* (`features/surfaces/runtime/surface-writeback.ts`) turns a THROW from a
|
|
404
|
+
* handler into the error envelope the agent reads back. Validating inside a
|
|
405
|
+
* `setState` updater would instead throw during React's render/commit — after
|
|
406
|
+
* the seam has already reported success — so the agent would be told its bad
|
|
407
|
+
* value landed. Validate here, synchronously, before touching any state.
|
|
408
|
+
*
|
|
409
|
+
* `DOCUMENT_NAME_MAX_LENGTH` is the single source of truth for the limit: it is
|
|
410
|
+
* enforced here, interpolated into the manifest target description, AND set as
|
|
411
|
+
* the `maxLength` of the header rename field on `/documents/[id]` — so the
|
|
412
|
+
* contract the agent reads, the rule the handler enforces, and the limit the
|
|
413
|
+
* human's own control applies cannot drift apart. The last of those matters
|
|
414
|
+
* for a non-obvious reason: the blur commit swallows service failures, so
|
|
415
|
+
* before the field was bounded a pasted 300-character title came back as a
|
|
416
|
+
* `varchar(255)` 400 and reverted with nothing on screen to explain it.
|
|
417
|
+
*/
|
|
418
|
+
/**
|
|
419
|
+
* `workbench.udt_documents.document_name` is `varchar(255) NOT NULL` — a
|
|
420
|
+
* longer value is rejected by Postgres, not merely by taste. Verified against
|
|
421
|
+
* `information_schema.columns` on 2026-08-11.
|
|
422
|
+
*/
|
|
423
|
+
declare const DOCUMENT_NAME_MAX_LENGTH = 255;
|
|
424
|
+
/**
|
|
425
|
+
* `workbench.udt_documents.description` is unbounded `text`, so this is a
|
|
426
|
+
* product bound rather than a database one: it matches the 2000 the sibling
|
|
427
|
+
* `workbook_description` target enforces, keeping the two mirrored services
|
|
428
|
+
* mirrored in behaviour too. The library renders this as a two-line blurb —
|
|
429
|
+
* anything near the cap is already past what a reader sees.
|
|
430
|
+
*/
|
|
431
|
+
declare const DOCUMENT_DESCRIPTION_MAX_LENGTH = 2000;
|
|
432
|
+
/**
|
|
433
|
+
* Validate an agent-supplied document title and return the exact string to
|
|
434
|
+
* persist. Throws (never coerces) so the agent hears about its own mistake.
|
|
435
|
+
*
|
|
436
|
+
* The `typeof` guard is load-bearing: the inline-tool layer PARSES a
|
|
437
|
+
* JSON-looking argument before the handler ever sees it, so a caller that
|
|
438
|
+
* sends `{"document_name":"..."}` or `"\"Quoted\""` arrives here as an object,
|
|
439
|
+
* not text. The message names the fix explicitly, because an agent that only
|
|
440
|
+
* hears "invalid" tends to retry by double-encoding — which lands escaped
|
|
441
|
+
* quotes and `\n` in the user's title box.
|
|
442
|
+
*/
|
|
443
|
+
declare function validateDocumentName(value: unknown): string;
|
|
444
|
+
/**
|
|
445
|
+
* Validate an agent-supplied document description and return the value to
|
|
446
|
+
* persist — `null` for a deliberate clear, so the caller never has to decide
|
|
447
|
+
* whether "" means "empty string" or "no description".
|
|
448
|
+
*
|
|
449
|
+
* Unlike the title this MAY span lines (it is a blurb, not a header), but it
|
|
450
|
+
* carries the same not-JSON guard for the same reason: the inline-tool layer
|
|
451
|
+
* parses a JSON-looking argument before the handler sees it.
|
|
452
|
+
*/
|
|
453
|
+
declare function validateDocumentDescription(value: unknown): string | null;
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Normalize a Univer document snapshot in place. Currently fixes string-valued
|
|
457
|
+
* `paragraphStyle.namedStyleType` (the confirmed `<ParagraphMenu>` crash). New
|
|
458
|
+
* classes of string-vs-enum corruption should be added here, not patched at the
|
|
459
|
+
* call site.
|
|
460
|
+
*
|
|
461
|
+
* @param snapshot The snapshot about to be passed to `createUniverDoc`.
|
|
462
|
+
* @param docId Document id, for the loud warning only.
|
|
463
|
+
* @returns the same snapshot reference (mutated).
|
|
464
|
+
*/
|
|
465
|
+
declare function sanitizeUniverDocSnapshot(snapshot: Partial<IDocumentData>, docId?: string): Partial<IDocumentData>;
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* The zoom that fits a document page inside a narrow editor (a phone), so the
|
|
469
|
+
* page reflows into view instead of scrolling sideways. Never above 100%, and
|
|
470
|
+
* never so small the text is unreadable. Pure — guarded by fit-zoom-ratio.test.ts.
|
|
471
|
+
*/
|
|
472
|
+
declare const MIN_FIT_ZOOM = 0.45;
|
|
473
|
+
declare function fitZoomRatio(containerWidth: number, pageWidth: number, gutter?: number): number;
|
|
474
|
+
|
|
475
|
+
declare function documentSourceLabel(source: DocumentSource): string;
|
|
476
|
+
|
|
477
|
+
/** Insert, Emoji and Special characters: searchable sets, a name per entry. */
|
|
478
|
+
interface Glyph {
|
|
479
|
+
char: string;
|
|
480
|
+
name: string;
|
|
481
|
+
}
|
|
482
|
+
declare const EMOJI_GROUPS: Array<{
|
|
483
|
+
id: string;
|
|
484
|
+
label: string;
|
|
485
|
+
items: Glyph[];
|
|
486
|
+
}>;
|
|
487
|
+
declare const SPECIAL_GROUPS: Array<{
|
|
488
|
+
id: string;
|
|
489
|
+
label: string;
|
|
490
|
+
items: Glyph[];
|
|
491
|
+
}>;
|
|
492
|
+
declare function searchSymbols(groups: typeof EMOJI_GROUPS, query: string): Glyph[];
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* The BODY TEXT of a Univer document, as agents read and write it (PURE).
|
|
496
|
+
*
|
|
497
|
+
* `matrx-user/documents` declares the body as a value (`document_body_text`)
|
|
498
|
+
* and a write target (`document_body`). Univer owns the document model, so
|
|
499
|
+
* both go through a small port the editor hands up (`DocumentEditor`
|
|
500
|
+
* `onBodyPort`): the read is the body's data stream as plain text, and a write
|
|
501
|
+
* is ONE changed span, applied through Univer's own facade (`deleteRange` /
|
|
502
|
+
* `insertText`, which run `InsertTextCommand` on the command service). That
|
|
503
|
+
* keeps every agent edit on the one editing path a keystroke takes: undo,
|
|
504
|
+
* autosave snapshots, History and collab all see it, and formatting outside
|
|
505
|
+
* the changed span is left exactly as it was.
|
|
506
|
+
*
|
|
507
|
+
* Univer's data stream encodes a paragraph end as `\r`, a section break as
|
|
508
|
+
* `\n`, and custom blocks / tables with control characters below U+0020. The
|
|
509
|
+
* plain text maps a paragraph end to `\n` and leaves the other control tokens
|
|
510
|
+
* out; `offsets` maps each text position back to its data-stream index so a
|
|
511
|
+
* change found in the text lands at the right place in the stream.
|
|
512
|
+
*/
|
|
513
|
+
/** The shape of a surface write handler (structurally the chat runtime's `SurfaceWriteHandlerEntry`; the package imports no chat). */
|
|
514
|
+
interface DocumentBodyWriteHandler {
|
|
515
|
+
validate: (value: unknown) => void;
|
|
516
|
+
apply: (value: unknown) => {
|
|
517
|
+
summary: string;
|
|
518
|
+
data?: unknown;
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* A product bound, not a database one (snapshots are jsonb): a body an agent
|
|
523
|
+
* sends larger than this is almost certainly a mistake (a whole file pasted
|
|
524
|
+
* twice), and past it the approval card stops being readable.
|
|
525
|
+
*/
|
|
526
|
+
declare const DOCUMENT_BODY_MAX_LENGTH = 200000;
|
|
527
|
+
/** What the editor lends the surface. Each call resolves the live document. */
|
|
528
|
+
interface DocumentBodyPort {
|
|
529
|
+
/** The main body's Univer data stream (ends with `\r\n`). */
|
|
530
|
+
getDataStream: () => string;
|
|
531
|
+
/** The live document snapshot (body with its text runs), for reading the formatting back out. */
|
|
532
|
+
getSnapshot?: () => unknown;
|
|
533
|
+
/** Delete `[start, end)` of the data stream; false when Univer refused. */
|
|
534
|
+
deleteRange: (start: number, end: number) => boolean;
|
|
535
|
+
/** Insert plain text (a `\n` starts a new paragraph) at a stream index. */
|
|
536
|
+
insertText: (at: number, text: string) => boolean;
|
|
537
|
+
/** Run a Univer command in the open editor (File menu: find and replace, comments). */
|
|
538
|
+
runCommand?: (commandId: string) => Promise<void>;
|
|
539
|
+
/** File → Page setup: open the page setup dialog in the open editor. */
|
|
540
|
+
openPageSetup?: () => void;
|
|
541
|
+
/** File → Language (and the other Docs tool dialogs): open one in the open editor. */
|
|
542
|
+
openTool?: (id: "language") => void;
|
|
543
|
+
}
|
|
544
|
+
interface BodyText {
|
|
545
|
+
text: string;
|
|
546
|
+
/** `offsets[i]` = the stream index of text position `i`; length is text.length + 1. */
|
|
547
|
+
offsets: number[];
|
|
548
|
+
}
|
|
549
|
+
/** The body's plain text and where each character sits in the stream. */
|
|
550
|
+
declare function bodyTextOf(dataStream: string): BodyText;
|
|
551
|
+
interface BodyEdit {
|
|
552
|
+
/** Stream range to remove (may be empty). */
|
|
553
|
+
start: number;
|
|
554
|
+
end: number;
|
|
555
|
+
/** Plain text to insert at `start` (may be empty). */
|
|
556
|
+
insert: string;
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* The ONE span that turns the current body into `next`: the longest common
|
|
560
|
+
* prefix and suffix stay untouched (with their formatting), only the middle
|
|
561
|
+
* changes. Null when nothing differs.
|
|
562
|
+
*/
|
|
563
|
+
declare function planBodyEdit(current: BodyText, next: string): BodyEdit | null;
|
|
564
|
+
/** Apply `next` as the whole body text through the port. */
|
|
565
|
+
declare function writeBodyText(port: DocumentBodyPort, next: string): {
|
|
566
|
+
changed: boolean;
|
|
567
|
+
removed: number;
|
|
568
|
+
inserted: number;
|
|
569
|
+
};
|
|
570
|
+
/** Shape check for an agent-sent body; throws a sentence the agent can act on. */
|
|
571
|
+
declare function validateDocumentBody(value: unknown): string;
|
|
572
|
+
/**
|
|
573
|
+
* The `document_body` write handler. `getPort` answers the live editor's port
|
|
574
|
+
* (null until Univer has mounted the document); `assertWritable` throws when
|
|
575
|
+
* the record is not loaded or the person may only view it.
|
|
576
|
+
*/
|
|
577
|
+
declare function documentBodyWriteHandler(deps: {
|
|
578
|
+
getPort: () => DocumentBodyPort | null;
|
|
579
|
+
assertWritable: (whatItBlocks: string) => void;
|
|
580
|
+
}): DocumentBodyWriteHandler;
|
|
581
|
+
|
|
582
|
+
export { type BodyEdit, type BodyText, type CreateDocumentArgs, DOCUMENT_BODY_MAX_LENGTH, DOCUMENT_DESCRIPTION_MAX_LENGTH, DOCUMENT_NAME_MAX_LENGTH, DOCUMENT_SAVE_DELAY_MS, type DocsHostPorts, type DocsSupabase, type DocumentAwareness, type DocumentBodyPort, type DocumentBodyWriteHandler, type DocumentCollabFactory, type DocumentCollabHandle, DocumentModel, type DocumentModelDeps, type DocumentSnapshotData, type DocumentViewPort, EMOJI_GROUPS, type Glyph, MIN_FIT_ZOOM, type ParkedDocumentEditor, SPECIAL_GROUPS, type SaveDocumentSnapshotArgs, bodyTextOf, configureDocsHost, copyDocument, createDocument, deleteDocument, discardFailedDocument, documentBodyWriteHandler, documentSourceLabel, fitZoomRatio, getDocsHost, getDocument, getLatestDocumentSnapshot, listAccessibleDocuments, listDocumentSnapshots, listTrashedDocuments, moveDocument, planBodyEdit, renameDocument, restoreDocument, sanitizeUniverDocSnapshot, saveDocumentSnapshot, searchSymbols, updateDocumentDescription, validateDocumentBody, validateDocumentDescription, validateDocumentName, writeBodyText };
|