edytor 5.0.0 → 7.0.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 +3 -3
- package/dist/cloudflare/DocumentRoom.d.ts +77 -2
- package/dist/cloudflare/DocumentRoom.js +37 -1
- package/dist/cloudflare/index.d.ts +1 -1
- package/dist/cloudflare/index.js +1 -1
- package/dist/cloudflare/room/access.d.ts +6 -1
- package/dist/cloudflare/room/access.js +30 -4
- package/dist/cloudflare/room/admission.d.ts +11 -0
- package/dist/cloudflare/room/admission.js +43 -10
- package/dist/cloudflare/room/context.d.ts +73 -76
- package/dist/cloudflare/room/context.js +17 -6
- package/dist/cloudflare/room/forged.d.ts +1 -1
- package/dist/cloudflare/room/forged.js +11 -9
- package/dist/cloudflare/room/frames.d.ts +2 -0
- package/dist/cloudflare/room/frames.js +2 -0
- package/dist/cloudflare/room/presence.js +1 -4
- package/dist/cloudflare/room/reseed.d.ts +93 -0
- package/dist/cloudflare/room/reseed.js +500 -0
- package/dist/cloudflare/room/scheduler.d.ts +1 -1
- package/dist/cloudflare/room/scheduler.js +9 -1
- package/dist/cloudflare/room/shared.d.ts +10 -0
- package/dist/cloudflare/room/shared.js +10 -0
- package/dist/cloudflare/room/storage.d.ts +7 -0
- package/dist/cloudflare/room/storage.js +33 -1
- package/dist/components/Edytor.svelte +18 -3
- package/dist/components/Edytor.svelte.d.ts +10 -1
- package/dist/components/EdytorRoot.svelte +17 -0
- package/dist/components/EdytorRoot.svelte.d.ts +4 -0
- package/dist/components/Suggestion.svelte +1 -1
- package/dist/crdt/attribution/block.d.ts +3 -0
- package/dist/crdt/attribution/block.js +3 -2
- package/dist/crdt/doc/history.js +2 -3
- package/dist/crdt/doc/ops.d.ts +81 -0
- package/dist/crdt/doc/ops.js +1898 -0
- package/dist/crdt/doc/suggest.d.ts +6 -2
- package/dist/crdt/doc/suggest.js +6 -5
- package/dist/crdt/edytor-doc.d.ts +157 -157
- package/dist/crdt/edytor-doc.js +15 -43
- package/dist/crdt/engine-room.d.ts +4 -0
- package/dist/crdt/engine-room.js +6 -0
- package/dist/crdt/flow.d.ts +4 -46
- package/dist/crdt/flow.js +2 -262
- package/dist/crdt/index.d.ts +64 -75
- package/dist/crdt/operations.d.ts +1 -1
- package/dist/crdt/placement/resolve.d.ts +1 -1
- package/dist/crdt/protocol.d.ts +2 -2
- package/dist/crdt/protocol.js +2 -2
- package/dist/crdt/protocols/auth.d.ts +8 -1
- package/dist/crdt/protocols/auth.js +14 -1
- package/dist/crdt/protocols/awareness.js +46 -81
- package/dist/crdt/providers/index.d.ts +11 -22
- package/dist/crdt/providers/index.js +22 -3
- package/dist/crdt/providers/indexeddb.d.ts +6 -10
- package/dist/crdt/providers/indexeddb.js +10 -16
- package/dist/crdt/providers/room.d.ts +26 -0
- package/dist/crdt/providers/room.js +41 -12
- package/dist/crdt/providers/websocket.d.ts +10 -14
- package/dist/crdt/providers/websocket.js +43 -23
- package/dist/crdt/rangeDelete.d.ts +2 -47
- package/dist/crdt/rangeDelete.js +1 -169
- package/dist/crdt/reseed.d.ts +127 -0
- package/dist/crdt/reseed.js +533 -0
- package/dist/crdt/restore.d.ts +13 -1
- package/dist/crdt/restore.js +8 -3
- package/dist/crdt/schema.d.ts +6 -0
- package/dist/crdt/schema.js +6 -0
- package/dist/crdt/structs.d.ts +8 -11
- package/dist/crdt/structs.js +25 -44
- package/dist/crdt/text/index/build.d.ts +119 -0
- package/dist/crdt/text/index/build.js +2801 -0
- package/dist/crdt/text/index/shared.d.ts +2 -6
- package/dist/crdt/text/index/shared.js +2 -5
- package/dist/crdt/text/model.js +2 -3
- package/dist/crdt/text/runs.d.ts +9 -12
- package/dist/crdt/text/runs.js +2 -165
- package/dist/crdt/vendor/yjs/UPSTREAM.md +101 -5
- package/dist/crdt/vendor/yjs/dts/index.d.ts +1 -1
- package/dist/crdt/vendor/yjs/dts/utils/Transaction.d.ts +10 -10
- package/dist/crdt/vendor/yjs/dts/utils/encoding.d.ts +1 -0
- package/dist/crdt/vendor/yjs/src/index.js +1 -1
- package/dist/crdt/vendor/yjs/src/structs/Item.js +24 -13
- package/dist/crdt/vendor/yjs/src/utils/Transaction.js +12 -10
- package/dist/crdt/vendor/yjs/src/utils/encoding.js +42 -1
- package/dist/events/domTextOffset.d.ts +2 -0
- package/dist/events/domTextOffset.js +8 -0
- package/dist/export/forms.d.ts +50 -50
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/plugins/richtext/RichTextPlugin.svelte +63 -61
- package/dist/plugins/richtext/richTextOperations.js +26 -32
- package/dist/selection/selection.svelte.d.ts +1 -1
- package/dist/selection/selection.svelte.js +87 -106
- package/dist/selection/selection.utils.js +5 -8
- package/dist/session/commands.js +49 -51
- package/dist/session/handles.js +3 -7
- package/dist/surface/attributes.d.ts +3 -3
- package/dist/surface/attributes.js +2 -2
- package/dist/surface/observer.svelte.d.ts +7 -7
- package/dist/surface/observer.svelte.js +225 -336
- package/dist/surface/projector.svelte.js +2 -2
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +7 -0
- package/package.json +1 -1
- package/dist/crdt/doc/capability.d.ts +0 -56
- package/dist/crdt/doc/capability.js +0 -207
- package/dist/crdt/doc/content.d.ts +0 -16
- package/dist/crdt/doc/content.js +0 -77
- package/dist/crdt/doc/delete.d.ts +0 -15
- package/dist/crdt/doc/delete.js +0 -84
- package/dist/crdt/doc/layout.d.ts +0 -9
- package/dist/crdt/doc/layout.js +0 -178
- package/dist/crdt/doc/meta.d.ts +0 -19
- package/dist/crdt/doc/meta.js +0 -198
- package/dist/crdt/doc/moves.d.ts +0 -21
- package/dist/crdt/doc/moves.js +0 -274
- package/dist/crdt/doc/split-merge.d.ts +0 -10
- package/dist/crdt/doc/split-merge.js +0 -179
- package/dist/crdt/doc/steps.d.ts +0 -65
- package/dist/crdt/doc/steps.js +0 -311
- package/dist/crdt/text/index/cache.d.ts +0 -16
- package/dist/crdt/text/index/cache.js +0 -175
- package/dist/crdt/text/index/claims.d.ts +0 -18
- package/dist/crdt/text/index/claims.js +0 -203
- package/dist/crdt/text/index/fold.d.ts +0 -21
- package/dist/crdt/text/index/fold.js +0 -656
- package/dist/crdt/text/index/layout.d.ts +0 -22
- package/dist/crdt/text/index/layout.js +0 -258
- package/dist/crdt/text/index/placement.d.ts +0 -47
- package/dist/crdt/text/index/placement.js +0 -738
- package/dist/crdt/text/index/records.d.ts +0 -13
- package/dist/crdt/text/index/records.js +0 -139
- package/dist/crdt/text/index/report.d.ts +0 -18
- package/dist/crdt/text/index/report.js +0 -337
- package/dist/crdt/text/index/state.d.ts +0 -197
- package/dist/crdt/text/index/state.js +0 -116
- package/dist/crdt/text/index/streams.d.ts +0 -25
- package/dist/crdt/text/index/streams.js +0 -248
package/dist/crdt/protocol.js
CHANGED
|
@@ -30,9 +30,9 @@ export { bindCrdt } from './index.js';
|
|
|
30
30
|
export { SCHEMA_VERSION, META_KEY } from './edytor-doc.js';
|
|
31
31
|
export { GENERATION, generationWord, frame, PROTOCOL_VERSION, GENERATION_RECORD, GenerationMismatchError, readProtocolVersion } from './protocols/envelope.js';
|
|
32
32
|
// ── Message types, acknowledgements and chunks ─────────────────────────
|
|
33
|
-
export { messageSync, messageAwareness, messageAuth, messageQueryAwareness, messageSaved, messageChunk, messageComments, MAX_FRAME_BYTES, chunkFrame, createChunkReader, ChunkError, CLOSE } from './providers/room.js';
|
|
33
|
+
export { messageSync, messageAwareness, messageAuth, messageQueryAwareness, messageSaved, messageChunk, messageComments, messageRebase, MAX_FRAME_BYTES, chunkFrame, createChunkReader, ChunkError, CLOSE } from './providers/room.js';
|
|
34
34
|
export { messageYjsSyncStep1, messageYjsSyncStep2, messageYjsUpdate } from './protocols/sync.js';
|
|
35
|
-
export { messageAccess, messagePermissionDenied, messageReadOnly, writeAccess, writePermissionDenied, writeReadOnly } from './protocols/auth.js';
|
|
35
|
+
export { messageAccess, messageEpoch, messagePermissionDenied, messageReadOnly, writeAccess, writeEpoch, writePermissionDenied, writeReadOnly } from './protocols/auth.js';
|
|
36
36
|
export { commentsSubscribe, commentsSnapshot, commentsChange, writeCommentsSubscribe, writeCommentsSnapshot, writeCommentsChange, readCommentsMessage } from './protocols/comments.js';
|
|
37
37
|
export { applyAwarenessUpdate, encodeAwarenessUpdate, readAwarenessEntries, writeAwarenessEntries } from './protocols/awareness.js';
|
|
38
38
|
// Minimal wire codec for frame bodies (lib0 — the codec the frames are
|
|
@@ -28,6 +28,13 @@ export declare const writeReadOnly: (encoder: encoding.Encoder) => void;
|
|
|
28
28
|
*/
|
|
29
29
|
export declare const messageAccess = 2;
|
|
30
30
|
export declare const writeAccess: (encoder: encoding.Encoder, access: string) => void;
|
|
31
|
+
/**
|
|
32
|
+
* The room's epoch (`room.reseed.protocol`), sent to a socket that dialed an
|
|
33
|
+
* older one, instead of anything else: the room asks it for its old
|
|
34
|
+
* document (`messageRebase`), then closes it `4410`.
|
|
35
|
+
*/
|
|
36
|
+
export declare const messageEpoch = 3;
|
|
37
|
+
export declare const writeEpoch: (encoder: encoding.Encoder, epoch: number) => void;
|
|
31
38
|
export type PermissionDeniedHandler = (ydoc: unknown, reason: string) => void;
|
|
32
39
|
/**
|
|
33
40
|
* Decode one auth payload. Returns the auth message subtype so the caller
|
|
@@ -35,4 +42,4 @@ export type PermissionDeniedHandler = (ydoc: unknown, reason: string) => void;
|
|
|
35
42
|
* do not speak is protocol skew, and this stack's contract is that skew is
|
|
36
43
|
* reported, not silently dropped (same rule as unknown sync subtypes).
|
|
37
44
|
*/
|
|
38
|
-
export declare const readAuthMessage: (decoder: decoding.Decoder, y: unknown, permissionDeniedHandler: PermissionDeniedHandler, readOnlyHandler?: (ydoc: unknown) => void, accessHandler?: (access: string) => void) => number;
|
|
45
|
+
export declare const readAuthMessage: (decoder: decoding.Decoder, y: unknown, permissionDeniedHandler: PermissionDeniedHandler, readOnlyHandler?: (ydoc: unknown) => void, accessHandler?: (access: string) => void, epochHandler?: (epoch: number) => void) => number;
|
|
@@ -36,13 +36,23 @@ export const writeAccess = (encoder, access) => {
|
|
|
36
36
|
encoding.writeVarUint(encoder, messageAccess);
|
|
37
37
|
encoding.writeVarString(encoder, access);
|
|
38
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* The room's epoch (`room.reseed.protocol`), sent to a socket that dialed an
|
|
41
|
+
* older one, instead of anything else: the room asks it for its old
|
|
42
|
+
* document (`messageRebase`), then closes it `4410`.
|
|
43
|
+
*/
|
|
44
|
+
export const messageEpoch = 3;
|
|
45
|
+
export const writeEpoch = (encoder, epoch) => {
|
|
46
|
+
encoding.writeVarUint(encoder, messageEpoch);
|
|
47
|
+
encoding.writeVarUint(encoder, epoch);
|
|
48
|
+
};
|
|
39
49
|
/**
|
|
40
50
|
* Decode one auth payload. Returns the auth message subtype so the caller
|
|
41
51
|
* can surface unknown subtypes — a valid envelope carrying an auth type we
|
|
42
52
|
* do not speak is protocol skew, and this stack's contract is that skew is
|
|
43
53
|
* reported, not silently dropped (same rule as unknown sync subtypes).
|
|
44
54
|
*/
|
|
45
|
-
export const readAuthMessage = (decoder, y, permissionDeniedHandler, readOnlyHandler, accessHandler) => {
|
|
55
|
+
export const readAuthMessage = (decoder, y, permissionDeniedHandler, readOnlyHandler, accessHandler, epochHandler) => {
|
|
46
56
|
const authMessageType = decoding.readVarUint(decoder);
|
|
47
57
|
switch (authMessageType) {
|
|
48
58
|
case messagePermissionDenied:
|
|
@@ -54,6 +64,9 @@ export const readAuthMessage = (decoder, y, permissionDeniedHandler, readOnlyHan
|
|
|
54
64
|
break;
|
|
55
65
|
case messageAccess:
|
|
56
66
|
accessHandler?.(decoding.readVarString(decoder));
|
|
67
|
+
break;
|
|
68
|
+
case messageEpoch:
|
|
69
|
+
epochHandler?.(decoding.readVarUint(decoder));
|
|
57
70
|
}
|
|
58
71
|
return authMessageType;
|
|
59
72
|
};
|
|
@@ -94,41 +94,19 @@ export class Awareness extends IsolatedObservable {
|
|
|
94
94
|
}
|
|
95
95
|
setLocalState(state) {
|
|
96
96
|
const clientID = this.clientID;
|
|
97
|
-
const currLocalMeta = this.meta.get(clientID);
|
|
98
|
-
const clock = currLocalMeta === undefined ? 0 : currLocalMeta.clock + 1;
|
|
99
97
|
const prevState = this.states.get(clientID);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
put(this, clientID, (this.meta.get(clientID)?.clock ?? -1) + 1, state, time.getUnixTime());
|
|
99
|
+
const changes = noChanges();
|
|
100
|
+
if (state === null)
|
|
101
|
+
changes.removed.push(clientID);
|
|
102
|
+
else if (prevState == null)
|
|
103
|
+
changes.added.push(clientID);
|
|
103
104
|
else {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
clock,
|
|
108
|
-
lastUpdated: time.getUnixTime()
|
|
109
|
-
});
|
|
110
|
-
const added = [];
|
|
111
|
-
const updated = [];
|
|
112
|
-
const filteredUpdated = [];
|
|
113
|
-
const removed = [];
|
|
114
|
-
if (state === null) {
|
|
115
|
-
removed.push(clientID);
|
|
105
|
+
changes.updated.push(clientID);
|
|
106
|
+
if (!jsonEquals(prevState, state))
|
|
107
|
+
changes.changed.push(clientID);
|
|
116
108
|
}
|
|
117
|
-
|
|
118
|
-
if (state != null) {
|
|
119
|
-
added.push(clientID);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
updated.push(clientID);
|
|
124
|
-
if (!jsonEquals(prevState, state)) {
|
|
125
|
-
filteredUpdated.push(clientID);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
if (added.length > 0 || filteredUpdated.length > 0 || removed.length > 0) {
|
|
129
|
-
this.emit('change', [{ added, updated: filteredUpdated, removed }, 'local']);
|
|
130
|
-
}
|
|
131
|
-
this.emit('update', [{ added, updated, removed }, 'local']);
|
|
109
|
+
emitChanges(this, changes, 'local', true);
|
|
132
110
|
}
|
|
133
111
|
setLocalStateField(field, value) {
|
|
134
112
|
const state = this.getLocalState();
|
|
@@ -143,30 +121,40 @@ export class Awareness extends IsolatedObservable {
|
|
|
143
121
|
return this.states;
|
|
144
122
|
}
|
|
145
123
|
}
|
|
124
|
+
const noChanges = () => ({ added: [], updated: [], changed: [], removed: [] });
|
|
125
|
+
/** Write client `clientID`'s `state` (`null`: removed) at `clock`, heard `now`. */
|
|
126
|
+
const put = (awareness, clientID, clock, state, now) => {
|
|
127
|
+
if (state === null)
|
|
128
|
+
awareness.states.delete(clientID);
|
|
129
|
+
else
|
|
130
|
+
awareness.states.set(clientID, state);
|
|
131
|
+
awareness.meta.set(clientID, { clock, lastUpdated: now });
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Emit a change: `change` when a client was added, removed or changed its
|
|
135
|
+
* state, `update` when one was touched at all (`always`: even when none was).
|
|
136
|
+
*/
|
|
137
|
+
const emitChanges = (awareness, { added, updated, changed, removed }, origin, always = false) => {
|
|
138
|
+
if (added.length > 0 || changed.length > 0 || removed.length > 0)
|
|
139
|
+
awareness.emit('change', [{ added, updated: changed, removed }, origin]);
|
|
140
|
+
if (always || added.length > 0 || updated.length > 0 || removed.length > 0)
|
|
141
|
+
awareness.emit('update', [{ added, updated, removed }, origin]);
|
|
142
|
+
};
|
|
146
143
|
/**
|
|
147
144
|
* Mark (remote) clients as inactive and remove them from the list of active
|
|
148
145
|
* peers. This change is propagated to remote clients.
|
|
149
146
|
*/
|
|
150
147
|
export const removeAwarenessStates = (awareness, clients, origin) => {
|
|
151
|
-
const
|
|
152
|
-
for (
|
|
153
|
-
const clientID = clients[i];
|
|
148
|
+
const changes = noChanges();
|
|
149
|
+
for (const clientID of clients) {
|
|
154
150
|
if (awareness.states.has(clientID)) {
|
|
155
151
|
awareness.states.delete(clientID);
|
|
156
|
-
if (clientID === awareness.clientID)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
clock: curMeta.clock + 1,
|
|
160
|
-
lastUpdated: time.getUnixTime()
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
removed.push(clientID);
|
|
152
|
+
if (clientID === awareness.clientID)
|
|
153
|
+
put(awareness, clientID, awareness.meta.get(clientID).clock + 1, null, time.getUnixTime());
|
|
154
|
+
changes.removed.push(clientID);
|
|
164
155
|
}
|
|
165
156
|
}
|
|
166
|
-
|
|
167
|
-
awareness.emit('change', [{ added: [], updated: [], removed }, origin]);
|
|
168
|
-
awareness.emit('update', [{ added: [], updated: [], removed }, origin]);
|
|
169
|
-
}
|
|
157
|
+
emitChanges(awareness, changes, origin);
|
|
170
158
|
};
|
|
171
159
|
/** The update carrying `clients`' entries of `awareness` (their states in `states`). */
|
|
172
160
|
export const encodeAwarenessUpdate = (awareness, clients, states = awareness.states) => writeAwarenessEntries(clients.map((clientID) => ({
|
|
@@ -202,36 +190,19 @@ export const writeAwarenessEntries = (entries) => encoding.encode((encoder) => {
|
|
|
202
190
|
*/
|
|
203
191
|
export const applyAwarenessUpdate = (awareness, update, origin) => {
|
|
204
192
|
const timestamp = time.getUnixTime();
|
|
205
|
-
const
|
|
206
|
-
const updated =
|
|
207
|
-
const
|
|
208
|
-
const removed = [];
|
|
209
|
-
for (const entry of readAwarenessEntries(update)) {
|
|
210
|
-
const { clientID, state } = entry;
|
|
211
|
-
let { clock } = entry;
|
|
193
|
+
const changes = noChanges();
|
|
194
|
+
const { added, updated, changed, removed } = changes;
|
|
195
|
+
for (const { clientID, clock, state } of readAwarenessEntries(update)) {
|
|
212
196
|
const clientMeta = awareness.meta.get(clientID);
|
|
213
197
|
const prevState = awareness.states.get(clientID);
|
|
214
198
|
const currClock = clientMeta === undefined ? 0 : clientMeta.clock;
|
|
215
199
|
if (currClock < clock ||
|
|
216
200
|
(currClock === clock && state === null && awareness.states.has(clientID))) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
clock++;
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
225
|
-
awareness.states.delete(clientID);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
awareness.states.set(clientID, state);
|
|
230
|
-
}
|
|
231
|
-
awareness.meta.set(clientID, {
|
|
232
|
-
clock,
|
|
233
|
-
lastUpdated: timestamp
|
|
234
|
-
});
|
|
201
|
+
// Never let a remote client remove this local state: keep it and
|
|
202
|
+
// broadcast that this client still exists, by increasing the clock.
|
|
203
|
+
const local = awareness.getLocalState();
|
|
204
|
+
const keep = state === null && clientID === awareness.clientID && local != null;
|
|
205
|
+
put(awareness, clientID, keep ? clock + 1 : clock, keep ? local : state, timestamp);
|
|
235
206
|
if (clientMeta === undefined && state !== null) {
|
|
236
207
|
added.push(clientID);
|
|
237
208
|
}
|
|
@@ -239,17 +210,11 @@ export const applyAwarenessUpdate = (awareness, update, origin) => {
|
|
|
239
210
|
removed.push(clientID);
|
|
240
211
|
}
|
|
241
212
|
else if (state !== null) {
|
|
242
|
-
if (!jsonEquals(state, prevState))
|
|
243
|
-
|
|
244
|
-
}
|
|
213
|
+
if (!jsonEquals(state, prevState))
|
|
214
|
+
changed.push(clientID);
|
|
245
215
|
updated.push(clientID);
|
|
246
216
|
}
|
|
247
217
|
}
|
|
248
218
|
}
|
|
249
|
-
|
|
250
|
-
awareness.emit('change', [{ added, updated: filteredUpdated, removed }, origin]);
|
|
251
|
-
}
|
|
252
|
-
if (added.length > 0 || updated.length > 0 || removed.length > 0) {
|
|
253
|
-
awareness.emit('update', [{ added, updated, removed }, origin]);
|
|
254
|
-
}
|
|
219
|
+
emitChanges(awareness, changes, origin);
|
|
255
220
|
};
|
|
@@ -147,17 +147,12 @@ export declare const bindProviders: (Y: EngineApi) => {
|
|
|
147
147
|
loadError: unknown;
|
|
148
148
|
_storeTimeout: number;
|
|
149
149
|
_storeTimeoutId: ReturnType<typeof setTimeout> | null;
|
|
150
|
-
|
|
150
|
+
_unlisten: () => void;
|
|
151
151
|
awareness: Awareness;
|
|
152
152
|
bcconnected: boolean;
|
|
153
153
|
disableBc: boolean;
|
|
154
154
|
_ownsAwareness: boolean;
|
|
155
155
|
_bcSubscriber: (data: ArrayBuffer | Uint8Array, origin: unknown) => void;
|
|
156
|
-
_awarenessUpdateHandler: (updates: {
|
|
157
|
-
added: number[];
|
|
158
|
-
updated: number[];
|
|
159
|
-
removed: number[];
|
|
160
|
-
}, origin: unknown) => void;
|
|
161
156
|
get synced(): boolean;
|
|
162
157
|
messageHandlers: Record<number, import("./room.js").RoomMessageHandler</*elided*/ any>>;
|
|
163
158
|
readMessage: (buf: Uint8Array, emitSynced: boolean) => import("lib0-v14/encoding").Encoder;
|
|
@@ -165,7 +160,7 @@ export declare const bindProviders: (Y: EngineApi) => {
|
|
|
165
160
|
connectBc(): void;
|
|
166
161
|
disconnectBc(): void;
|
|
167
162
|
destroy(): Promise<void>;
|
|
168
|
-
emit<N extends "failed" | "
|
|
163
|
+
emit<N extends "failed" | "message-error" | "schema-mismatch" | "protocol-mismatch" | "synced" | "load-error">(name: N, args: Parameters<{
|
|
169
164
|
synced: (provider: /*elided*/ any) => void;
|
|
170
165
|
'protocol-mismatch': (mismatch: import("./room.js").ProtocolMismatch, provider: /*elided*/ any) => void;
|
|
171
166
|
'load-error': (error: unknown, provider: /*elided*/ any) => void;
|
|
@@ -174,7 +169,7 @@ export declare const bindProviders: (Y: EngineApi) => {
|
|
|
174
169
|
failed: (error: unknown, provider: /*elided*/ any) => void;
|
|
175
170
|
}[N]>): void;
|
|
176
171
|
_observers: Map<string, Set<any>>;
|
|
177
|
-
on<NAME extends "failed" | "
|
|
172
|
+
on<NAME extends "failed" | "message-error" | "schema-mismatch" | "protocol-mismatch" | "synced" | "load-error">(name: NAME, f: {
|
|
178
173
|
synced: (provider: /*elided*/ any) => void;
|
|
179
174
|
'protocol-mismatch': (mismatch: import("./room.js").ProtocolMismatch, provider: /*elided*/ any) => void;
|
|
180
175
|
'load-error': (error: unknown, provider: /*elided*/ any) => void;
|
|
@@ -189,7 +184,7 @@ export declare const bindProviders: (Y: EngineApi) => {
|
|
|
189
184
|
'schema-mismatch': (detail: import("./room.js").SchemaMismatchDetail, provider: /*elided*/ any) => void;
|
|
190
185
|
failed: (error: unknown, provider: /*elided*/ any) => void;
|
|
191
186
|
}[NAME];
|
|
192
|
-
once<NAME extends "failed" | "
|
|
187
|
+
once<NAME extends "failed" | "message-error" | "schema-mismatch" | "protocol-mismatch" | "synced" | "load-error">(name: NAME, f: {
|
|
193
188
|
synced: (provider: /*elided*/ any) => void;
|
|
194
189
|
'protocol-mismatch': (mismatch: import("./room.js").ProtocolMismatch, provider: /*elided*/ any) => void;
|
|
195
190
|
'load-error': (error: unknown, provider: /*elided*/ any) => void;
|
|
@@ -197,7 +192,7 @@ export declare const bindProviders: (Y: EngineApi) => {
|
|
|
197
192
|
'schema-mismatch': (detail: import("./room.js").SchemaMismatchDetail, provider: /*elided*/ any) => void;
|
|
198
193
|
failed: (error: unknown, provider: /*elided*/ any) => void;
|
|
199
194
|
}[NAME]): void;
|
|
200
|
-
off<NAME extends "failed" | "
|
|
195
|
+
off<NAME extends "failed" | "message-error" | "schema-mismatch" | "protocol-mismatch" | "synced" | "load-error">(name: NAME, f: {
|
|
201
196
|
synced: (provider: /*elided*/ any) => void;
|
|
202
197
|
'protocol-mismatch': (mismatch: import("./room.js").ProtocolMismatch, provider: /*elided*/ any) => void;
|
|
203
198
|
'load-error': (error: unknown, provider: /*elided*/ any) => void;
|
|
@@ -248,6 +243,7 @@ export declare const bindProviders: (Y: EngineApi) => {
|
|
|
248
243
|
deny(): void;
|
|
249
244
|
allow(): void;
|
|
250
245
|
};
|
|
246
|
+
_rebasing: boolean;
|
|
251
247
|
messageHandlers: Record<number, import("./room.js").RoomMessageHandler</*elided*/ any>>;
|
|
252
248
|
hasSynced: boolean;
|
|
253
249
|
whenSynced: Promise<unknown>;
|
|
@@ -258,14 +254,7 @@ export declare const bindProviders: (Y: EngineApi) => {
|
|
|
258
254
|
_resync: ReturnType<typeof setInterval> | undefined;
|
|
259
255
|
_connectTimer: ReturnType<typeof setTimeout> | undefined;
|
|
260
256
|
_checkInterval: ReturnType<typeof setInterval>;
|
|
261
|
-
|
|
262
|
-
local: boolean;
|
|
263
|
-
}) => void;
|
|
264
|
-
_awarenessUpdateHandler: (updates: {
|
|
265
|
-
added: number[];
|
|
266
|
-
updated: number[];
|
|
267
|
-
removed: number[];
|
|
268
|
-
}, origin: unknown) => void;
|
|
257
|
+
_unlisten: () => void;
|
|
269
258
|
get url(): string;
|
|
270
259
|
get unsaved(): number;
|
|
271
260
|
get saved(): boolean;
|
|
@@ -275,11 +264,11 @@ export declare const bindProviders: (Y: EngineApi) => {
|
|
|
275
264
|
destroy(): void;
|
|
276
265
|
disconnect(): void;
|
|
277
266
|
connect(): void;
|
|
278
|
-
emit<N extends "refused" | "status" | "failed" | "
|
|
267
|
+
emit<N extends "refused" | "status" | "failed" | "message-error" | "schema-mismatch" | "protocol-mismatch" | "synced" | "access" | "connection-close" | "connection-error" | "saved" | "permission-denied" | "expired" | "unreachable">(name: N, args: Parameters<WebsocketProviderEvents[N]>): void;
|
|
279
268
|
_observers: Map<string, Set<any>>;
|
|
280
|
-
on<NAME extends "refused" | "status" | "failed" | "
|
|
281
|
-
once<NAME extends "refused" | "status" | "failed" | "
|
|
282
|
-
off<NAME extends "refused" | "status" | "failed" | "
|
|
269
|
+
on<NAME extends "refused" | "status" | "failed" | "message-error" | "schema-mismatch" | "protocol-mismatch" | "synced" | "access" | "connection-close" | "connection-error" | "saved" | "permission-denied" | "expired" | "unreachable">(name: NAME, f: WebsocketProviderEvents[NAME]): WebsocketProviderEvents[NAME];
|
|
270
|
+
once<NAME extends "refused" | "status" | "failed" | "message-error" | "schema-mismatch" | "protocol-mismatch" | "synced" | "access" | "connection-close" | "connection-error" | "saved" | "permission-denied" | "expired" | "unreachable">(name: NAME, f: WebsocketProviderEvents[NAME]): void;
|
|
271
|
+
off<NAME extends "refused" | "status" | "failed" | "message-error" | "schema-mismatch" | "protocol-mismatch" | "synced" | "access" | "connection-close" | "connection-error" | "saved" | "permission-denied" | "expired" | "unreachable">(name: NAME, f: WebsocketProviderEvents[NAME]): void;
|
|
283
272
|
};
|
|
284
273
|
};
|
|
285
274
|
watchComments: (server: string | null, roomName: string, listener: (message: import("../protocol.js").CommentMessage) => void) => (() => void);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { keepingReplaced } from '../incarnations.js';
|
|
2
2
|
import { bindIndexeddbProvider } from './indexeddb.js';
|
|
3
|
-
import { assertRoomId, SyncRefusedError } from './room.js';
|
|
3
|
+
import { assertRoomId, CLOSE, SyncRefusedError } from './room.js';
|
|
4
4
|
import { bindWebsocketProvider } from './websocket.js';
|
|
5
5
|
export const bindProviders = (Y) => {
|
|
6
6
|
const idb = bindIndexeddbProvider(Y);
|
|
@@ -50,7 +50,18 @@ export const bindProviders = (Y) => {
|
|
|
50
50
|
maxBackoffTime,
|
|
51
51
|
connectTimeout,
|
|
52
52
|
disableBc: disableBc || local !== undefined,
|
|
53
|
-
maxFrameBytes
|
|
53
|
+
maxFrameBytes,
|
|
54
|
+
// With a local copy, the dial waits for it: the epoch it names is the copy's.
|
|
55
|
+
connect: local === undefined
|
|
56
|
+
});
|
|
57
|
+
const dial = () => provider._destroyed || provider.connect();
|
|
58
|
+
// A re-seed (`room.reseed.protocol`, a `4410` refusal): the local copy goes,
|
|
59
|
+
// its deletion waiting for every tab's connection to close.
|
|
60
|
+
provider.on('refused', ({ code }) => {
|
|
61
|
+
if (code !== CLOSE.reseeded || !loaded)
|
|
62
|
+
return;
|
|
63
|
+
void release?.();
|
|
64
|
+
void idb.clearDocument(persistName);
|
|
54
65
|
});
|
|
55
66
|
if (onExpired)
|
|
56
67
|
provider.on('expired', (state) => onExpired(state));
|
|
@@ -94,9 +105,17 @@ export const bindProviders = (Y) => {
|
|
|
94
105
|
});
|
|
95
106
|
}
|
|
96
107
|
let release = undefined;
|
|
108
|
+
// The store's load (or its failure) opens the dial.
|
|
109
|
+
const loaded = local &&
|
|
110
|
+
Object.assign((p) => local({
|
|
111
|
+
...p,
|
|
112
|
+
synced: (x) => (p.synced(x), dial()),
|
|
113
|
+
failed: (error, x) => (p.failed?.(error, x), dial())
|
|
114
|
+
}), local);
|
|
97
115
|
try {
|
|
98
116
|
// Called directly (no `attach`), the store only persists: readiness is the socket's.
|
|
99
|
-
release =
|
|
117
|
+
release =
|
|
118
|
+
loaded && (attach ? attach(loaded) : loaded({ doc, awareness, synced: () => { } }));
|
|
100
119
|
}
|
|
101
120
|
catch (error) {
|
|
102
121
|
provider.destroy();
|
|
@@ -45,17 +45,13 @@ export declare const bindIndexeddbProvider: (Y: EngineApi) => {
|
|
|
45
45
|
loadError: unknown;
|
|
46
46
|
_storeTimeout: number;
|
|
47
47
|
_storeTimeoutId: ReturnType<typeof setTimeout> | null;
|
|
48
|
-
|
|
48
|
+
/** @internal Removes the document and presence listeners (`room.listen`). */
|
|
49
|
+
_unlisten: () => void;
|
|
49
50
|
awareness: Awareness;
|
|
50
51
|
bcconnected: boolean;
|
|
51
52
|
disableBc: boolean;
|
|
52
53
|
_ownsAwareness: boolean;
|
|
53
54
|
_bcSubscriber: (data: ArrayBuffer | Uint8Array, origin: unknown) => void;
|
|
54
|
-
_awarenessUpdateHandler: (updates: {
|
|
55
|
-
added: number[];
|
|
56
|
-
updated: number[];
|
|
57
|
-
removed: number[];
|
|
58
|
-
}, origin: unknown) => void;
|
|
59
55
|
/** The lifetime hydration claim. */
|
|
60
56
|
get synced(): boolean;
|
|
61
57
|
/**
|
|
@@ -78,7 +74,7 @@ export declare const bindIndexeddbProvider: (Y: EngineApi) => {
|
|
|
78
74
|
* close the DB. Does NOT remove stored data — `clearDocument` does.
|
|
79
75
|
*/
|
|
80
76
|
destroy(): Promise<void>;
|
|
81
|
-
emit<N extends "failed" | "
|
|
77
|
+
emit<N extends "failed" | "message-error" | "schema-mismatch" | "protocol-mismatch" | "synced" | "load-error">(name: N, args: Parameters<{
|
|
82
78
|
synced: (provider: /*elided*/ any) => void;
|
|
83
79
|
'protocol-mismatch': (mismatch: ProtocolMismatch, provider: /*elided*/ any) => void;
|
|
84
80
|
/** Fired when loading persisted state failed (e.g. a generation mismatch). `whenSynced` rejects. */
|
|
@@ -101,7 +97,7 @@ export declare const bindIndexeddbProvider: (Y: EngineApi) => {
|
|
|
101
97
|
failed: (error: unknown, provider: /*elided*/ any) => void;
|
|
102
98
|
}[N]>): void;
|
|
103
99
|
_observers: Map<string, Set<any>>;
|
|
104
|
-
on<NAME extends "failed" | "
|
|
100
|
+
on<NAME extends "failed" | "message-error" | "schema-mismatch" | "protocol-mismatch" | "synced" | "load-error">(name: NAME, f: {
|
|
105
101
|
synced: (provider: /*elided*/ any) => void;
|
|
106
102
|
'protocol-mismatch': (mismatch: ProtocolMismatch, provider: /*elided*/ any) => void;
|
|
107
103
|
/** Fired when loading persisted state failed (e.g. a generation mismatch). `whenSynced` rejects. */
|
|
@@ -144,7 +140,7 @@ export declare const bindIndexeddbProvider: (Y: EngineApi) => {
|
|
|
144
140
|
*/
|
|
145
141
|
failed: (error: unknown, provider: /*elided*/ any) => void;
|
|
146
142
|
}[NAME];
|
|
147
|
-
once<NAME extends "failed" | "
|
|
143
|
+
once<NAME extends "failed" | "message-error" | "schema-mismatch" | "protocol-mismatch" | "synced" | "load-error">(name: NAME, f: {
|
|
148
144
|
synced: (provider: /*elided*/ any) => void;
|
|
149
145
|
'protocol-mismatch': (mismatch: ProtocolMismatch, provider: /*elided*/ any) => void;
|
|
150
146
|
/** Fired when loading persisted state failed (e.g. a generation mismatch). `whenSynced` rejects. */
|
|
@@ -166,7 +162,7 @@ export declare const bindIndexeddbProvider: (Y: EngineApi) => {
|
|
|
166
162
|
*/
|
|
167
163
|
failed: (error: unknown, provider: /*elided*/ any) => void;
|
|
168
164
|
}[NAME]): void;
|
|
169
|
-
off<NAME extends "failed" | "
|
|
165
|
+
off<NAME extends "failed" | "message-error" | "schema-mismatch" | "protocol-mismatch" | "synced" | "load-error">(name: NAME, f: {
|
|
170
166
|
synced: (provider: /*elided*/ any) => void;
|
|
171
167
|
'protocol-mismatch': (mismatch: ProtocolMismatch, provider: /*elided*/ any) => void;
|
|
172
168
|
/** Fired when loading persisted state failed (e.g. a generation mismatch). `whenSynced` rejects. */
|
|
@@ -41,7 +41,7 @@ import { IsolatedObservable } from '../protocols/observable.js';
|
|
|
41
41
|
import { bindSync } from '../protocols/sync.js';
|
|
42
42
|
import { generationDbName } from '../protocols/envelope.js';
|
|
43
43
|
import { CUSTOM as customStoreName, encodeRow, lastKey, openContainer, readRow, rtop, snapshotRow, storesOf, UPDATES as updatesStoreName, verifyOrStamp } from './container.js';
|
|
44
|
-
import { beginDestroy, bindRoomProtocol, tabs, emitFailed, initLifecycle, markSynced, quarantined } from './room.js';
|
|
44
|
+
import { beginDestroy, bindRoomProtocol, tabs, emitFailed, fault, initLifecycle, markSynced, quarantined } from './room.js';
|
|
45
45
|
export const PREFERRED_TRIM_SIZE = 500;
|
|
46
46
|
/**
|
|
47
47
|
* Bind the IndexedDB persistence provider to the vendored v14 engine module.
|
|
@@ -175,13 +175,13 @@ export const bindIndexeddbProvider = (Y) => {
|
|
|
175
175
|
loadError = null;
|
|
176
176
|
_storeTimeout;
|
|
177
177
|
_storeTimeoutId;
|
|
178
|
-
|
|
178
|
+
/** @internal Removes the document and presence listeners (`room.listen`). */
|
|
179
|
+
_unlisten;
|
|
179
180
|
awareness;
|
|
180
181
|
bcconnected = false;
|
|
181
182
|
disableBc;
|
|
182
183
|
_ownsAwareness;
|
|
183
184
|
_bcSubscriber;
|
|
184
|
-
_awarenessUpdateHandler;
|
|
185
185
|
constructor(name, doc, options = {}) {
|
|
186
186
|
super();
|
|
187
187
|
this.doc = doc;
|
|
@@ -196,8 +196,6 @@ export const bindIndexeddbProvider = (Y) => {
|
|
|
196
196
|
this._db = openContainer(this.dbName);
|
|
197
197
|
this.destroy = this.destroy.bind(this);
|
|
198
198
|
initLifecycle(this, this.destroy, () => room.depart(this));
|
|
199
|
-
this._bcSubscriber = room.bcSubscriber(this);
|
|
200
|
-
this._awarenessUpdateHandler = room.awarenessUpdateHandler(this);
|
|
201
199
|
// Fail closed: no sync, no BC room join, whenSynced rejects, and
|
|
202
200
|
// the terminal 'failed' fires — the provider can never reach
|
|
203
201
|
// synced once loading its persisted state has failed.
|
|
@@ -216,7 +214,7 @@ export const bindIndexeddbProvider = (Y) => {
|
|
|
216
214
|
// A read-only doc's pre-hydration state is never persisted.
|
|
217
215
|
const beforeApplyUpdatesCallback = (updatesStore) => {
|
|
218
216
|
if (!quarantined(doc)) {
|
|
219
|
-
rtop(updatesStore.add(encodeRow(Y.encodeStateAsUpdate(doc)))).catch((error) => this
|
|
217
|
+
rtop(updatesStore.add(encodeRow(Y.encodeStateAsUpdate(doc)))).catch((error) => fault(this, error));
|
|
220
218
|
}
|
|
221
219
|
};
|
|
222
220
|
// Hydrated: join the room and claim `synced` (lifetime).
|
|
@@ -243,7 +241,7 @@ export const bindIndexeddbProvider = (Y) => {
|
|
|
243
241
|
.catch(onLoadError);
|
|
244
242
|
this._storeTimeout = 1000;
|
|
245
243
|
this._storeTimeoutId = null;
|
|
246
|
-
|
|
244
|
+
const storeUpdate = (update, origin) => {
|
|
247
245
|
// Outbound quarantine: a read-only doc is never persisted
|
|
248
246
|
// (`broadcastUpdate` applies the same rule to the room).
|
|
249
247
|
if (origin === this || quarantined(doc))
|
|
@@ -253,9 +251,7 @@ export const bindIndexeddbProvider = (Y) => {
|
|
|
253
251
|
const [updatesStore] = storesOf(this.db, [updatesStoreName]);
|
|
254
252
|
// Storage failures must surface — never an unobserved
|
|
255
253
|
// rejection (the error channel observes every failure mode).
|
|
256
|
-
rtop(updatesStore.add(encodeRow(update))).catch((error) =>
|
|
257
|
-
this.emit('message-error', [error, this]);
|
|
258
|
-
});
|
|
254
|
+
rtop(updatesStore.add(encodeRow(update))).catch((error) => fault(this, error));
|
|
259
255
|
if (++this._dbsize >= PREFERRED_TRIM_SIZE) {
|
|
260
256
|
if (this._storeTimeoutId !== null) {
|
|
261
257
|
clearTimeout(this._storeTimeoutId);
|
|
@@ -264,7 +260,7 @@ export const bindIndexeddbProvider = (Y) => {
|
|
|
264
260
|
this._storeTimeoutId = null;
|
|
265
261
|
// The timed caller has no promise consumer — surface
|
|
266
262
|
// compaction/storage failures on the error channel.
|
|
267
|
-
storeState(this, false).catch((error) => this
|
|
263
|
+
storeState(this, false).catch((error) => fault(this, error));
|
|
268
264
|
}, this._storeTimeout);
|
|
269
265
|
}
|
|
270
266
|
}
|
|
@@ -272,14 +268,13 @@ export const bindIndexeddbProvider = (Y) => {
|
|
|
272
268
|
// A synchronous transact failure (e.g. a handle closed
|
|
273
269
|
// mid-session) still lands on the error channel rather
|
|
274
270
|
// than propagating into the doc's update dispatch.
|
|
275
|
-
this
|
|
271
|
+
fault(this, error);
|
|
276
272
|
}
|
|
277
273
|
}
|
|
278
274
|
// Broadcast the update to other tabs
|
|
279
275
|
room.broadcastUpdate(this, update);
|
|
280
276
|
};
|
|
281
|
-
|
|
282
|
-
this.awareness.on('update', this._awarenessUpdateHandler);
|
|
277
|
+
this._unlisten = room.listen(this, storeUpdate);
|
|
283
278
|
const onDocDestroy = () => void this.destroy();
|
|
284
279
|
destroyWithDoc.set(this, onDocDestroy);
|
|
285
280
|
doc.on('destroy', onDocDestroy);
|
|
@@ -324,11 +319,10 @@ export const bindIndexeddbProvider = (Y) => {
|
|
|
324
319
|
if (this._storeTimeoutId) {
|
|
325
320
|
clearTimeout(this._storeTimeoutId);
|
|
326
321
|
}
|
|
327
|
-
this.
|
|
322
|
+
this._unlisten();
|
|
328
323
|
const onDocDestroy = destroyWithDoc.get(this);
|
|
329
324
|
if (onDocDestroy)
|
|
330
325
|
this.doc.off('destroy', onDocDestroy);
|
|
331
|
-
this.awareness.off('update', this._awarenessUpdateHandler);
|
|
332
326
|
this.disconnectBc();
|
|
333
327
|
if (this._ownsAwareness) {
|
|
334
328
|
this.awareness.destroy();
|
|
@@ -61,6 +61,12 @@ export declare const messageChunk = 5;
|
|
|
61
61
|
* room sends it only to a socket that subscribed.
|
|
62
62
|
*/
|
|
63
63
|
export declare const messageComments = 6;
|
|
64
|
+
/**
|
|
65
|
+
* Client → server, after a re-seed (`room.reseed.protocol`): the client's
|
|
66
|
+
* whole old document, its unsaved edits in it, for the room to rebase onto
|
|
67
|
+
* the current epoch. Sent only when the room asks (its epoch notice).
|
|
68
|
+
*/
|
|
69
|
+
export declare const messageRebase = 7;
|
|
64
70
|
/** A WebSocket message limit on Cloudflare (32 MiB): a larger frame is sent as chunks. */
|
|
65
71
|
export declare const MAX_FRAME_BYTES: number;
|
|
66
72
|
/**
|
|
@@ -164,6 +170,14 @@ export declare const onPageLeave: (fn: () => void, phase: PageLeavePhase) => (()
|
|
|
164
170
|
export declare const initLifecycle: (host: LifecycleHost, destroy: () => unknown, depart?: () => void) => void;
|
|
165
171
|
/** The first sync — lifetime. Returns `true` only the first time. */
|
|
166
172
|
export declare const markSynced: (host: LifecycleHost) => boolean;
|
|
173
|
+
/** Report `error` on `provider`'s error channel (`'message-error'`): a frame, a payload or a storage failure. */
|
|
174
|
+
export declare const fault: (provider: {
|
|
175
|
+
emit?(event: "message-error", args: [unknown, unknown]): void;
|
|
176
|
+
}, error: unknown) => void;
|
|
177
|
+
/** A message type no handler claims inside a valid envelope: protocol skew, reported, never dropped silently. */
|
|
178
|
+
export declare const unknownType: (provider: {
|
|
179
|
+
emit?(event: "message-error", args: [unknown, unknown]): void;
|
|
180
|
+
}, what: string, type: number) => void;
|
|
167
181
|
/**
|
|
168
182
|
* Terminal `'failed'` emission (the sync-failure contract): fires at
|
|
169
183
|
* most once per provider, only while it has never synced — destroy before
|
|
@@ -195,6 +209,15 @@ export declare const CLOSE: {
|
|
|
195
209
|
readonly denied: 4403;
|
|
196
210
|
/** The dialed replica is bound to another user. */
|
|
197
211
|
readonly replicaTaken: 4409;
|
|
212
|
+
/**
|
|
213
|
+
* The room re-seeded the document (`room.reseed.protocol`; the reason is
|
|
214
|
+
* the room's epoch): a refusal of this document, once a client with
|
|
215
|
+
* unsaved edits redialed and handed them over. The new epoch is a new
|
|
216
|
+
* document's. Also the answer to a copy the room cannot rebase (an
|
|
217
|
+
* epoch past the cuts it keeps, or a later one) and to an older epoch's
|
|
218
|
+
* content on a socket of the current one.
|
|
219
|
+
*/
|
|
220
|
+
readonly reseeded: 4410;
|
|
198
221
|
/**
|
|
199
222
|
* A room quota refused the socket's write (`quota: document`,
|
|
200
223
|
* `quota: rate`, `quota: frame`): the frame was not applied, and a
|
|
@@ -298,5 +321,8 @@ export declare const bindRoomProtocol: <P extends RoomProvider<P>>(syncProtocol:
|
|
|
298
321
|
depart: (provider: P) => void;
|
|
299
322
|
connectBc: (provider: P & BcMember) => void;
|
|
300
323
|
disconnectBc: (provider: P & BcMember) => void;
|
|
324
|
+
listen: (provider: P & BcMember, onUpdate: (update: Uint8Array, origin: unknown, doc?: unknown, transaction?: {
|
|
325
|
+
local: boolean;
|
|
326
|
+
}) => void) => (() => void);
|
|
301
327
|
};
|
|
302
328
|
export {};
|