ooxml-core 1.22.0 → 1.24.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.
- package/README.md +7 -2
- package/dist/automation/index.cjs +559 -339
- package/dist/automation/index.d.ts +1 -0
- package/dist/automation/index.d.ts.map +1 -1
- package/dist/automation/index.mjs +558 -340
- package/dist/automation/live.d.ts +89 -0
- package/dist/automation/live.d.ts.map +1 -0
- package/dist/collab/embedding.d.ts +7 -0
- package/dist/collab/embedding.d.ts.map +1 -1
- package/dist/collab/index.cjs +189 -0
- package/dist/collab/index.d.ts +2 -0
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.mjs +186 -1
- package/dist/collab/write-back-lifecycle.d.ts +33 -0
- package/dist/collab/write-back-lifecycle.d.ts.map +1 -0
- package/dist/collab/write-back.d.ts +75 -0
- package/dist/collab/write-back.d.ts.map +1 -0
- package/dist/docx/ui/customization.d.ts +30 -0
- package/dist/docx/ui/customization.d.ts.map +1 -0
- package/dist/docx/ui/index.cjs +51 -0
- package/dist/docx/ui/index.d.ts +1 -0
- package/dist/docx/ui/index.d.ts.map +1 -1
- package/dist/docx/ui/index.mjs +46 -1
- package/dist/embedding/backstage.d.ts +48 -0
- package/dist/embedding/backstage.d.ts.map +1 -0
- package/dist/embedding/capabilities.d.ts +60 -0
- package/dist/embedding/capabilities.d.ts.map +1 -0
- package/dist/embedding/customization.d.ts +32 -0
- package/dist/embedding/customization.d.ts.map +1 -0
- package/dist/embedding/index.cjs +229 -0
- package/dist/embedding/index.d.ts +7 -0
- package/dist/embedding/index.d.ts.map +1 -0
- package/dist/embedding/index.mjs +204 -0
- package/dist/embedding/menu-commands.d.ts +66 -0
- package/dist/embedding/menu-commands.d.ts.map +1 -0
- package/dist/embedding/regions.d.ts +58 -0
- package/dist/embedding/regions.d.ts.map +1 -0
- package/dist/embedding/storage.d.ts +111 -0
- package/dist/embedding/storage.d.ts.map +1 -0
- package/dist/index.cjs +233 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +233 -1
- package/dist/visio/collab/baseline.d.ts +36 -0
- package/dist/visio/collab/baseline.d.ts.map +1 -0
- package/dist/visio/collab/bind.d.ts +20 -2
- package/dist/visio/collab/bind.d.ts.map +1 -1
- package/dist/visio/collab/compose-lists.d.ts +27 -0
- package/dist/visio/collab/compose-lists.d.ts.map +1 -0
- package/dist/visio/collab/compose.d.ts +6 -2
- package/dist/visio/collab/compose.d.ts.map +1 -1
- package/dist/visio/collab/fixups.d.ts +5 -0
- package/dist/visio/collab/fixups.d.ts.map +1 -0
- package/dist/visio/collab/index.cjs +1603 -361
- package/dist/visio/collab/index.d.ts +3 -2
- package/dist/visio/collab/index.d.ts.map +1 -1
- package/dist/visio/collab/index.mjs +1596 -362
- package/dist/visio/collab/keys.d.ts +32 -1
- package/dist/visio/collab/keys.d.ts.map +1 -1
- package/dist/visio/collab/package.d.ts +22 -1
- package/dist/visio/collab/package.d.ts.map +1 -1
- package/dist/visio/collab/pieces.d.ts +41 -0
- package/dist/visio/collab/pieces.d.ts.map +1 -0
- package/dist/visio/collab/read-ids.d.ts +35 -0
- package/dist/visio/collab/read-ids.d.ts.map +1 -0
- package/dist/visio/collab/read-parts.d.ts +34 -0
- package/dist/visio/collab/read-parts.d.ts.map +1 -0
- package/dist/visio/collab/read-shapes.d.ts +34 -0
- package/dist/visio/collab/read-shapes.d.ts.map +1 -0
- package/dist/visio/collab/read-util.d.ts +20 -0
- package/dist/visio/collab/read-util.d.ts.map +1 -0
- package/dist/visio/collab/read.d.ts +40 -19
- package/dist/visio/collab/read.d.ts.map +1 -1
- package/dist/visio/collab/schema.d.ts +55 -1
- package/dist/visio/collab/schema.d.ts.map +1 -1
- package/dist/visio/collab/snapshot-contents.d.ts +9 -0
- package/dist/visio/collab/snapshot-contents.d.ts.map +1 -0
- package/dist/visio/collab/snapshot-io.d.ts +26 -0
- package/dist/visio/collab/snapshot-io.d.ts.map +1 -0
- package/dist/visio/collab/snapshot-parts.d.ts +14 -0
- package/dist/visio/collab/snapshot-parts.d.ts.map +1 -0
- package/dist/visio/collab/snapshot.d.ts +31 -24
- package/dist/visio/collab/snapshot.d.ts.map +1 -1
- package/dist/visio/collab/write-parts.d.ts +8 -0
- package/dist/visio/collab/write-parts.d.ts.map +1 -0
- package/dist/visio/collab/write-shapes.d.ts +30 -0
- package/dist/visio/collab/write-shapes.d.ts.map +1 -0
- package/dist/visio/collab/write.d.ts +4 -16
- package/dist/visio/collab/write.d.ts.map +1 -1
- package/dist/visio/collab/zip-store.d.ts +4 -0
- package/dist/visio/collab/zip-store.d.ts.map +1 -0
- package/dist/visio/document-level.d.ts +57 -0
- package/dist/visio/document-level.d.ts.map +1 -0
- package/dist/visio/index.cjs +485 -333
- package/dist/visio/index.d.ts +2 -0
- package/dist/visio/index.d.ts.map +1 -1
- package/dist/visio/index.mjs +484 -334
- package/dist/visio/layers.d.ts +3 -0
- package/dist/visio/layers.d.ts.map +1 -1
- package/dist/visio/package.d.ts +9 -0
- package/dist/visio/package.d.ts.map +1 -1
- package/dist/visio/parse-incremental.d.ts +16 -0
- package/dist/visio/parse-incremental.d.ts.map +1 -0
- package/dist/visio/parser.d.ts +14 -0
- package/dist/visio/parser.d.ts.map +1 -1
- package/dist/visio/shape-metadata.d.ts +3 -0
- package/dist/visio/shape-metadata.d.ts.map +1 -1
- package/dist/visio/ui/collab-options.d.ts +10 -5
- package/dist/visio/ui/collab-options.d.ts.map +1 -1
- package/dist/visio/ui/contract.d.ts +27 -2
- package/dist/visio/ui/contract.d.ts.map +1 -1
- package/dist/visio/ui/customization.d.ts +46 -0
- package/dist/visio/ui/customization.d.ts.map +1 -0
- package/dist/visio/ui/index.cjs +460 -320
- package/dist/visio/ui/index.d.ts +1 -0
- package/dist/visio/ui/index.d.ts.map +1 -1
- package/dist/visio/ui/index.mjs +458 -321
- package/dist/xlsx/ui/commands.d.ts +2 -0
- package/dist/xlsx/ui/commands.d.ts.map +1 -1
- package/dist/xlsx/ui/customization.d.ts +49 -0
- package/dist/xlsx/ui/customization.d.ts.map +1 -0
- package/dist/xlsx/ui/index.cjs +39 -1
- package/dist/xlsx/ui/index.d.ts +1 -0
- package/dist/xlsx/ui/index.d.ts.map +1 -1
- package/dist/xlsx/ui/index.mjs +37 -2
- package/package.json +6 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { AutomationFormat, AutomationTool } from './tools/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Runs the headless document tools against editors that are open on screen. A host's own
|
|
4
|
+
* assistant (or the suite's) registers each mounted editor under an id it chooses, and every call
|
|
5
|
+
* names the document it acts on: there is no "current document", so a chat that spans several
|
|
6
|
+
* tabs can never edit the wrong one. The tools are the same definitions the MCP servers use;
|
|
7
|
+
* this only adds the snapshot and load-back around them.
|
|
8
|
+
*/
|
|
9
|
+
/** What a mounted editor must offer. The editor elements fit it through `liveEditorFromElement`. */
|
|
10
|
+
export interface LiveEditor {
|
|
11
|
+
readonly format: AutomationFormat;
|
|
12
|
+
/** The open document as a file, including unsaved edits. */
|
|
13
|
+
save(): Promise<Uint8Array> | Uint8Array;
|
|
14
|
+
/** Replaces the open document with `bytes`. */
|
|
15
|
+
load(bytes: Uint8Array): Promise<void> | void;
|
|
16
|
+
/** True while the editor refuses edits (a read-only role, a locked document). */
|
|
17
|
+
readonly readOnly?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** A tool call: the target document, then the tool's own parameters. */
|
|
20
|
+
export interface LiveToolCall {
|
|
21
|
+
/** The id the editor was registered under. Required: there is no default document. */
|
|
22
|
+
target: string;
|
|
23
|
+
params?: unknown;
|
|
24
|
+
}
|
|
25
|
+
export interface LiveToolResult {
|
|
26
|
+
target: string;
|
|
27
|
+
tool: string;
|
|
28
|
+
/** What the tool returned: a read's view, an edit's report. */
|
|
29
|
+
result: unknown;
|
|
30
|
+
/** True when an edit changed the open document. */
|
|
31
|
+
changed: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** What an edit is about to do, for a host that wants to confirm it first. */
|
|
34
|
+
export interface LiveEditProposal {
|
|
35
|
+
target: string;
|
|
36
|
+
tool: string;
|
|
37
|
+
params: unknown;
|
|
38
|
+
/** The tool's report for the edit (warnings, results). */
|
|
39
|
+
result: unknown;
|
|
40
|
+
/** The file before and after, for a diff. */
|
|
41
|
+
before: Uint8Array;
|
|
42
|
+
after: Uint8Array;
|
|
43
|
+
}
|
|
44
|
+
export interface LiveToolHostOptions {
|
|
45
|
+
/**
|
|
46
|
+
* Called with each edit before it reaches the editor. Return false to discard it. Leave it out
|
|
47
|
+
* to apply edits straight away.
|
|
48
|
+
*/
|
|
49
|
+
review?(proposal: LiveEditProposal): boolean | Promise<boolean>;
|
|
50
|
+
}
|
|
51
|
+
export interface LiveToolDescriptor {
|
|
52
|
+
name: string;
|
|
53
|
+
description: string;
|
|
54
|
+
kind: 'read' | 'edit';
|
|
55
|
+
format: AutomationFormat;
|
|
56
|
+
/** JSON Schema of the parameters, with the required `target` added. */
|
|
57
|
+
inputSchema: Record<string, unknown>;
|
|
58
|
+
}
|
|
59
|
+
export interface LiveToolHost {
|
|
60
|
+
/** Registers an editor under `id`. Returns a function that removes it. */
|
|
61
|
+
register(id: string, editor: LiveEditor): () => void;
|
|
62
|
+
/** The registered documents, so an assistant can offer them to the model. */
|
|
63
|
+
targets(): {
|
|
64
|
+
id: string;
|
|
65
|
+
format: AutomationFormat;
|
|
66
|
+
readOnly: boolean;
|
|
67
|
+
}[];
|
|
68
|
+
/** The read and edit tools that apply to the registered documents, as function-calling specs. */
|
|
69
|
+
describe(): LiveToolDescriptor[];
|
|
70
|
+
call(name: string, call: LiveToolCall): Promise<LiveToolResult>;
|
|
71
|
+
}
|
|
72
|
+
/** `tools` is the catalogue to serve: `automationTools.docx`, `pptxTools` and so on, in any mix. */
|
|
73
|
+
export declare function createLiveToolHost(tools: readonly AutomationTool[], options?: LiveToolHostOptions): LiveToolHost;
|
|
74
|
+
/** The members of an editor element that `liveEditorFromElement` uses. */
|
|
75
|
+
export interface LiveEditorElement {
|
|
76
|
+
saveBytes?(): Promise<Uint8Array> | Uint8Array;
|
|
77
|
+
exportVsdx?(): Promise<{
|
|
78
|
+
bytes: Uint8Array;
|
|
79
|
+
}>;
|
|
80
|
+
load(bytes: Uint8Array, name?: string): Promise<unknown> | unknown;
|
|
81
|
+
commitEdit?(): boolean;
|
|
82
|
+
readOnly?: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Adapts a mounted editor element (`<docx-editor>`, `<xlsx-editor>`, `<pptx-editor>`,
|
|
86
|
+
* `<visio-editor>`) so it can be registered with a host. `name` is the file name the editor shows.
|
|
87
|
+
*/
|
|
88
|
+
export declare function liveEditorFromElement(format: AutomationFormat, element: LiveEditorElement, name?: string): LiveEditor;
|
|
89
|
+
//# sourceMappingURL=live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../automation/live.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import type { CollaborationRole } from './identity.js';
|
|
|
3
3
|
import type { ConnectionStatus, ProviderFactory } from './provider.js';
|
|
4
4
|
import { type CollabSession } from './session.js';
|
|
5
5
|
import { type WebrtcOptions } from './webrtc-provider.js';
|
|
6
|
+
import type { CollaborationWriteBackState } from './write-back.js';
|
|
6
7
|
/** Who this window is in the room. */
|
|
7
8
|
export interface CollaborationUser {
|
|
8
9
|
/** Display name; each editor falls back to its own author name. */
|
|
@@ -58,6 +59,12 @@ export interface CollaborationState {
|
|
|
58
59
|
/** The first exchange with the room finished. */
|
|
59
60
|
synced: boolean;
|
|
60
61
|
people: Collaborator[];
|
|
62
|
+
/**
|
|
63
|
+
* The owner's write-back (`onWriteBack`), present only in the window that writes back. `saved`
|
|
64
|
+
* means the host's callback returned (or its promise resolved): the host's acknowledgement and
|
|
65
|
+
* nothing more.
|
|
66
|
+
*/
|
|
67
|
+
writeBack?: CollaborationWriteBackState;
|
|
61
68
|
}
|
|
62
69
|
/** The event every editor element dispatches, with a {@link CollaborationState} detail. */
|
|
63
70
|
export declare const COLLABORATION_CHANGE_EVENT = "collaboration-change";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../collab/embedding.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAoB,MAAM,qBAAqB,CAAC;AAC7E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,KAAK,aAAa,EAAuB,MAAM,WAAW,CAAC;AAGpE,OAAO,EAAE,KAAK,aAAa,EAAkB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../collab/embedding.ts"],"names":[],"mappings":"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"}
|
package/dist/collab/index.cjs
CHANGED
|
@@ -1523,6 +1523,191 @@ function freezeDeep(value) {
|
|
|
1523
1523
|
return value;
|
|
1524
1524
|
}
|
|
1525
1525
|
|
|
1526
|
+
// collab/write-back.ts
|
|
1527
|
+
var DEFAULT_WRITE_BACK_DEBOUNCE_MS = 5e3;
|
|
1528
|
+
var DEFAULT_RETRY_BASE_MS = 1e3;
|
|
1529
|
+
var DEFAULT_RETRY_MAX_MS = 3e4;
|
|
1530
|
+
var globalTimers = {
|
|
1531
|
+
setTimeout: (callback, ms) => globalThis.setTimeout(callback, ms),
|
|
1532
|
+
clearTimeout: (handle) => globalThis.clearTimeout(handle)
|
|
1533
|
+
};
|
|
1534
|
+
var isThenable = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
|
|
1535
|
+
function writeBackStateOf(state) {
|
|
1536
|
+
const out = { status: state.status };
|
|
1537
|
+
if (state.lastSavedAt !== void 0) out.lastSavedAt = state.lastSavedAt;
|
|
1538
|
+
if (state.status === "failed" && state.lastError !== void 0) {
|
|
1539
|
+
out.error = state.lastError instanceof Error ? state.lastError.message : String(state.lastError);
|
|
1540
|
+
}
|
|
1541
|
+
return out;
|
|
1542
|
+
}
|
|
1543
|
+
function createWriteBackScheduler(options) {
|
|
1544
|
+
const timers = options.timers ?? globalTimers;
|
|
1545
|
+
const now = options.now ?? Date.now;
|
|
1546
|
+
const configured = options.debounceMs;
|
|
1547
|
+
const debounceMs = configured !== void 0 && Number.isFinite(configured) && configured >= 0 ? configured : DEFAULT_WRITE_BACK_DEBOUNCE_MS;
|
|
1548
|
+
const attempts = Math.max(1, Math.floor(options.retry?.attempts ?? 1) || 1);
|
|
1549
|
+
const baseDelay = Math.max(0, options.retry?.baseDelayMs ?? DEFAULT_RETRY_BASE_MS);
|
|
1550
|
+
const maxDelay = Math.max(baseDelay, options.retry?.maxDelayMs ?? DEFAULT_RETRY_MAX_MS);
|
|
1551
|
+
let state = { status: "idle" };
|
|
1552
|
+
let generation = 0;
|
|
1553
|
+
let disposed = false;
|
|
1554
|
+
let dirty = false;
|
|
1555
|
+
let timer = null;
|
|
1556
|
+
let running = null;
|
|
1557
|
+
let wake = null;
|
|
1558
|
+
let ended = false;
|
|
1559
|
+
let rushing = 0;
|
|
1560
|
+
const patch = (status, extra = {}) => {
|
|
1561
|
+
const next = { status };
|
|
1562
|
+
const saved = extra.lastSavedAt ?? state.lastSavedAt;
|
|
1563
|
+
if (saved !== void 0) next.lastSavedAt = saved;
|
|
1564
|
+
if (extra.lastError !== void 0) next.lastError = extra.lastError;
|
|
1565
|
+
state = next;
|
|
1566
|
+
options.onStatus?.(state);
|
|
1567
|
+
};
|
|
1568
|
+
const clearTimer = () => {
|
|
1569
|
+
if (timer !== null) timers.clearTimeout(timer);
|
|
1570
|
+
timer = null;
|
|
1571
|
+
};
|
|
1572
|
+
const arm = () => {
|
|
1573
|
+
clearTimer();
|
|
1574
|
+
timer = timers.setTimeout(() => {
|
|
1575
|
+
timer = null;
|
|
1576
|
+
void start();
|
|
1577
|
+
}, debounceMs);
|
|
1578
|
+
if (state.status !== "pending") patch("pending");
|
|
1579
|
+
};
|
|
1580
|
+
const sleep = (ms) => new Promise((resolve) => {
|
|
1581
|
+
if (rushing > 0) return resolve();
|
|
1582
|
+
const handle = timers.setTimeout(done, ms);
|
|
1583
|
+
function done() {
|
|
1584
|
+
timers.clearTimeout(handle);
|
|
1585
|
+
wake = null;
|
|
1586
|
+
resolve();
|
|
1587
|
+
}
|
|
1588
|
+
wake = done;
|
|
1589
|
+
});
|
|
1590
|
+
const settledStatus = () => state.lastSavedAt === void 0 ? "idle" : "saved";
|
|
1591
|
+
async function run() {
|
|
1592
|
+
const gen = generation;
|
|
1593
|
+
const isCurrent = () => gen === generation;
|
|
1594
|
+
patch("saving");
|
|
1595
|
+
try {
|
|
1596
|
+
for (let attempt = 1; ; attempt++) {
|
|
1597
|
+
dirty = false;
|
|
1598
|
+
try {
|
|
1599
|
+
let bytes = options.serialize({ isCurrent });
|
|
1600
|
+
if (isThenable(bytes)) bytes = await bytes;
|
|
1601
|
+
if (!isCurrent()) return;
|
|
1602
|
+
if (bytes === null || bytes === void 0) {
|
|
1603
|
+
if (dirty) arm();
|
|
1604
|
+
else patch(settledStatus());
|
|
1605
|
+
return;
|
|
1606
|
+
}
|
|
1607
|
+
const acknowledged = options.write(bytes);
|
|
1608
|
+
if (isThenable(acknowledged)) await acknowledged;
|
|
1609
|
+
if (!isCurrent()) return;
|
|
1610
|
+
const lastSavedAt = now();
|
|
1611
|
+
if (dirty) {
|
|
1612
|
+
patch("pending", { lastSavedAt });
|
|
1613
|
+
arm();
|
|
1614
|
+
} else {
|
|
1615
|
+
patch("saved", { lastSavedAt });
|
|
1616
|
+
}
|
|
1617
|
+
return;
|
|
1618
|
+
} catch (error) {
|
|
1619
|
+
if (!isCurrent()) return;
|
|
1620
|
+
if (attempt >= attempts) {
|
|
1621
|
+
dirty = true;
|
|
1622
|
+
patch("failed", { lastError: error });
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1625
|
+
await sleep(Math.min(maxDelay, baseDelay * 2 ** (attempt - 1)));
|
|
1626
|
+
if (!isCurrent()) return;
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
} finally {
|
|
1630
|
+
ended = true;
|
|
1631
|
+
running = null;
|
|
1632
|
+
if (dirty && timer === null && !disposed && state.status !== "failed") arm();
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
function start() {
|
|
1636
|
+
if (running) return running;
|
|
1637
|
+
ended = false;
|
|
1638
|
+
const promise = run();
|
|
1639
|
+
if (!ended) running = promise;
|
|
1640
|
+
return promise;
|
|
1641
|
+
}
|
|
1642
|
+
function cancel() {
|
|
1643
|
+
generation++;
|
|
1644
|
+
clearTimer();
|
|
1645
|
+
dirty = false;
|
|
1646
|
+
const waiting = wake;
|
|
1647
|
+
wake = null;
|
|
1648
|
+
waiting?.();
|
|
1649
|
+
if (state.status === "pending" || state.status === "saving") patch(settledStatus());
|
|
1650
|
+
}
|
|
1651
|
+
return {
|
|
1652
|
+
schedule() {
|
|
1653
|
+
if (disposed) return;
|
|
1654
|
+
dirty = true;
|
|
1655
|
+
if (running) return;
|
|
1656
|
+
arm();
|
|
1657
|
+
},
|
|
1658
|
+
async flush() {
|
|
1659
|
+
if (disposed) return;
|
|
1660
|
+
clearTimer();
|
|
1661
|
+
rushing++;
|
|
1662
|
+
try {
|
|
1663
|
+
wake?.();
|
|
1664
|
+
for (; ; ) {
|
|
1665
|
+
if (running) await running;
|
|
1666
|
+
else if (dirty) await start();
|
|
1667
|
+
else return;
|
|
1668
|
+
if (disposed) return;
|
|
1669
|
+
if (state.status === "failed") throw state.lastError;
|
|
1670
|
+
clearTimer();
|
|
1671
|
+
}
|
|
1672
|
+
} finally {
|
|
1673
|
+
rushing--;
|
|
1674
|
+
}
|
|
1675
|
+
},
|
|
1676
|
+
cancel,
|
|
1677
|
+
dispose() {
|
|
1678
|
+
if (disposed) return;
|
|
1679
|
+
cancel();
|
|
1680
|
+
disposed = true;
|
|
1681
|
+
},
|
|
1682
|
+
get state() {
|
|
1683
|
+
return state;
|
|
1684
|
+
},
|
|
1685
|
+
get dirty() {
|
|
1686
|
+
return dirty;
|
|
1687
|
+
}
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
// collab/write-back-lifecycle.ts
|
|
1692
|
+
function flushWriteBackOnPageClose(scheduler, options = {}) {
|
|
1693
|
+
const globals = globalThis;
|
|
1694
|
+
const win = options.window === void 0 ? typeof globals.addEventListener === "function" ? globalThis : null : options.window;
|
|
1695
|
+
const doc = options.document === void 0 ? globals.document ?? null : options.document;
|
|
1696
|
+
const flush = () => {
|
|
1697
|
+
if (!scheduler.dirty) return;
|
|
1698
|
+
scheduler.flush().catch((error) => options.onError?.(error));
|
|
1699
|
+
};
|
|
1700
|
+
const hidden = () => {
|
|
1701
|
+
if (doc?.visibilityState === "hidden") flush();
|
|
1702
|
+
};
|
|
1703
|
+
win?.addEventListener("pagehide", flush);
|
|
1704
|
+
doc?.addEventListener("visibilitychange", hidden);
|
|
1705
|
+
return () => {
|
|
1706
|
+
win?.removeEventListener("pagehide", flush);
|
|
1707
|
+
doc?.removeEventListener("visibilitychange", hidden);
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1526
1711
|
exports.BROADCAST_THROTTLE_MS = BROADCAST_THROTTLE_MS;
|
|
1527
1712
|
exports.BoundedMap = BoundedMap;
|
|
1528
1713
|
exports.COLLABORATION_CHANGE_EVENT = COLLABORATION_CHANGE_EVENT;
|
|
@@ -1533,6 +1718,7 @@ exports.CONNECTION_TIMEOUT_MS = CONNECTION_TIMEOUT_MS;
|
|
|
1533
1718
|
exports.CURSOR_PALETTE = CURSOR_PALETTE;
|
|
1534
1719
|
exports.DEFAULT_COLOR = DEFAULT_COLOR;
|
|
1535
1720
|
exports.DEFAULT_MAX_PACKAGE_BYTES = DEFAULT_MAX_PACKAGE_BYTES;
|
|
1721
|
+
exports.DEFAULT_WRITE_BACK_DEBOUNCE_MS = DEFAULT_WRITE_BACK_DEBOUNCE_MS;
|
|
1536
1722
|
exports.DEPARTURE_CHANNEL = DEPARTURE_CHANNEL;
|
|
1537
1723
|
exports.Emitter = Emitter;
|
|
1538
1724
|
exports.INITIAL_SYNC_GRACE_MS = INITIAL_SYNC_GRACE_MS;
|
|
@@ -1575,11 +1761,13 @@ exports.createPresencePublisher = createPresencePublisher;
|
|
|
1575
1761
|
exports.createSyncGate = createSyncGate;
|
|
1576
1762
|
exports.createTransportProvider = createTransportProvider;
|
|
1577
1763
|
exports.createWebSocketTransport = createWebSocketTransport;
|
|
1764
|
+
exports.createWriteBackScheduler = createWriteBackScheduler;
|
|
1578
1765
|
exports.deriveCanvasPresence = deriveCanvasPresence;
|
|
1579
1766
|
exports.derivePresence = derivePresence;
|
|
1580
1767
|
exports.encodeDiff = encodeDiff;
|
|
1581
1768
|
exports.encodeSnapshot = encodeSnapshot;
|
|
1582
1769
|
exports.encodeStateVector = encodeStateVector2;
|
|
1770
|
+
exports.flushWriteBackOnPageClose = flushWriteBackOnPageClose;
|
|
1583
1771
|
exports.formatCursorLabel = formatCursorLabel;
|
|
1584
1772
|
exports.freezeDeep = freezeDeep;
|
|
1585
1773
|
exports.fromBase64 = fromBase64;
|
|
@@ -1617,3 +1805,4 @@ exports.validateDisplayName = validateDisplayName;
|
|
|
1617
1805
|
exports.validateRoomId = validateRoomId;
|
|
1618
1806
|
exports.validateUpdate = validateUpdate;
|
|
1619
1807
|
exports.webrtcProvider = webrtcProvider;
|
|
1808
|
+
exports.writeBackStateOf = writeBackStateOf;
|
package/dist/collab/index.d.ts
CHANGED
|
@@ -19,4 +19,6 @@ export * from './transport-provider.js';
|
|
|
19
19
|
export * from './validation.js';
|
|
20
20
|
export * from './webrtc-provider.js';
|
|
21
21
|
export * from './websocket-transport.js';
|
|
22
|
+
export * from './write-back.js';
|
|
23
|
+
export * from './write-back-lifecycle.js';
|
|
22
24
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../collab/index.ts"],"names":[],"mappings":"AAIA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,uBAAuB,CAAC;AACtC,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../collab/index.ts"],"names":[],"mappings":"AAIA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,uBAAuB,CAAC;AACtC,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,wBAAwB,CAAC"}
|
package/dist/collab/index.mjs
CHANGED
|
@@ -1499,4 +1499,189 @@ function freezeDeep(value) {
|
|
|
1499
1499
|
return value;
|
|
1500
1500
|
}
|
|
1501
1501
|
|
|
1502
|
-
|
|
1502
|
+
// collab/write-back.ts
|
|
1503
|
+
var DEFAULT_WRITE_BACK_DEBOUNCE_MS = 5e3;
|
|
1504
|
+
var DEFAULT_RETRY_BASE_MS = 1e3;
|
|
1505
|
+
var DEFAULT_RETRY_MAX_MS = 3e4;
|
|
1506
|
+
var globalTimers = {
|
|
1507
|
+
setTimeout: (callback, ms) => globalThis.setTimeout(callback, ms),
|
|
1508
|
+
clearTimeout: (handle) => globalThis.clearTimeout(handle)
|
|
1509
|
+
};
|
|
1510
|
+
var isThenable = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
|
|
1511
|
+
function writeBackStateOf(state) {
|
|
1512
|
+
const out = { status: state.status };
|
|
1513
|
+
if (state.lastSavedAt !== void 0) out.lastSavedAt = state.lastSavedAt;
|
|
1514
|
+
if (state.status === "failed" && state.lastError !== void 0) {
|
|
1515
|
+
out.error = state.lastError instanceof Error ? state.lastError.message : String(state.lastError);
|
|
1516
|
+
}
|
|
1517
|
+
return out;
|
|
1518
|
+
}
|
|
1519
|
+
function createWriteBackScheduler(options) {
|
|
1520
|
+
const timers = options.timers ?? globalTimers;
|
|
1521
|
+
const now = options.now ?? Date.now;
|
|
1522
|
+
const configured = options.debounceMs;
|
|
1523
|
+
const debounceMs = configured !== void 0 && Number.isFinite(configured) && configured >= 0 ? configured : DEFAULT_WRITE_BACK_DEBOUNCE_MS;
|
|
1524
|
+
const attempts = Math.max(1, Math.floor(options.retry?.attempts ?? 1) || 1);
|
|
1525
|
+
const baseDelay = Math.max(0, options.retry?.baseDelayMs ?? DEFAULT_RETRY_BASE_MS);
|
|
1526
|
+
const maxDelay = Math.max(baseDelay, options.retry?.maxDelayMs ?? DEFAULT_RETRY_MAX_MS);
|
|
1527
|
+
let state = { status: "idle" };
|
|
1528
|
+
let generation = 0;
|
|
1529
|
+
let disposed = false;
|
|
1530
|
+
let dirty = false;
|
|
1531
|
+
let timer = null;
|
|
1532
|
+
let running = null;
|
|
1533
|
+
let wake = null;
|
|
1534
|
+
let ended = false;
|
|
1535
|
+
let rushing = 0;
|
|
1536
|
+
const patch = (status, extra = {}) => {
|
|
1537
|
+
const next = { status };
|
|
1538
|
+
const saved = extra.lastSavedAt ?? state.lastSavedAt;
|
|
1539
|
+
if (saved !== void 0) next.lastSavedAt = saved;
|
|
1540
|
+
if (extra.lastError !== void 0) next.lastError = extra.lastError;
|
|
1541
|
+
state = next;
|
|
1542
|
+
options.onStatus?.(state);
|
|
1543
|
+
};
|
|
1544
|
+
const clearTimer = () => {
|
|
1545
|
+
if (timer !== null) timers.clearTimeout(timer);
|
|
1546
|
+
timer = null;
|
|
1547
|
+
};
|
|
1548
|
+
const arm = () => {
|
|
1549
|
+
clearTimer();
|
|
1550
|
+
timer = timers.setTimeout(() => {
|
|
1551
|
+
timer = null;
|
|
1552
|
+
void start();
|
|
1553
|
+
}, debounceMs);
|
|
1554
|
+
if (state.status !== "pending") patch("pending");
|
|
1555
|
+
};
|
|
1556
|
+
const sleep = (ms) => new Promise((resolve) => {
|
|
1557
|
+
if (rushing > 0) return resolve();
|
|
1558
|
+
const handle = timers.setTimeout(done, ms);
|
|
1559
|
+
function done() {
|
|
1560
|
+
timers.clearTimeout(handle);
|
|
1561
|
+
wake = null;
|
|
1562
|
+
resolve();
|
|
1563
|
+
}
|
|
1564
|
+
wake = done;
|
|
1565
|
+
});
|
|
1566
|
+
const settledStatus = () => state.lastSavedAt === void 0 ? "idle" : "saved";
|
|
1567
|
+
async function run() {
|
|
1568
|
+
const gen = generation;
|
|
1569
|
+
const isCurrent = () => gen === generation;
|
|
1570
|
+
patch("saving");
|
|
1571
|
+
try {
|
|
1572
|
+
for (let attempt = 1; ; attempt++) {
|
|
1573
|
+
dirty = false;
|
|
1574
|
+
try {
|
|
1575
|
+
let bytes = options.serialize({ isCurrent });
|
|
1576
|
+
if (isThenable(bytes)) bytes = await bytes;
|
|
1577
|
+
if (!isCurrent()) return;
|
|
1578
|
+
if (bytes === null || bytes === void 0) {
|
|
1579
|
+
if (dirty) arm();
|
|
1580
|
+
else patch(settledStatus());
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
const acknowledged = options.write(bytes);
|
|
1584
|
+
if (isThenable(acknowledged)) await acknowledged;
|
|
1585
|
+
if (!isCurrent()) return;
|
|
1586
|
+
const lastSavedAt = now();
|
|
1587
|
+
if (dirty) {
|
|
1588
|
+
patch("pending", { lastSavedAt });
|
|
1589
|
+
arm();
|
|
1590
|
+
} else {
|
|
1591
|
+
patch("saved", { lastSavedAt });
|
|
1592
|
+
}
|
|
1593
|
+
return;
|
|
1594
|
+
} catch (error) {
|
|
1595
|
+
if (!isCurrent()) return;
|
|
1596
|
+
if (attempt >= attempts) {
|
|
1597
|
+
dirty = true;
|
|
1598
|
+
patch("failed", { lastError: error });
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
await sleep(Math.min(maxDelay, baseDelay * 2 ** (attempt - 1)));
|
|
1602
|
+
if (!isCurrent()) return;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
} finally {
|
|
1606
|
+
ended = true;
|
|
1607
|
+
running = null;
|
|
1608
|
+
if (dirty && timer === null && !disposed && state.status !== "failed") arm();
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
function start() {
|
|
1612
|
+
if (running) return running;
|
|
1613
|
+
ended = false;
|
|
1614
|
+
const promise = run();
|
|
1615
|
+
if (!ended) running = promise;
|
|
1616
|
+
return promise;
|
|
1617
|
+
}
|
|
1618
|
+
function cancel() {
|
|
1619
|
+
generation++;
|
|
1620
|
+
clearTimer();
|
|
1621
|
+
dirty = false;
|
|
1622
|
+
const waiting = wake;
|
|
1623
|
+
wake = null;
|
|
1624
|
+
waiting?.();
|
|
1625
|
+
if (state.status === "pending" || state.status === "saving") patch(settledStatus());
|
|
1626
|
+
}
|
|
1627
|
+
return {
|
|
1628
|
+
schedule() {
|
|
1629
|
+
if (disposed) return;
|
|
1630
|
+
dirty = true;
|
|
1631
|
+
if (running) return;
|
|
1632
|
+
arm();
|
|
1633
|
+
},
|
|
1634
|
+
async flush() {
|
|
1635
|
+
if (disposed) return;
|
|
1636
|
+
clearTimer();
|
|
1637
|
+
rushing++;
|
|
1638
|
+
try {
|
|
1639
|
+
wake?.();
|
|
1640
|
+
for (; ; ) {
|
|
1641
|
+
if (running) await running;
|
|
1642
|
+
else if (dirty) await start();
|
|
1643
|
+
else return;
|
|
1644
|
+
if (disposed) return;
|
|
1645
|
+
if (state.status === "failed") throw state.lastError;
|
|
1646
|
+
clearTimer();
|
|
1647
|
+
}
|
|
1648
|
+
} finally {
|
|
1649
|
+
rushing--;
|
|
1650
|
+
}
|
|
1651
|
+
},
|
|
1652
|
+
cancel,
|
|
1653
|
+
dispose() {
|
|
1654
|
+
if (disposed) return;
|
|
1655
|
+
cancel();
|
|
1656
|
+
disposed = true;
|
|
1657
|
+
},
|
|
1658
|
+
get state() {
|
|
1659
|
+
return state;
|
|
1660
|
+
},
|
|
1661
|
+
get dirty() {
|
|
1662
|
+
return dirty;
|
|
1663
|
+
}
|
|
1664
|
+
};
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
// collab/write-back-lifecycle.ts
|
|
1668
|
+
function flushWriteBackOnPageClose(scheduler, options = {}) {
|
|
1669
|
+
const globals = globalThis;
|
|
1670
|
+
const win = options.window === void 0 ? typeof globals.addEventListener === "function" ? globalThis : null : options.window;
|
|
1671
|
+
const doc = options.document === void 0 ? globals.document ?? null : options.document;
|
|
1672
|
+
const flush = () => {
|
|
1673
|
+
if (!scheduler.dirty) return;
|
|
1674
|
+
scheduler.flush().catch((error) => options.onError?.(error));
|
|
1675
|
+
};
|
|
1676
|
+
const hidden = () => {
|
|
1677
|
+
if (doc?.visibilityState === "hidden") flush();
|
|
1678
|
+
};
|
|
1679
|
+
win?.addEventListener("pagehide", flush);
|
|
1680
|
+
doc?.addEventListener("visibilitychange", hidden);
|
|
1681
|
+
return () => {
|
|
1682
|
+
win?.removeEventListener("pagehide", flush);
|
|
1683
|
+
doc?.removeEventListener("visibilitychange", hidden);
|
|
1684
|
+
};
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
export { BROADCAST_THROTTLE_MS, BoundedMap, COLLABORATION_CHANGE_EVENT, COLLABORATION_OFF_STATE, COLLABORATION_ROLES, COLLAB_LEAVE_MESSAGE, CONNECTION_TIMEOUT_MS, CURSOR_PALETTE, DEFAULT_COLOR, DEFAULT_MAX_PACKAGE_BYTES, DEFAULT_WRITE_BACK_DEBOUNCE_MS, DEPARTURE_CHANNEL, Emitter, INITIAL_SYNC_GRACE_MS, INVALID_ROOM_MESSAGE, IdempotencyCache, LEGACY_PPTX_DEPARTURE_CHANNEL, LEGACY_PPTX_LEAVE_MESSAGE, LOCAL_ORIGIN, MAX_LABEL_CHARS, MAX_UPDATE_BYTES, MESSAGE_AWARENESS, MESSAGE_QUERY_AWARENESS, MESSAGE_SYNC, NO_BROADCAST_MESSAGE, PRESENCE_FIELD, PRESENCE_HEARTBEAT_MS, STALE_PRESENCE_MS, SequenceTracker, adaptYjsProvider, applyUpdateSafe, asSelectionIds, assignUserColor, bindDocument, borrowAwareness, buildRoster, canBroadcast, canWrite, clampCoordinate, classifyVersion, clearLocalAwareness, collaborationStateOf, createAssetSync, createBroadcastTransport, createClientId, createCollabSession, createDepartureChannel, createIdGenerator, createMemoryHub, createPresencePublisher, createSyncGate, createTransportProvider, createWebSocketTransport, createWriteBackScheduler, deriveCanvasPresence, derivePresence, encodeDiff, encodeSnapshot, encodeStateVector2 as encodeStateVector, flushWriteBackOnPageClose, formatCursorLabel, freezeDeep, fromBase64, getUserInitials, isMixedContentBlocked, isNonNegativeSafeInteger, isPresenceFresh, isValidId, isValidRoomId, mergeUpdates2 as mergeUpdates, observeExternalSession, onCollaborationStateChange, openCollaborationSession, packageAdapter, presenceToCursors, randomToken, registerTeardown, removeAwarenessStatesLocally, restoreSnapshot, roomUrl, sanitizeAvatarUrl, sanitizeCanvasPayload, sanitizeColor, sanitizeIdentity, sanitizeIndex, sanitizeRole, sanitizeUserName, shouldAutoFollowBroadcaster, shouldRoomReplaceLoad, stripHtmlTags, toBase64, toExternalSession, transportProvider, validateDisplayName, validateRoomId, validateUpdate, webrtcProvider, writeBackStateOf };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { WriteBackScheduler } from './write-back.js';
|
|
2
|
+
/** The part of `window` used: `pagehide` is listened on it. */
|
|
3
|
+
export interface PageHideTarget {
|
|
4
|
+
addEventListener(type: 'pagehide', listener: () => void): void;
|
|
5
|
+
removeEventListener(type: 'pagehide', listener: () => void): void;
|
|
6
|
+
}
|
|
7
|
+
/** The part of `document` used: `visibilitychange` is listened on it. */
|
|
8
|
+
export interface VisibilityTarget {
|
|
9
|
+
readonly visibilityState?: string;
|
|
10
|
+
addEventListener(type: 'visibilitychange', listener: () => void): void;
|
|
11
|
+
removeEventListener(type: 'visibilitychange', listener: () => void): void;
|
|
12
|
+
}
|
|
13
|
+
export interface FlushOnPageCloseOptions {
|
|
14
|
+
/** Default `globalThis` when it can listen (a browser window), otherwise no `pagehide` hook. */
|
|
15
|
+
window?: PageHideTarget | null;
|
|
16
|
+
/** Default `globalThis.document` when present. */
|
|
17
|
+
document?: VisibilityTarget | null;
|
|
18
|
+
/** Receives a flush that failed (it never throws). Default ignores it. */
|
|
19
|
+
onError?: (error: unknown) => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Flushes `scheduler` on `pagehide` and when the page turns hidden, and returns the function that
|
|
23
|
+
* removes the listeners. Only unsaved work is written.
|
|
24
|
+
*
|
|
25
|
+
* Browsers do not wait for asynchronous work when a page unloads: the flush starts the write, but
|
|
26
|
+
* a write that needs a network round trip can still be lost on close. A host that must survive a
|
|
27
|
+
* close should send the bytes with `navigator.sendBeacon(url, bytes)` or
|
|
28
|
+
* `fetch(url, { method: 'PUT', body: bytes, keepalive: true })` (the browser caps keepalive bodies
|
|
29
|
+
* at about 64 KiB, so a large document may still not make it), which the browser completes after
|
|
30
|
+
* the page is gone.
|
|
31
|
+
*/
|
|
32
|
+
export declare function flushWriteBackOnPageClose(scheduler: Pick<WriteBackScheduler, 'flush' | 'dirty'>, options?: FlushOnPageCloseOptions): () => void;
|
|
33
|
+
//# sourceMappingURL=write-back-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-back-lifecycle.d.ts","sourceRoot":"","sources":["../../collab/write-back-lifecycle.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC9B,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC/D,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAClE;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACvE,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAC1E;AAED,MAAM,WAAW,uBAAuB;IACvC,gGAAgG;IAChG,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,kDAAkD;IAClD,QAAQ,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACnC,0EAA0E;IAC1E,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACnC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACxC,SAAS,EAAE,IAAI,CAAC,kBAAkB,EAAE,OAAO,GAAG,OAAO,CAAC,EACtD,OAAO,GAAE,uBAA4B,GACnC,MAAM,IAAI,CAyBZ"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** Where a write-back stands: `idle` until the first change, then `pending`, `saving`, `saved` or `failed`. */
|
|
2
|
+
export type WriteBackStatus = 'idle' | 'pending' | 'saving' | 'saved' | 'failed';
|
|
3
|
+
/** What {@link WriteBackScheduler.state} and `onStatus` report. */
|
|
4
|
+
export interface WriteBackState {
|
|
5
|
+
status: WriteBackStatus;
|
|
6
|
+
/** `now()` when the host last acknowledged a write. */
|
|
7
|
+
lastSavedAt?: number;
|
|
8
|
+
/** The error of the last failed write, once its retries are spent. */
|
|
9
|
+
lastError?: unknown;
|
|
10
|
+
}
|
|
11
|
+
/** The write-back status as an editor reports it in its collaboration state (JSON friendly). */
|
|
12
|
+
export interface CollaborationWriteBackState {
|
|
13
|
+
status: WriteBackStatus;
|
|
14
|
+
lastSavedAt?: number;
|
|
15
|
+
/** The message of the last failure, while `status` is `failed`. */
|
|
16
|
+
error?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface WriteBackRetry {
|
|
19
|
+
/** Total tries per write, the first included. 1 (the default) never retries. */
|
|
20
|
+
attempts: number;
|
|
21
|
+
/** Wait before the first retry; doubles on each further retry. Default 1000. */
|
|
22
|
+
baseDelayMs?: number;
|
|
23
|
+
/** Upper bound of the wait. Default 30000. */
|
|
24
|
+
maxDelayMs?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface WriteBackTimers {
|
|
27
|
+
setTimeout(callback: () => void, ms: number): unknown;
|
|
28
|
+
clearTimeout(handle: unknown): void;
|
|
29
|
+
}
|
|
30
|
+
export interface WriteBackOptions {
|
|
31
|
+
/**
|
|
32
|
+
* The bytes to store now. Resolve `null` when there is nothing to save yet (the change is not
|
|
33
|
+
* lost: call `schedule()` again when it is). `isCurrent` turns false once the scheduler was
|
|
34
|
+
* cancelled or disposed, so a long serialisation can stop early.
|
|
35
|
+
*/
|
|
36
|
+
serialize: (context: {
|
|
37
|
+
isCurrent: () => boolean;
|
|
38
|
+
}) => Uint8Array | null | Promise<Uint8Array | null>;
|
|
39
|
+
/**
|
|
40
|
+
* Stores the bytes. A returned promise is the acknowledgement: resolving means stored, rejecting
|
|
41
|
+
* counts as a failed try. A plain return (void) is treated as acknowledged at once.
|
|
42
|
+
*/
|
|
43
|
+
write: (bytes: Uint8Array) => void | Promise<void>;
|
|
44
|
+
/** Quiet time after the last change. Default 5000; invalid values fall back to it. */
|
|
45
|
+
debounceMs?: number;
|
|
46
|
+
retry?: WriteBackRetry;
|
|
47
|
+
onStatus?: (state: WriteBackState) => void;
|
|
48
|
+
/** Clock for `lastSavedAt`. Default `Date.now`. */
|
|
49
|
+
now?: () => number;
|
|
50
|
+
/** Timers, injectable for tests. Default the global ones, looked up at call time. */
|
|
51
|
+
timers?: WriteBackTimers;
|
|
52
|
+
}
|
|
53
|
+
export interface WriteBackScheduler {
|
|
54
|
+
/** Notes a change: (re)starts the quiet time, or queues one follow-up write during a write. */
|
|
55
|
+
schedule(): void;
|
|
56
|
+
/**
|
|
57
|
+
* Writes now and resolves once the host acknowledged it (and anything changed meanwhile).
|
|
58
|
+
* Resolves at once when nothing is unsaved; rejects with the last error when the write failed
|
|
59
|
+
* after its retries. When `serialize` and `write` return synchronously, the write has been
|
|
60
|
+
* handed over before `flush` returns.
|
|
61
|
+
*/
|
|
62
|
+
flush(): Promise<void>;
|
|
63
|
+
/** Drops pending work and ignores the result of a write in flight; the scheduler stays usable. */
|
|
64
|
+
cancel(): void;
|
|
65
|
+
/** Cancels and stops for good: later calls do nothing. */
|
|
66
|
+
dispose(): void;
|
|
67
|
+
readonly state: WriteBackState;
|
|
68
|
+
/** True while a change waits for its quiet time or a write (or its retry) is under way. */
|
|
69
|
+
readonly dirty: boolean;
|
|
70
|
+
}
|
|
71
|
+
export declare const DEFAULT_WRITE_BACK_DEBOUNCE_MS = 5000;
|
|
72
|
+
/** The status of `state` for a collaboration state; the error becomes its message. */
|
|
73
|
+
export declare function writeBackStateOf(state: WriteBackState): CollaborationWriteBackState;
|
|
74
|
+
export declare function createWriteBackScheduler(options: WriteBackOptions): WriteBackScheduler;
|
|
75
|
+
//# sourceMappingURL=write-back.d.ts.map
|