edytor 0.1.0-next.23 → 0.1.0-next.25
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 +1 -1
- package/dist/cloudflare/DocumentRoom.d.ts +264 -10
- package/dist/cloudflare/DocumentRoom.js +867 -58
- package/dist/cloudflare/history.d.ts +110 -0
- package/dist/cloudflare/history.js +125 -0
- package/dist/cloudflare/index.d.ts +4 -2
- package/dist/cloudflare/index.js +4 -2
- package/dist/cloudflare/routeDocumentSocket.d.ts +17 -0
- package/dist/cloudflare/routeDocumentSocket.js +82 -17
- package/dist/crdt/data.js +2 -1
- package/dist/crdt/document.d.ts +151 -0
- package/dist/crdt/document.js +11 -146
- package/dist/crdt/edytor-doc.d.ts +137 -4
- package/dist/crdt/edytor-doc.js +54 -2
- package/dist/crdt/engine.d.ts +3 -1
- package/dist/crdt/engine.js +4 -1
- package/dist/crdt/index.d.ts +29 -4
- package/dist/crdt/index.js +25 -1
- package/dist/crdt/migration/generation.d.ts +58 -0
- package/dist/crdt/migration/generation.js +68 -0
- package/dist/crdt/migration/migrate.js +1 -1
- package/dist/crdt/placement/model.d.ts +32 -0
- package/dist/crdt/placement/model.js +151 -7
- package/dist/crdt/placement/rank.d.ts +38 -24
- package/dist/crdt/placement/rank.js +147 -93
- package/dist/crdt/protocols/envelope.d.ts +9 -3
- package/dist/crdt/protocols/envelope.js +9 -3
- package/dist/crdt/protocols/sync.d.ts +13 -6
- package/dist/crdt/protocols/sync.js +31 -9
- package/dist/crdt/providers/index.js +2 -1
- package/dist/crdt/providers/indexeddb.d.ts +10 -0
- package/dist/crdt/providers/indexeddb.js +53 -6
- package/dist/crdt/providers/room.js +16 -1
- package/dist/crdt/purge.d.ts +46 -0
- package/dist/crdt/purge.js +206 -0
- package/dist/crdt/restore.d.ts +63 -0
- package/dist/crdt/restore.js +217 -0
- package/dist/crdt/schema.d.ts +9 -1
- package/dist/crdt/schema.js +12 -1
- package/dist/crdt/semantics.d.ts +46 -1
- package/dist/crdt/semantics.js +32 -3
- package/dist/crdt/text/deletes.d.ts +17 -0
- package/dist/crdt/text/deletes.js +218 -21
- package/dist/crdt/text/marks.d.ts +58 -0
- package/dist/crdt/text/marks.js +85 -0
- package/dist/crdt/text/model.d.ts +1 -0
- package/dist/crdt/text/model.js +33 -8
- package/dist/crdt/text/runs.js +48 -3
- package/dist/crdt/vendor/yjs/UPSTREAM.md +40 -0
- package/dist/crdt/vendor/yjs/dts/utils/Doc.d.ts +6 -0
- package/dist/crdt/vendor/yjs/dts/utils/marks.d.ts +83 -0
- package/dist/crdt/vendor/yjs/dts/utils/transaction-helpers.d.ts +1 -1
- package/dist/crdt/vendor/yjs/dts/ynode.d.ts +25 -0
- package/dist/crdt/vendor/yjs/src/structs/Item.js +12 -2
- package/dist/crdt/vendor/yjs/src/utils/Doc.js +6 -0
- package/dist/crdt/vendor/yjs/src/utils/RangeCursor.js +2 -0
- package/dist/crdt/vendor/yjs/src/utils/marks.js +149 -0
- package/dist/crdt/vendor/yjs/src/utils/transaction-helpers.js +10 -4
- package/dist/crdt/vendor/yjs/src/ynode.js +226 -2
- package/dist/edytor.svelte.js +19 -2
- package/dist/plugins/richtext/RichTextPlugin.svelte +2 -2
- package/dist/session/editing/text.d.ts +6 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
Edytor aims to be for Svelte what Slate.js is for React: a heavily customizable editor with an API to build any kind of collaborative rich text editor.
|
|
17
17
|
|
|
18
|
-
> **Work in progress.** Edytor is a pre-release (`0.1.0-next.
|
|
18
|
+
> **Work in progress.** Edytor is a pre-release (`0.1.0-next.25`, `edytor@next` on npm) and not ready for production; the API changes between releases without a compatibility layer. The untagged `edytor@0.0.11` on npm predates the current API. Issues and PRs are welcome: when you report a bug, include the document's JSON value.
|
|
19
19
|
|
|
20
20
|
## Features
|
|
21
21
|
|
|
@@ -95,6 +95,8 @@
|
|
|
95
95
|
*/
|
|
96
96
|
import { DurableObject } from 'cloudflare:workers';
|
|
97
97
|
import * as E from '../crdt/index.js';
|
|
98
|
+
import type { PurgeReport } from '../crdt/purge.js';
|
|
99
|
+
import { type HistoryEntry, type HistoryOptions, type KVLike } from './history.js';
|
|
98
100
|
import type { AwarenessEntry, DocumentSemanticsConfig, EdytorDoc, JSONBlock, JSONDoc, YDoc } from '../crdt/index.js';
|
|
99
101
|
/** Under SQLite-backed Durable Objects' 2 MB row cap, with room for the other columns. */
|
|
100
102
|
export declare const DEFAULT_MAX_ROW_BYTES: number;
|
|
@@ -135,6 +137,16 @@ export type ReplicaOwner = {
|
|
|
135
137
|
replica: number;
|
|
136
138
|
user: string;
|
|
137
139
|
};
|
|
140
|
+
/** What `restoreHistory` did (`room.history.restore`): `refused` when the room holds no such version. */
|
|
141
|
+
export type RestoreResult = {
|
|
142
|
+
status: 'applied' | 'noop' | 'refused';
|
|
143
|
+
key: string;
|
|
144
|
+
revived?: number;
|
|
145
|
+
moved?: number;
|
|
146
|
+
rewritten?: number;
|
|
147
|
+
created?: number;
|
|
148
|
+
deleted?: number;
|
|
149
|
+
};
|
|
138
150
|
/** The document as `onSave` receives it. */
|
|
139
151
|
export type SavedDocument = {
|
|
140
152
|
/** The document as JSON. */
|
|
@@ -154,6 +166,14 @@ export type LoadedDocument = JSONDoc | Uint8Array | Pick<SavedDocument, 'update'
|
|
|
154
166
|
export declare const PROBE_HEADER = "X-Edytor-Probe";
|
|
155
167
|
/** The transaction origin of the room's own edits (`transact`, `onLoad` seeds). */
|
|
156
168
|
export declare const ROOM_ORIGIN: unique symbol;
|
|
169
|
+
/** The transaction origin of a history restore (H11): the room's restore history tracks it. */
|
|
170
|
+
export declare const RESTORE_ORIGIN: unique symbol;
|
|
171
|
+
/** The transaction origin of the room's purge (H7): tracked by no history. */
|
|
172
|
+
export declare const PURGE_ORIGIN: unique symbol;
|
|
173
|
+
/** The header `routeDocumentHistory` sets on an authorized history request (H11). */
|
|
174
|
+
export declare const HISTORY_HEADER = "X-Edytor-History";
|
|
175
|
+
/** The version key of a history `read` or `restore` request. */
|
|
176
|
+
export declare const HISTORY_KEY_HEADER = "X-Edytor-History-Key";
|
|
157
177
|
/**
|
|
158
178
|
* Headers carrying the identity `routeDocumentSocket` verified — never the
|
|
159
179
|
* client's. The user id is percent-encoded (`encodeURIComponent`): a header
|
|
@@ -179,6 +199,17 @@ export type DocumentRoomEnv = {
|
|
|
179
199
|
EDYTOR_MAX_UPDATES_PER_SECOND?: string | number;
|
|
180
200
|
/** `off`: the room logs nothing (default: one JSON line per compaction, quota hit, denial, fault). */
|
|
181
201
|
EDYTOR_LOG?: string;
|
|
202
|
+
/**
|
|
203
|
+
* Days after which deleted content is purged (H7; default: the history
|
|
204
|
+
* retention, else 30); `off` never purges.
|
|
205
|
+
*/
|
|
206
|
+
EDYTOR_PURGE_AFTER_DAYS?: string | number;
|
|
207
|
+
/** A KV namespace binding: the room keeps its version history there (H11, `history()`). */
|
|
208
|
+
EDYTOR_HISTORY?: KVLike;
|
|
209
|
+
/** Days a version is kept (default 30). */
|
|
210
|
+
EDYTOR_HISTORY_RETENTION_DAYS?: string | number;
|
|
211
|
+
/** The IANA time zone of the history's half-day slots (default `UTC`). */
|
|
212
|
+
EDYTOR_HISTORY_TIME_ZONE?: string;
|
|
182
213
|
};
|
|
183
214
|
/** What a socket is bound to: its verified user, its replica (Yjs client id), its access. */
|
|
184
215
|
export type SocketIdentity = {
|
|
@@ -192,7 +223,7 @@ export type Attachment = SocketIdentity & {
|
|
|
192
223
|
clock: number | null;
|
|
193
224
|
};
|
|
194
225
|
export type Refusal = {
|
|
195
|
-
reason: 'generation' | 'schema' | 'malformed' | 'container' | 'identity' | 'replica' | 'read-only' | 'waiting' | 'storage' | 'internal' | 'quota' | 'mark' | 'denied' | 'orphan' | 'relayed';
|
|
226
|
+
reason: 'generation' | 'schema' | 'malformed' | 'container' | 'identity' | 'replica' | 'read-only' | 'waiting' | 'storage' | 'internal' | 'quota' | 'mark' | 'denied' | 'orphan' | 'relayed' | 'history';
|
|
196
227
|
detail: unknown;
|
|
197
228
|
};
|
|
198
229
|
/** A duration series: how many, their total and longest (ms; see {@link RoomMetrics}). */
|
|
@@ -239,6 +270,17 @@ export type RoomMetrics = {
|
|
|
239
270
|
validationDenials: number;
|
|
240
271
|
/** Every refusal, by reason (as `refusalCounts`). */
|
|
241
272
|
refusals: Partial<Record<Refusal['reason'], number>>;
|
|
273
|
+
/** Versions written to the history (H11), skipped (`history` refusals), and the last key written. */
|
|
274
|
+
history: {
|
|
275
|
+
written: number;
|
|
276
|
+
skipped: number;
|
|
277
|
+
lastKey: string | null;
|
|
278
|
+
};
|
|
279
|
+
/** Purges run (H7) and what they wrote, summed; the last horizon purged (ms since the epoch). */
|
|
280
|
+
purge: PurgeReport & {
|
|
281
|
+
runs: number;
|
|
282
|
+
horizon: number | null;
|
|
283
|
+
};
|
|
242
284
|
/** When this instance started (ms since the epoch). */
|
|
243
285
|
since: number;
|
|
244
286
|
};
|
|
@@ -250,6 +292,20 @@ export type RoomLogEntry = {
|
|
|
250
292
|
records: number;
|
|
251
293
|
rows: number;
|
|
252
294
|
} | {
|
|
295
|
+
edytor: 'history';
|
|
296
|
+
key: string;
|
|
297
|
+
bytes: number;
|
|
298
|
+
editors: number;
|
|
299
|
+
} | {
|
|
300
|
+
edytor: 'restore';
|
|
301
|
+
key: string;
|
|
302
|
+
user: string | null;
|
|
303
|
+
undo: boolean;
|
|
304
|
+
} | ({
|
|
305
|
+
edytor: 'purge';
|
|
306
|
+
horizon: number;
|
|
307
|
+
bytes: number;
|
|
308
|
+
} & PurgeReport) | {
|
|
253
309
|
edytor: 'quota';
|
|
254
310
|
user: string;
|
|
255
311
|
quota: string;
|
|
@@ -261,6 +317,12 @@ export type RoomLogEntry = {
|
|
|
261
317
|
edytor: 'fault';
|
|
262
318
|
reason: 'storage' | 'internal';
|
|
263
319
|
detail: string;
|
|
320
|
+
} | {
|
|
321
|
+
edytor: 'convert';
|
|
322
|
+
from: number;
|
|
323
|
+
to: number;
|
|
324
|
+
blocks: number;
|
|
325
|
+
bytes: number;
|
|
264
326
|
};
|
|
265
327
|
/** `pending`: deletes of items the room does not hold yet (they wait for them). */
|
|
266
328
|
type RowKind = 'generation' | 'update' | 'snapshot' | 'pending';
|
|
@@ -375,6 +437,22 @@ export type AttachDocumentOptions = {
|
|
|
375
437
|
* {@link E.defaultSemantics} (the bundled rich-text, code and image kinds).
|
|
376
438
|
*/
|
|
377
439
|
semantics?: DocumentSemanticsConfig;
|
|
440
|
+
/**
|
|
441
|
+
* Version history in KV (H11, `room.history.*`): the room writes its
|
|
442
|
+
* state twice a day — the morning's at local noon, the evening's at
|
|
443
|
+
* midnight, in `timeZone` — when it changed, for `retentionDays`; read
|
|
444
|
+
* and restore them with `listHistory`, `readHistory`, `restoreHistory`
|
|
445
|
+
* and `undoRestore` (or `routeDocumentHistory`). Without it, no history.
|
|
446
|
+
*/
|
|
447
|
+
history?: HistoryOptions;
|
|
448
|
+
/**
|
|
449
|
+
* Days after which deleted content is purged from the room and every
|
|
450
|
+
* replica (H7, `room.purge.*`): default the history's `retentionDays`,
|
|
451
|
+
* else 30; `false` never purges.
|
|
452
|
+
*/
|
|
453
|
+
purgeAfterDays?: number | false;
|
|
454
|
+
/** The room's clock, ms since the epoch (default `Date.now`): its slots, epochs and alarm read it. */
|
|
455
|
+
now?: () => number;
|
|
378
456
|
};
|
|
379
457
|
/** The tag of the document's sockets: other sockets of the object are left to you. */
|
|
380
458
|
export declare const SOCKET_TAG = "edytor";
|
|
@@ -409,6 +487,10 @@ export declare class AttachedDocument {
|
|
|
409
487
|
} | {
|
|
410
488
|
kind: 'restored';
|
|
411
489
|
records: number;
|
|
490
|
+
} | {
|
|
491
|
+
kind: 'converted';
|
|
492
|
+
from: number;
|
|
493
|
+
records: number;
|
|
412
494
|
};
|
|
413
495
|
private nextRecord;
|
|
414
496
|
private updates;
|
|
@@ -442,14 +524,33 @@ export declare class AttachedDocument {
|
|
|
442
524
|
private retryable;
|
|
443
525
|
private readonly sql;
|
|
444
526
|
private _facade;
|
|
445
|
-
private saveScheduled;
|
|
446
527
|
/** Alarms in a row that found the rows unreadable: each re-arms later. */
|
|
447
528
|
private saveRetries;
|
|
529
|
+
/** Each alarm task's due time (`room.alarm.tasks`), mirrored in the meta table (`due.<task>`). */
|
|
530
|
+
private dues;
|
|
531
|
+
/** The alarm this instance set, or found set at its start (`null`: none). */
|
|
532
|
+
private armed;
|
|
533
|
+
/** The room's clock (`now`). */
|
|
534
|
+
private readonly clock;
|
|
535
|
+
/** The verified users the open slot recorded (memory: a wake records them again, `OR IGNORE`). */
|
|
536
|
+
private readonly slotEditors;
|
|
537
|
+
/** Who the room writes for while a restore or its undo runs (the slot's editor). */
|
|
538
|
+
private writer;
|
|
539
|
+
/** The last restore's step (`room.history.undo`), read from the `restore` table at load. */
|
|
540
|
+
private restoreStep;
|
|
541
|
+
/** The history recording restores (`RESTORE_ORIGIN`), on the live facade. */
|
|
542
|
+
private restoreManager;
|
|
543
|
+
/** The version writes in flight (`historyWritten()`). */
|
|
544
|
+
private writing;
|
|
448
545
|
private readonly options;
|
|
449
546
|
private readonly rowsTable;
|
|
450
547
|
private readonly replicasTable;
|
|
451
548
|
private readonly metaTable;
|
|
549
|
+
private readonly epochsTable;
|
|
550
|
+
private readonly editorsTable;
|
|
551
|
+
private readonly restoreTable;
|
|
452
552
|
private _lookups;
|
|
553
|
+
private _history;
|
|
453
554
|
constructor(ctx: DurableObjectState, options?: AttachDocumentOptions);
|
|
454
555
|
/**
|
|
455
556
|
* Restore from storage, or seed from `onLoad`. Never throws: a throw
|
|
@@ -508,15 +609,33 @@ export declare class AttachedDocument {
|
|
|
508
609
|
/** The document as JSON. */
|
|
509
610
|
read(): JSONDoc;
|
|
510
611
|
/**
|
|
511
|
-
*
|
|
512
|
-
*
|
|
513
|
-
*
|
|
514
|
-
* alarm is set
|
|
515
|
-
*
|
|
612
|
+
* The room's one alarm (`room.alarm.tasks`): every task due at its time
|
|
613
|
+
* runs — the history slot (`room.history.slots`), `onSave`, the purge
|
|
614
|
+
* (`room.purge.timing`) — each re-arming itself or clearing its due
|
|
615
|
+
* row; then the alarm is set to the earliest due time left. While the
|
|
616
|
+
* rows cannot be read (a retryable failure), it starts the room again;
|
|
617
|
+
* if that fails too, the save stays due, later at each failure (up to 5
|
|
618
|
+
* minutes), so the mirror never silently lags what the room stored. A
|
|
619
|
+
* throw from `onSave` keeps it due and is rethrown (the platform retries).
|
|
516
620
|
*/
|
|
517
621
|
alarm(): Promise<void>;
|
|
518
|
-
/** The
|
|
622
|
+
/** The `save` task: `onSave` with the document, or the save kept due while the rows cannot be read. */
|
|
623
|
+
private save;
|
|
624
|
+
/** The first unsaved change arms the save alarm; a save already due keeps its time. */
|
|
519
625
|
private scheduleSave;
|
|
626
|
+
/**
|
|
627
|
+
* Arm `task` at `at` (`room.alarm.tasks`): a task already due keeps its
|
|
628
|
+
* time (a wake or an edit never moves a pending save), unless `earlier`
|
|
629
|
+
* (an earlier time wins: the purge tick) or `replace`. The due time is
|
|
630
|
+
* stored (meta `due.<task>`) and the alarm set to the earliest one.
|
|
631
|
+
*/
|
|
632
|
+
private schedule;
|
|
633
|
+
/** Clear `task`'s due time. */
|
|
634
|
+
private unschedule;
|
|
635
|
+
/** Set the alarm to the earliest due time (none due: the alarm set is left, and finds nothing). */
|
|
636
|
+
private arm;
|
|
637
|
+
/** The due times stored (`due.<task>`); an alarm armed by 0.1.0-next.23 (none stored) is a due save. */
|
|
638
|
+
private readDues;
|
|
520
639
|
/**
|
|
521
640
|
* Generation cutover: drop the stored document (both tables) of a room
|
|
522
641
|
* whose storage belongs to another edytor generation, and start again
|
|
@@ -542,6 +661,18 @@ export declare class AttachedDocument {
|
|
|
542
661
|
* engine refuses) is refused for good.
|
|
543
662
|
*/
|
|
544
663
|
private load;
|
|
664
|
+
/**
|
|
665
|
+
* The generation cutover at load (`room.generation.convert`): the
|
|
666
|
+
* records of a generation-4 container are read as JSON
|
|
667
|
+
* (`crdt.generations.previousJSON`), which this generation seeds as
|
|
668
|
+
* `onLoad`'s JSON is (deterministic: every replica converting the same
|
|
669
|
+
* state writes the same update), and the container is replaced by it in
|
|
670
|
+
* one storage transaction: rows, replicas, purge epochs, slot editors
|
|
671
|
+
* and the stored restore go; the document data, the alarm's due tasks
|
|
672
|
+
* and `lastUpdated` stay. What a generation-4 client never sent is not
|
|
673
|
+
* in it; history, attribution and CRDT identity do not cross.
|
|
674
|
+
*/
|
|
675
|
+
private convert;
|
|
545
676
|
/** The bytes of the stored `pending` records (uncompressed, as every record but a snapshot). */
|
|
546
677
|
private pendingBytes;
|
|
547
678
|
/**
|
|
@@ -600,6 +731,93 @@ export declare class AttachedDocument {
|
|
|
600
731
|
* (`GET <room>?lastUpdated`), also over RPC.
|
|
601
732
|
*/
|
|
602
733
|
lastUpdated(): number | null;
|
|
734
|
+
/** The room's id: its name (`getByName`), else the object's id. */
|
|
735
|
+
private get roomId();
|
|
736
|
+
/** The history settings, resolved at first use (`null`: none; an unknown time zone is noted `history`). */
|
|
737
|
+
private get historyConfig();
|
|
738
|
+
/** Days after which deleted content is purged (`null`: never), `room.purge.timing`. */
|
|
739
|
+
private get purgeDays();
|
|
740
|
+
/** The last restore's deleted content, kept for its undo (`prepareRoomDoc`). */
|
|
741
|
+
private get restoreKeep();
|
|
742
|
+
/** The verified user a stored change is written for (a socket's, or the restorer's), or `null`. */
|
|
743
|
+
private editorOf;
|
|
744
|
+
/**
|
|
745
|
+
* A change was stored: arm the purge tick (`room.purge.timing`) and open
|
|
746
|
+
* the history slot it falls in (`room.history.slots`) — a purge opens
|
|
747
|
+
* none: it changes nothing a reader sees.
|
|
748
|
+
*/
|
|
749
|
+
private noteChange;
|
|
750
|
+
/** Before a write: a slot past its end is captured as it is, and written (`room.history.slots`). */
|
|
751
|
+
private closeSlotIfPast;
|
|
752
|
+
/** Close the open slot: capture it now, write it (the alarm, a start past its end). */
|
|
753
|
+
private closeSlot;
|
|
754
|
+
/**
|
|
755
|
+
* The open slot's version, read now (synchronous: nothing writes
|
|
756
|
+
* between the read and the slot's close), and the slot closed.
|
|
757
|
+
*/
|
|
758
|
+
private captureSlot;
|
|
759
|
+
/** Write a captured version (`room.history.value`); a failure is noted `history` and the slot skipped. */
|
|
760
|
+
private putSlot;
|
|
761
|
+
private skipVersion;
|
|
762
|
+
/** The history settings, or a throw: the room keeps no history. */
|
|
763
|
+
private requireHistory;
|
|
764
|
+
/**
|
|
765
|
+
* Resolves once the versions the room is writing are stored (a slot a
|
|
766
|
+
* write closed is written in the background).
|
|
767
|
+
*/
|
|
768
|
+
historyWritten(): Promise<void>;
|
|
769
|
+
/**
|
|
770
|
+
* The room's versions, newest first (H11): one per half-day slot that
|
|
771
|
+
* changed, for the retention (`room.history.slots`). Throws when the
|
|
772
|
+
* room keeps no history.
|
|
773
|
+
*/
|
|
774
|
+
listHistory(): Promise<HistoryEntry[]>;
|
|
775
|
+
/** Version `key` as JSON (a preview), or `null` when this room holds no such version. */
|
|
776
|
+
readHistory(key: string): Promise<JSONDoc | null>;
|
|
777
|
+
/**
|
|
778
|
+
* Restore version `key` as a forward edit (`room.history.restore`): one
|
|
779
|
+
* room transaction makes the visible document equal the version, keeping
|
|
780
|
+
* every id the registry holds and writing only what differs; stored,
|
|
781
|
+
* relayed to every socket, one step `undoRestore` undoes. `user` (the
|
|
782
|
+
* restorer) is recorded as the slot's editor and in the log. `refused`:
|
|
783
|
+
* this room holds no such version (expired, another room's key).
|
|
784
|
+
*/
|
|
785
|
+
restoreHistory(key: string, options?: {
|
|
786
|
+
user?: string;
|
|
787
|
+
}): Promise<RestoreResult>;
|
|
788
|
+
/**
|
|
789
|
+
* Undo the last restore (`room.history.undo`): the history undo of
|
|
790
|
+
* exactly its transaction, edits made since kept. One level: `noop` when
|
|
791
|
+
* no restore stands (none, undone already, or past the purge horizon).
|
|
792
|
+
*/
|
|
793
|
+
undoRestore(options?: {
|
|
794
|
+
user?: string;
|
|
795
|
+
}): Promise<{
|
|
796
|
+
status: 'applied' | 'noop';
|
|
797
|
+
}>;
|
|
798
|
+
/** The history recording restores, on the live facade (`RESTORE_ORIGIN` only, one step each). */
|
|
799
|
+
private restoreHistoryOf;
|
|
800
|
+
/** The last restore's step, from its table (`null`: none). */
|
|
801
|
+
private readRestore;
|
|
802
|
+
/**
|
|
803
|
+
* Forget the last restore's step: its table row goes, then what it kept
|
|
804
|
+
* is released and collected (the next compaction stores it collected).
|
|
805
|
+
*/
|
|
806
|
+
private dropRestore;
|
|
807
|
+
/**
|
|
808
|
+
* The purge task, also over RPC (`room.purge.timing`): record an epoch
|
|
809
|
+
* (the state vector, now) when the document changed since the last one,
|
|
810
|
+
* purge what was deleted before the horizon — the newest epoch at least
|
|
811
|
+
* `purgeAfterDays` old — when it is newer than the last purged, and
|
|
812
|
+
* re-arm for the next epoch to pass it. Returns what the purge wrote, or
|
|
813
|
+
* `null` when nothing was past the horizon.
|
|
814
|
+
*/
|
|
815
|
+
purge(): (PurgeReport & {
|
|
816
|
+
horizon: number;
|
|
817
|
+
}) | null;
|
|
818
|
+
private tick;
|
|
819
|
+
/** Purge what was deleted before `horizon`, as the room's own transaction, then compact. */
|
|
820
|
+
private purgeTo;
|
|
603
821
|
/** The room's counters (H14), also over RPC — see {@link RoomMetrics}. */
|
|
604
822
|
metrics(): RoomMetrics;
|
|
605
823
|
/** What the rows take: bytes, logical records, rows. */
|
|
@@ -687,6 +905,13 @@ export declare class AttachedDocument {
|
|
|
687
905
|
*/
|
|
688
906
|
private attribute;
|
|
689
907
|
fetch(request: Request): Promise<Response>;
|
|
908
|
+
/**
|
|
909
|
+
* One history request (H11): `list`, `read` (a version as JSON), and,
|
|
910
|
+
* for a write identity, `restore` and `undo`. `404` when the room keeps
|
|
911
|
+
* no history or holds no such version, `403` for a read-only identity's
|
|
912
|
+
* write, `503` when the room cannot serve it.
|
|
913
|
+
*/
|
|
914
|
+
private historyRequest;
|
|
690
915
|
/** Is `ws` one of this document's sockets? */
|
|
691
916
|
owns(ws: WebSocket): boolean;
|
|
692
917
|
webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): boolean;
|
|
@@ -806,7 +1031,8 @@ export declare class AttachedDocument {
|
|
|
806
1031
|
* `edytor_replicas`) live beside yours and its sockets carry
|
|
807
1032
|
* {@link SOCKET_TAG}. Each handler your class does not define —
|
|
808
1033
|
* `fetch`, `webSocketMessage`, `webSocketClose`, `webSocketError`, and
|
|
809
|
-
* `alarm`
|
|
1034
|
+
* `alarm` unless the document needs none (no `onSave`, no `history`,
|
|
1035
|
+
* `purgeAfterDays: false`) — is installed on the object; a class that
|
|
810
1036
|
* defines one delegates to the returned document's method (which returns
|
|
811
1037
|
* `false` for a socket that is not the document's).
|
|
812
1038
|
*/
|
|
@@ -840,12 +1066,40 @@ export declare class DocumentRoom<Env = DocumentRoomEnv> extends DurableObject<E
|
|
|
840
1066
|
* at first use (after construction: it may return a subclass field).
|
|
841
1067
|
*/
|
|
842
1068
|
protected semantics(): DocumentSemanticsConfig;
|
|
1069
|
+
/**
|
|
1070
|
+
* Version history — see {@link AttachDocumentOptions.history}. Default:
|
|
1071
|
+
* the `EDYTOR_HISTORY` KV binding, with `EDYTOR_HISTORY_RETENTION_DAYS`
|
|
1072
|
+
* and `EDYTOR_HISTORY_TIME_ZONE`; none without it. Read once, at first use.
|
|
1073
|
+
*/
|
|
1074
|
+
protected history(): HistoryOptions | undefined;
|
|
1075
|
+
/** The room's clock — see {@link AttachDocumentOptions.now}. */
|
|
1076
|
+
protected now(): number;
|
|
843
1077
|
fetch(request: Request): Promise<Response>;
|
|
844
1078
|
webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): void;
|
|
845
1079
|
webSocketClose(ws: WebSocket, code: number, reason: string): void;
|
|
846
1080
|
webSocketError(ws: WebSocket): void;
|
|
847
|
-
/** Runs `onSave
|
|
1081
|
+
/** Runs the room's tasks: `onSave`, the history slots, the purge. Call `super.alarm()` if you override it. */
|
|
848
1082
|
alarm(): Promise<void>;
|
|
1083
|
+
/** The versions, newest first, also over RPC — see {@link AttachedDocument.listHistory}. */
|
|
1084
|
+
listHistory(): Promise<HistoryEntry[]>;
|
|
1085
|
+
/** A version as JSON, also over RPC — see {@link AttachedDocument.readHistory}. */
|
|
1086
|
+
readHistory(key: string): Promise<JSONDoc | null>;
|
|
1087
|
+
/** Restore a version, also over RPC — see {@link AttachedDocument.restoreHistory}. */
|
|
1088
|
+
restoreHistory(key: string, options?: {
|
|
1089
|
+
user?: string;
|
|
1090
|
+
}): Promise<RestoreResult>;
|
|
1091
|
+
/** Undo the last restore, also over RPC — see {@link AttachedDocument.undoRestore}. */
|
|
1092
|
+
undoRestore(options?: {
|
|
1093
|
+
user?: string;
|
|
1094
|
+
}): Promise<{
|
|
1095
|
+
status: 'applied' | 'noop';
|
|
1096
|
+
}>;
|
|
1097
|
+
/** The version writes in flight, also over RPC — see {@link AttachedDocument.historyWritten}. */
|
|
1098
|
+
historyWritten(): Promise<void>;
|
|
1099
|
+
/** Run the purge task now, also over RPC — see {@link AttachedDocument.purge}. */
|
|
1100
|
+
purge(): (PurgeReport & {
|
|
1101
|
+
horizon: number;
|
|
1102
|
+
}) | null;
|
|
849
1103
|
/** Compaction, also over RPC. */
|
|
850
1104
|
compact(): {
|
|
851
1105
|
rows: number;
|