y-partyserver 2.1.4 → 2.2.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/dist/{chunk-C0xms8kb.cjs → chunk-CKQMccvm.cjs} +12 -18
- package/dist/provider/index.cjs +27 -34
- package/dist/provider/index.cjs.map +1 -1
- package/dist/provider/index.js +17 -24
- package/dist/provider/index.js.map +1 -1
- package/dist/provider/react.cjs +2 -3
- package/dist/provider/react.cjs.map +1 -1
- package/dist/provider/react.js +1 -2
- package/dist/provider/react.js.map +1 -1
- package/dist/server/index.cjs +7 -8
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +1 -2
- package/dist/server/index.js.map +1 -1
- package/package.json +8 -7
|
@@ -6,16 +6,12 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
8
|
var __copyProps = (to, from, except, desc) => {
|
|
9
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
}
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
19
15
|
}
|
|
20
16
|
return to;
|
|
21
17
|
};
|
|
@@ -23,12 +19,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
19
|
value: mod,
|
|
24
20
|
enumerable: true
|
|
25
21
|
}) : target, mod));
|
|
26
|
-
|
|
27
22
|
//#endregion
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
});
|
|
23
|
+
Object.defineProperty(exports, "__toESM", {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function() {
|
|
26
|
+
return __toESM;
|
|
27
|
+
}
|
|
28
|
+
});
|
package/dist/provider/index.cjs
CHANGED
|
@@ -2,29 +2,28 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_chunk = require("../chunk-
|
|
5
|
+
const require_chunk = require("../chunk-CKQMccvm.cjs");
|
|
6
6
|
let lib0_decoding = require("lib0/decoding");
|
|
7
|
-
lib0_decoding = require_chunk.__toESM(lib0_decoding);
|
|
7
|
+
lib0_decoding = require_chunk.__toESM(lib0_decoding, 1);
|
|
8
8
|
let lib0_encoding = require("lib0/encoding");
|
|
9
|
-
lib0_encoding = require_chunk.__toESM(lib0_encoding);
|
|
9
|
+
lib0_encoding = require_chunk.__toESM(lib0_encoding, 1);
|
|
10
10
|
let y_protocols_awareness = require("y-protocols/awareness");
|
|
11
|
-
y_protocols_awareness = require_chunk.__toESM(y_protocols_awareness);
|
|
11
|
+
y_protocols_awareness = require_chunk.__toESM(y_protocols_awareness, 1);
|
|
12
12
|
let y_protocols_sync = require("y-protocols/sync");
|
|
13
|
-
y_protocols_sync = require_chunk.__toESM(y_protocols_sync);
|
|
13
|
+
y_protocols_sync = require_chunk.__toESM(y_protocols_sync, 1);
|
|
14
14
|
let yjs = require("yjs");
|
|
15
15
|
let lib0_broadcastchannel = require("lib0/broadcastchannel");
|
|
16
|
-
lib0_broadcastchannel = require_chunk.__toESM(lib0_broadcastchannel);
|
|
16
|
+
lib0_broadcastchannel = require_chunk.__toESM(lib0_broadcastchannel, 1);
|
|
17
17
|
let lib0_math = require("lib0/math");
|
|
18
|
-
lib0_math = require_chunk.__toESM(lib0_math);
|
|
18
|
+
lib0_math = require_chunk.__toESM(lib0_math, 1);
|
|
19
19
|
let lib0_observable = require("lib0/observable");
|
|
20
20
|
let lib0_time = require("lib0/time");
|
|
21
|
-
lib0_time = require_chunk.__toESM(lib0_time);
|
|
21
|
+
lib0_time = require_chunk.__toESM(lib0_time, 1);
|
|
22
22
|
let lib0_url = require("lib0/url");
|
|
23
|
-
lib0_url = require_chunk.__toESM(lib0_url);
|
|
23
|
+
lib0_url = require_chunk.__toESM(lib0_url, 1);
|
|
24
24
|
let nanoid = require("nanoid");
|
|
25
25
|
let y_protocols_auth = require("y-protocols/auth");
|
|
26
|
-
y_protocols_auth = require_chunk.__toESM(y_protocols_auth);
|
|
27
|
-
|
|
26
|
+
y_protocols_auth = require_chunk.__toESM(y_protocols_auth, 1);
|
|
28
27
|
//#region src/provider/index.ts
|
|
29
28
|
const messageSync = 0;
|
|
30
29
|
const messageQueryAwareness = 3;
|
|
@@ -32,14 +31,8 @@ const messageAwareness = 1;
|
|
|
32
31
|
const messageAuth = 2;
|
|
33
32
|
const DEFAULT_DISABLE_BC = typeof window === "undefined";
|
|
34
33
|
const messageHandlers = [];
|
|
35
|
-
messageHandlers[
|
|
36
|
-
encoder,
|
|
37
|
-
decoder,
|
|
38
|
-
provider,
|
|
39
|
-
emitSynced,
|
|
40
|
-
_messageType
|
|
41
|
-
) => {
|
|
42
|
-
lib0_encoding.writeVarUint(encoder, messageSync);
|
|
34
|
+
messageHandlers[0] = (encoder, decoder, provider, emitSynced, _messageType) => {
|
|
35
|
+
lib0_encoding.writeVarUint(encoder, 0);
|
|
43
36
|
const syncMessageType = y_protocols_sync.readSyncMessage(
|
|
44
37
|
decoder,
|
|
45
38
|
encoder,
|
|
@@ -53,14 +46,14 @@ messageHandlers[messageSync] = (
|
|
|
53
46
|
)
|
|
54
47
|
provider.synced = true;
|
|
55
48
|
};
|
|
56
|
-
messageHandlers[
|
|
49
|
+
messageHandlers[3] = (
|
|
57
50
|
encoder,
|
|
58
51
|
_decoder,
|
|
59
52
|
provider,
|
|
60
53
|
_emitSynced,
|
|
61
54
|
_messageType
|
|
62
55
|
) => {
|
|
63
|
-
lib0_encoding.writeVarUint(encoder,
|
|
56
|
+
lib0_encoding.writeVarUint(encoder, 1);
|
|
64
57
|
lib0_encoding.writeVarUint8Array(
|
|
65
58
|
encoder,
|
|
66
59
|
y_protocols_awareness.encodeAwarenessUpdate(
|
|
@@ -69,7 +62,7 @@ messageHandlers[messageQueryAwareness] = (
|
|
|
69
62
|
)
|
|
70
63
|
);
|
|
71
64
|
};
|
|
72
|
-
messageHandlers[
|
|
65
|
+
messageHandlers[1] = (
|
|
73
66
|
_encoder,
|
|
74
67
|
decoder,
|
|
75
68
|
provider,
|
|
@@ -82,7 +75,7 @@ messageHandlers[messageAwareness] = (
|
|
|
82
75
|
provider
|
|
83
76
|
);
|
|
84
77
|
};
|
|
85
|
-
messageHandlers[
|
|
78
|
+
messageHandlers[2] = (
|
|
86
79
|
_encoder,
|
|
87
80
|
decoder,
|
|
88
81
|
provider,
|
|
@@ -173,13 +166,13 @@ function setupWS(provider) {
|
|
|
173
166
|
provider.wsUnsuccessfulReconnects = 0;
|
|
174
167
|
provider.emit("status", [{ status: "connected" }]);
|
|
175
168
|
const encoder = lib0_encoding.createEncoder();
|
|
176
|
-
lib0_encoding.writeVarUint(encoder,
|
|
169
|
+
lib0_encoding.writeVarUint(encoder, 0);
|
|
177
170
|
y_protocols_sync.writeSyncStep1(encoder, provider.doc);
|
|
178
171
|
websocket.send(lib0_encoding.toUint8Array(encoder));
|
|
179
172
|
if (provider.awareness.getLocalState() !== null) {
|
|
180
173
|
provider.awareness.setLocalState(provider.awareness.getLocalState());
|
|
181
174
|
const encoderAwarenessState = lib0_encoding.createEncoder();
|
|
182
|
-
lib0_encoding.writeVarUint(encoderAwarenessState,
|
|
175
|
+
lib0_encoding.writeVarUint(encoderAwarenessState, 1);
|
|
183
176
|
lib0_encoding.writeVarUint8Array(
|
|
184
177
|
encoderAwarenessState,
|
|
185
178
|
y_protocols_awareness.encodeAwarenessUpdate(provider.awareness, [
|
|
@@ -278,7 +271,7 @@ var WebsocketProvider = class extends lib0_observable.Observable {
|
|
|
278
271
|
this._resyncInterval = setInterval(() => {
|
|
279
272
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
280
273
|
const encoder = lib0_encoding.createEncoder();
|
|
281
|
-
lib0_encoding.writeVarUint(encoder,
|
|
274
|
+
lib0_encoding.writeVarUint(encoder, 0);
|
|
282
275
|
y_protocols_sync.writeSyncStep1(encoder, doc);
|
|
283
276
|
this.ws.send(lib0_encoding.toUint8Array(encoder));
|
|
284
277
|
}
|
|
@@ -300,7 +293,7 @@ var WebsocketProvider = class extends lib0_observable.Observable {
|
|
|
300
293
|
this._updateHandler = (update, origin) => {
|
|
301
294
|
if (origin !== this) {
|
|
302
295
|
const encoder = lib0_encoding.createEncoder();
|
|
303
|
-
lib0_encoding.writeVarUint(encoder,
|
|
296
|
+
lib0_encoding.writeVarUint(encoder, 0);
|
|
304
297
|
y_protocols_sync.writeUpdate(encoder, update);
|
|
305
298
|
broadcastMessage(this, lib0_encoding.toUint8Array(encoder));
|
|
306
299
|
}
|
|
@@ -309,7 +302,7 @@ var WebsocketProvider = class extends lib0_observable.Observable {
|
|
|
309
302
|
this._awarenessUpdateHandler = ({ added, updated, removed }, _origin) => {
|
|
310
303
|
const changedClients = added.concat(updated).concat(removed);
|
|
311
304
|
const encoder = lib0_encoding.createEncoder();
|
|
312
|
-
lib0_encoding.writeVarUint(encoder,
|
|
305
|
+
lib0_encoding.writeVarUint(encoder, 1);
|
|
313
306
|
lib0_encoding.writeVarUint8Array(
|
|
314
307
|
encoder,
|
|
315
308
|
y_protocols_awareness.encodeAwarenessUpdate(awareness, changedClients)
|
|
@@ -365,7 +358,7 @@ var WebsocketProvider = class extends lib0_observable.Observable {
|
|
|
365
358
|
this.bcconnected = true;
|
|
366
359
|
}
|
|
367
360
|
const encoderSync = lib0_encoding.createEncoder();
|
|
368
|
-
lib0_encoding.writeVarUint(encoderSync,
|
|
361
|
+
lib0_encoding.writeVarUint(encoderSync, 0);
|
|
369
362
|
y_protocols_sync.writeSyncStep1(encoderSync, this.doc);
|
|
370
363
|
lib0_broadcastchannel.publish(
|
|
371
364
|
this.bcChannel,
|
|
@@ -373,7 +366,7 @@ var WebsocketProvider = class extends lib0_observable.Observable {
|
|
|
373
366
|
this
|
|
374
367
|
);
|
|
375
368
|
const encoderState = lib0_encoding.createEncoder();
|
|
376
|
-
lib0_encoding.writeVarUint(encoderState,
|
|
369
|
+
lib0_encoding.writeVarUint(encoderState, 0);
|
|
377
370
|
y_protocols_sync.writeSyncStep2(encoderState, this.doc);
|
|
378
371
|
lib0_broadcastchannel.publish(
|
|
379
372
|
this.bcChannel,
|
|
@@ -381,14 +374,14 @@ var WebsocketProvider = class extends lib0_observable.Observable {
|
|
|
381
374
|
this
|
|
382
375
|
);
|
|
383
376
|
const encoderAwarenessQuery = lib0_encoding.createEncoder();
|
|
384
|
-
lib0_encoding.writeVarUint(encoderAwarenessQuery,
|
|
377
|
+
lib0_encoding.writeVarUint(encoderAwarenessQuery, 3);
|
|
385
378
|
lib0_broadcastchannel.publish(
|
|
386
379
|
this.bcChannel,
|
|
387
380
|
lib0_encoding.toUint8Array(encoderAwarenessQuery),
|
|
388
381
|
this
|
|
389
382
|
);
|
|
390
383
|
const encoderAwarenessState = lib0_encoding.createEncoder();
|
|
391
|
-
lib0_encoding.writeVarUint(encoderAwarenessState,
|
|
384
|
+
lib0_encoding.writeVarUint(encoderAwarenessState, 1);
|
|
392
385
|
lib0_encoding.writeVarUint8Array(
|
|
393
386
|
encoderAwarenessState,
|
|
394
387
|
y_protocols_awareness.encodeAwarenessUpdate(this.awareness, [
|
|
@@ -403,7 +396,7 @@ var WebsocketProvider = class extends lib0_observable.Observable {
|
|
|
403
396
|
}
|
|
404
397
|
disconnectBc() {
|
|
405
398
|
const encoder = lib0_encoding.createEncoder();
|
|
406
|
-
lib0_encoding.writeVarUint(encoder,
|
|
399
|
+
lib0_encoding.writeVarUint(encoder, 1);
|
|
407
400
|
lib0_encoding.writeVarUint8Array(
|
|
408
401
|
encoder,
|
|
409
402
|
y_protocols_awareness.encodeAwarenessUpdate(
|
|
@@ -502,7 +495,6 @@ var YProvider = class extends WebsocketProvider {
|
|
|
502
495
|
this.ws?.send(`__YPS:${message}`);
|
|
503
496
|
}
|
|
504
497
|
};
|
|
505
|
-
|
|
506
498
|
//#endregion
|
|
507
499
|
exports.WebsocketProvider = WebsocketProvider;
|
|
508
500
|
exports.default = YProvider;
|
|
@@ -510,4 +502,5 @@ exports.messageAuth = messageAuth;
|
|
|
510
502
|
exports.messageAwareness = messageAwareness;
|
|
511
503
|
exports.messageQueryAwareness = messageQueryAwareness;
|
|
512
504
|
exports.messageSync = messageSync;
|
|
505
|
+
|
|
513
506
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["syncProtocol","awarenessProtocol","decoding","encoding","time","math","Observable","url","YDoc","#params","#resolveParams"],"sources":["../../src/provider/index.ts"],"sourcesContent":["import * as bc from \"lib0/broadcastchannel\";\nimport * as decoding from \"lib0/decoding\";\nimport * as encoding from \"lib0/encoding\";\nimport * as math from \"lib0/math\";\nimport { Observable } from \"lib0/observable\";\nimport * as time from \"lib0/time\";\nimport * as url from \"lib0/url\";\nimport { nanoid } from \"nanoid\";\nimport * as authProtocol from \"y-protocols/auth\";\nimport * as awarenessProtocol from \"y-protocols/awareness\";\nimport * as syncProtocol from \"y-protocols/sync\";\nimport { Doc as YDoc } from \"yjs\";\n\nexport const messageSync = 0;\nexport const messageQueryAwareness = 3;\nexport const messageAwareness = 1;\nexport const messageAuth = 2;\n\n// Disable BroadcastChannel by default in Cloudflare Workers / Node\nconst DEFAULT_DISABLE_BC = typeof window === \"undefined\";\n\nconst messageHandlers: Array<\n (\n encoder: encoding.Encoder,\n decoder: decoding.Decoder,\n provider: WebsocketProvider,\n emitSynced: boolean,\n messageType: number\n ) => void\n> = [];\n\nmessageHandlers[messageSync] = (\n encoder,\n decoder,\n provider,\n emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageSync);\n const syncMessageType = syncProtocol.readSyncMessage(\n decoder,\n encoder,\n provider.doc,\n provider\n );\n if (\n emitSynced &&\n syncMessageType === syncProtocol.messageYjsSyncStep2 &&\n !provider.synced\n ) {\n provider.synced = true;\n }\n};\n\nmessageHandlers[messageQueryAwareness] = (\n encoder,\n _decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n provider.awareness,\n Array.from(provider.awareness.getStates().keys())\n )\n );\n};\n\nmessageHandlers[messageAwareness] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n awarenessProtocol.applyAwarenessUpdate(\n provider.awareness,\n decoding.readVarUint8Array(decoder),\n provider\n );\n};\n\nmessageHandlers[messageAuth] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n authProtocol.readAuthMessage(decoder, provider.doc, (_ydoc, reason) =>\n permissionDeniedHandler(provider, reason)\n );\n};\n\nfunction permissionDeniedHandler(provider: WebsocketProvider, reason: string) {\n console.warn(`Permission denied to access ${provider.url}.\\n${reason}`);\n}\n\nfunction readMessage(\n provider: WebsocketProvider,\n buf: Uint8Array,\n emitSynced: boolean\n): encoding.Encoder {\n const decoder = decoding.createDecoder(buf);\n const encoder = encoding.createEncoder();\n const messageType = decoding.readVarUint(decoder);\n const messageHandler = provider.messageHandlers[messageType];\n if (/** @type {any} */ messageHandler) {\n messageHandler(encoder, decoder, provider, emitSynced, messageType);\n } else {\n console.error(\"Unable to compute message\");\n }\n return encoder;\n}\n\nfunction setupWS(provider: WebsocketProvider) {\n if (provider.shouldConnect && provider.ws === null) {\n if (!provider._WS) {\n throw new Error(\n \"No WebSocket implementation available, did you forget to pass options.WebSocketPolyfill?\"\n );\n }\n const websocket = new provider._WS(provider.url);\n websocket.binaryType = \"arraybuffer\";\n provider.ws = websocket;\n provider.wsconnecting = true;\n provider.wsconnected = false;\n provider.synced = false;\n\n websocket.addEventListener(\"message\", (event) => {\n if (typeof event.data === \"string\") {\n // Handle custom messages with __YPS: prefix\n if (event.data.startsWith(\"__YPS:\")) {\n const customMessage = event.data.slice(6); // Remove __YPS: prefix\n provider.emit(\"custom-message\", [customMessage]);\n }\n return;\n }\n provider.wsLastMessageReceived = time.getUnixTime();\n const encoder = readMessage(provider, new Uint8Array(event.data), true);\n if (encoding.length(encoder) > 1) {\n websocket.send(encoding.toUint8Array(encoder));\n }\n });\n websocket.addEventListener(\"error\", (event) => {\n provider.emit(\"connection-error\", [event, provider]);\n });\n websocket.addEventListener(\"close\", (event) => {\n provider.emit(\"connection-close\", [event, provider]);\n provider.ws = null;\n provider.wsconnecting = false;\n if (provider.wsconnected) {\n provider.wsconnected = false;\n provider.synced = false;\n // update awareness (all users except local left)\n const removedClients = Array.from(\n provider.awareness.getStates().keys()\n ).filter((client) => client !== provider.doc.clientID);\n awarenessProtocol.removeAwarenessStates(\n provider.awareness,\n removedClients,\n provider\n );\n // Clear stale meta for remote clients so their awareness\n // updates are accepted on reconnect (clock check starts fresh)\n for (const clientID of removedClients) {\n provider.awareness.meta.delete(clientID);\n }\n provider.emit(\"status\", [\n {\n status: \"disconnected\"\n }\n ]);\n } else {\n provider.wsUnsuccessfulReconnects++;\n }\n // Start with no reconnect timeout and increase timeout by\n // using exponential backoff starting with 100ms\n setTimeout(\n () => {\n if (provider.shouldConnect) {\n Promise.resolve(provider._reconnectWS()).catch((err) => {\n console.error(\"Reconnection failed\", err);\n });\n }\n },\n math.min(\n math.pow(2, provider.wsUnsuccessfulReconnects) * 100,\n provider.maxBackoffTime\n )\n );\n });\n websocket.addEventListener(\"open\", () => {\n provider.wsLastMessageReceived = time.getUnixTime();\n provider.wsconnecting = false;\n provider.wsconnected = true;\n provider.wsUnsuccessfulReconnects = 0;\n provider.emit(\"status\", [\n {\n status: \"connected\"\n }\n ]);\n // always send sync step 1 when connected\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, provider.doc);\n websocket.send(encoding.toUint8Array(encoder));\n // broadcast local awareness state\n if (provider.awareness.getLocalState() !== null) {\n // Re-set local state to bump the awareness clock, ensuring\n // remote clients accept the update even if they have stale meta\n provider.awareness.setLocalState(provider.awareness.getLocalState());\n const encoderAwarenessState = encoding.createEncoder();\n encoding.writeVarUint(encoderAwarenessState, messageAwareness);\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(provider.awareness, [\n provider.doc.clientID\n ])\n );\n websocket.send(encoding.toUint8Array(encoderAwarenessState));\n }\n });\n provider.emit(\"status\", [\n {\n status: \"connecting\"\n }\n ]);\n }\n}\n\nfunction broadcastMessage(provider: WebsocketProvider, buf: Uint8Array) {\n const ws = provider.ws;\n if (provider.wsconnected && ws && ws.readyState === ws.OPEN) {\n ws.send(buf);\n }\n if (provider.bcconnected) {\n bc.publish(provider.bcChannel, buf, provider);\n }\n}\n\ntype AwarenessUpdate = {\n added: number[];\n updated: number[];\n removed: number[];\n};\n\nconst DefaultWebSocket = typeof WebSocket === \"undefined\" ? null : WebSocket;\n\n/**\n * Websocket Provider for Yjs. Creates a websocket connection to sync the shared document.\n * The document name is attached to the provided url. I.e. the following example\n * creates a websocket connection to http://localhost:1234/my-document-name\n *\n * @example\n * import * as Y from 'yjs'\n * import { WebsocketProvider } from 'y-websocket'\n * const doc = new Y.Doc()\n * const provider = new WebsocketProvider('http://localhost:1234', 'my-document-name', doc)\n *\n * @extends {Observable<string>}\n */\nexport class WebsocketProvider extends Observable<string> {\n maxBackoffTime: number;\n bcChannel: string;\n url: string;\n roomname: string;\n doc: YDoc;\n _WS: typeof WebSocket;\n awareness: awarenessProtocol.Awareness;\n wsconnected: boolean;\n wsconnecting: boolean;\n bcconnected: boolean;\n disableBc: boolean;\n wsUnsuccessfulReconnects: number;\n messageHandlers: typeof messageHandlers;\n _synced: boolean;\n ws: WebSocket | null;\n wsLastMessageReceived: number;\n shouldConnect: boolean; // Whether to connect to other peers or not\n _resyncInterval: ReturnType<typeof setInterval> | number;\n _bcSubscriber: (message: Uint8Array, origin: unknown) => void;\n _updateHandler: (update: Uint8Array, origin: unknown) => void;\n _awarenessUpdateHandler: (update: AwarenessUpdate, origin: unknown) => void;\n _unloadHandler: () => void;\n\n constructor(\n serverUrl: string,\n roomname: string,\n doc: YDoc,\n {\n connect = true,\n awareness = new awarenessProtocol.Awareness(doc),\n params = {},\n isPrefixedUrl = false,\n WebSocketPolyfill = DefaultWebSocket, // Optionally provide a WebSocket polyfill\n resyncInterval = -1, // Request server state every `resyncInterval` milliseconds\n maxBackoffTime = 2500, // Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)\n disableBc = DEFAULT_DISABLE_BC // Disable cross-tab BroadcastChannel communication\n }: {\n connect?: boolean;\n awareness?: awarenessProtocol.Awareness;\n params?: { [s: string]: string };\n isPrefixedUrl?: boolean;\n WebSocketPolyfill?: typeof WebSocket | null;\n resyncInterval?: number;\n maxBackoffTime?: number;\n disableBc?: boolean;\n } = {}\n ) {\n super();\n // ensure that url is always ends with /\n while (serverUrl[serverUrl.length - 1] === \"/\") {\n serverUrl = serverUrl.slice(0, serverUrl.length - 1);\n }\n const encodedParams = url.encodeQueryParams(params);\n this.maxBackoffTime = maxBackoffTime;\n this.bcChannel = `${serverUrl}/${roomname}`;\n this.url = isPrefixedUrl\n ? serverUrl\n : `${serverUrl}/${roomname}${encodedParams.length === 0 ? \"\" : `?${encodedParams}`}`;\n this.roomname = roomname;\n this.doc = doc;\n this._WS = WebSocketPolyfill!;\n this.awareness = awareness;\n this.wsconnected = false;\n this.wsconnecting = false;\n this.bcconnected = false;\n this.disableBc = disableBc;\n this.wsUnsuccessfulReconnects = 0;\n this.messageHandlers = messageHandlers.slice();\n\n this._synced = false;\n\n this.ws = null;\n this.wsLastMessageReceived = 0;\n\n this.shouldConnect = connect;\n\n this._resyncInterval = 0;\n if (resyncInterval > 0) {\n this._resyncInterval = /** @type {any} */ setInterval(() => {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n // resend sync step 1\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, doc);\n this.ws.send(encoding.toUint8Array(encoder));\n }\n }, resyncInterval);\n }\n\n this._bcSubscriber = (data: Uint8Array, origin: unknown) => {\n if (origin !== this) {\n const encoder = readMessage(this, new Uint8Array(data), false);\n if (encoding.length(encoder) > 1) {\n bc.publish(this.bcChannel, encoding.toUint8Array(encoder), this);\n }\n }\n };\n /**\n * Listens to Yjs updates and sends them to remote peers (ws and broadcastchannel)\n */\n this._updateHandler = (update: Uint8Array, origin: unknown) => {\n if (origin !== this) {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeUpdate(encoder, update);\n broadcastMessage(this, encoding.toUint8Array(encoder));\n }\n };\n this.doc.on(\"update\", this._updateHandler);\n\n this._awarenessUpdateHandler = (\n { added, updated, removed }: AwarenessUpdate,\n _origin: unknown\n ) => {\n const changedClients = added.concat(updated).concat(removed);\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(awareness, changedClients)\n );\n broadcastMessage(this, encoding.toUint8Array(encoder));\n };\n this._unloadHandler = () => {\n awarenessProtocol.removeAwarenessStates(\n this.awareness,\n [doc.clientID],\n \"window unload\"\n );\n };\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"unload\", this._unloadHandler);\n } else if (\n typeof process !== \"undefined\" &&\n typeof process.on === \"function\"\n ) {\n process.on(\"exit\", this._unloadHandler);\n }\n // Listen on 'change' (not 'update') so that clock-only awareness\n // renewals (the 15-second heartbeat) do NOT produce network traffic.\n // Only actual state changes (cursor moved, name changed, etc.) are sent.\n // This allows Durable Objects to hibernate when sessions are idle.\n awareness.on(\"change\", this._awarenessUpdateHandler);\n\n // Disable the awareness protocol's built-in check interval.\n // It renews the local clock every 15s (causing wire traffic that defeats\n // DO hibernation) and removes remote peers after 30s of inactivity.\n // We handle peer cleanup via WebSocket close events instead.\n clearInterval(\n (\n awareness as unknown as {\n _checkInterval: ReturnType<typeof setInterval>;\n }\n )._checkInterval\n );\n if (connect) {\n this.connect();\n }\n }\n\n /**\n * @type {boolean}\n */\n get synced() {\n return this._synced;\n }\n\n set synced(state) {\n if (this._synced !== state) {\n this._synced = state;\n this.emit(\"synced\", [state]);\n this.emit(\"sync\", [state]);\n }\n }\n\n destroy() {\n if (this._resyncInterval !== 0) {\n clearInterval(this._resyncInterval);\n }\n this.disconnect();\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"unload\", this._unloadHandler);\n } else if (\n typeof process !== \"undefined\" &&\n typeof process.off === \"function\"\n ) {\n process.off(\"exit\", this._unloadHandler);\n }\n this.awareness.off(\"change\", this._awarenessUpdateHandler);\n this.doc.off(\"update\", this._updateHandler);\n super.destroy();\n }\n\n connectBc() {\n if (this.disableBc) {\n return;\n }\n if (!this.bcconnected) {\n bc.subscribe(this.bcChannel, this._bcSubscriber);\n this.bcconnected = true;\n }\n // send sync step1 to bc\n // write sync step 1\n const encoderSync = encoding.createEncoder();\n encoding.writeVarUint(encoderSync, messageSync);\n syncProtocol.writeSyncStep1(encoderSync, this.doc);\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderSync), this);\n // broadcast local state\n const encoderState = encoding.createEncoder();\n encoding.writeVarUint(encoderState, messageSync);\n syncProtocol.writeSyncStep2(encoderState, this.doc);\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderState), this);\n // write queryAwareness\n const encoderAwarenessQuery = encoding.createEncoder();\n encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessQuery),\n this\n );\n // broadcast local awareness state\n const encoderAwarenessState = encoding.createEncoder();\n encoding.writeVarUint(encoderAwarenessState, messageAwareness);\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(this.awareness, [\n this.doc.clientID\n ])\n );\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessState),\n this\n );\n }\n\n disconnectBc() {\n // broadcast message with local awareness state set to null (indicating disconnect)\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n this.awareness,\n [this.doc.clientID],\n new Map()\n )\n );\n broadcastMessage(this, encoding.toUint8Array(encoder));\n if (this.bcconnected) {\n bc.unsubscribe(this.bcChannel, this._bcSubscriber);\n this.bcconnected = false;\n }\n }\n\n disconnect() {\n this.shouldConnect = false;\n this.disconnectBc();\n if (this.ws !== null) {\n this.ws.close();\n }\n }\n\n /**\n * Called by the close handler to re-establish the WebSocket.\n * Subclasses (e.g. YProvider) override this to refresh dynamic\n * params before reconnecting.\n */\n _reconnectWS() {\n setupWS(this);\n }\n\n connect() {\n this.shouldConnect = true;\n if (!this.wsconnected && this.ws === null) {\n setupWS(this);\n this.connectBc();\n }\n }\n}\n\nfunction assertType(value: unknown, label: string, type: string) {\n if (typeof value !== type) {\n throw new Error(\n `Invalid \"${label}\" parameter provided to YProvider. Expected: ${type}, received: ${value as string}`\n );\n }\n}\n\ntype Params = Record<string, string | null | undefined>;\ntype ParamsProvider = Params | (() => Params | Promise<Params>);\ntype BaseProviderOptions = ConstructorParameters<typeof WebsocketProvider>[3];\n\ntype YProviderOptions = Omit<NonNullable<BaseProviderOptions>, \"params\"> & {\n connectionId?: string;\n party?: string;\n prefix?: string;\n params?: ParamsProvider;\n protocol?: \"ws\" | \"wss\";\n};\n\nexport default class YProvider extends WebsocketProvider {\n id: string;\n #params?: ParamsProvider;\n\n constructor(\n host: string,\n room: string,\n doc?: YDoc,\n options: YProviderOptions = {}\n ) {\n assertType(host, \"host\", \"string\");\n assertType(room, \"room\", \"string\");\n\n // strip the protocol from the beginning of `host` if any\n host = host.replace(/^(http|https|ws|wss):\\/\\//, \"\");\n\n // strip trailing slash from host if any\n if (host.endsWith(\"/\")) {\n host = host.slice(0, -1);\n }\n\n const serverUrl = `${\n options.protocol ||\n (host.startsWith(\"localhost:\") ||\n host.startsWith(\"127.0.0.1:\") ||\n host.startsWith(\"192.168.\") ||\n host.startsWith(\"10.\") ||\n (host.startsWith(\"172.\") &&\n host.split(\".\")[1] >= \"16\" &&\n host.split(\".\")[1] <= \"31\")\n ? \"ws\"\n : \"wss\")\n }://${host}${options.prefix || `/parties/${options.party || \"main\"}`}`;\n\n // use provided id, or generate a random one\n const id = options.connectionId ?? nanoid(10);\n\n // don't pass params to WebsocketProvider, we override them in connect()\n const { params, connect = true, ...rest } = options;\n\n // don't connect until we've updated the url parameters\n const baseOptions = {\n ...rest,\n isPrefixedUrl: !!options.prefix,\n connect: false\n };\n\n super(serverUrl, room, doc ?? new YDoc(), baseOptions);\n\n this.id = id;\n this.#params = params;\n\n if (connect) {\n void this.connect();\n }\n }\n\n async #resolveParams() {\n const nextParams =\n typeof this.#params === \"function\" ? await this.#params() : this.#params;\n const urlParams = new URLSearchParams([[\"_pk\", this.id]]);\n if (nextParams) {\n for (const [key, value] of Object.entries(nextParams)) {\n if (value !== null && value !== undefined) {\n urlParams.append(key, value);\n }\n }\n }\n const nextUrl = new URL(this.url);\n nextUrl.search = urlParams.toString();\n this.url = nextUrl.toString();\n }\n\n async connect() {\n try {\n await this.#resolveParams();\n super.connect();\n } catch (err) {\n console.error(\"Failed to open connecton to PartyServer\", err);\n throw err;\n }\n }\n\n async _reconnectWS() {\n try {\n await this.#resolveParams();\n } catch (err) {\n console.error(\n \"Failed to refresh params, reconnecting with stale params\",\n err\n );\n }\n super._reconnectWS();\n }\n\n sendMessage(message: string) {\n this.ws?.send(`__YPS:${message}`);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["syncProtocol","awarenessProtocol","decoding","encoding","time","math","Observable","url","YDoc","#params","#resolveParams"],"sources":["../../src/provider/index.ts"],"sourcesContent":["import * as bc from \"lib0/broadcastchannel\";\nimport * as decoding from \"lib0/decoding\";\nimport * as encoding from \"lib0/encoding\";\nimport * as math from \"lib0/math\";\nimport { Observable } from \"lib0/observable\";\nimport * as time from \"lib0/time\";\nimport * as url from \"lib0/url\";\nimport { nanoid } from \"nanoid\";\nimport * as authProtocol from \"y-protocols/auth\";\nimport * as awarenessProtocol from \"y-protocols/awareness\";\nimport * as syncProtocol from \"y-protocols/sync\";\nimport { Doc as YDoc } from \"yjs\";\n\nexport const messageSync = 0;\nexport const messageQueryAwareness = 3;\nexport const messageAwareness = 1;\nexport const messageAuth = 2;\n\n// Disable BroadcastChannel by default in Cloudflare Workers / Node\nconst DEFAULT_DISABLE_BC = typeof window === \"undefined\";\n\nconst messageHandlers: Array<\n (\n encoder: encoding.Encoder,\n decoder: decoding.Decoder,\n provider: WebsocketProvider,\n emitSynced: boolean,\n messageType: number\n ) => void\n> = [];\n\nmessageHandlers[messageSync] = (\n encoder,\n decoder,\n provider,\n emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageSync);\n const syncMessageType = syncProtocol.readSyncMessage(\n decoder,\n encoder,\n provider.doc,\n provider\n );\n if (\n emitSynced &&\n syncMessageType === syncProtocol.messageYjsSyncStep2 &&\n !provider.synced\n ) {\n provider.synced = true;\n }\n};\n\nmessageHandlers[messageQueryAwareness] = (\n encoder,\n _decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n provider.awareness,\n Array.from(provider.awareness.getStates().keys())\n )\n );\n};\n\nmessageHandlers[messageAwareness] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n awarenessProtocol.applyAwarenessUpdate(\n provider.awareness,\n decoding.readVarUint8Array(decoder),\n provider\n );\n};\n\nmessageHandlers[messageAuth] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n authProtocol.readAuthMessage(decoder, provider.doc, (_ydoc, reason) =>\n permissionDeniedHandler(provider, reason)\n );\n};\n\nfunction permissionDeniedHandler(provider: WebsocketProvider, reason: string) {\n console.warn(`Permission denied to access ${provider.url}.\\n${reason}`);\n}\n\nfunction readMessage(\n provider: WebsocketProvider,\n buf: Uint8Array,\n emitSynced: boolean\n): encoding.Encoder {\n const decoder = decoding.createDecoder(buf);\n const encoder = encoding.createEncoder();\n const messageType = decoding.readVarUint(decoder);\n const messageHandler = provider.messageHandlers[messageType];\n if (/** @type {any} */ messageHandler) {\n messageHandler(encoder, decoder, provider, emitSynced, messageType);\n } else {\n console.error(\"Unable to compute message\");\n }\n return encoder;\n}\n\nfunction setupWS(provider: WebsocketProvider) {\n if (provider.shouldConnect && provider.ws === null) {\n if (!provider._WS) {\n throw new Error(\n \"No WebSocket implementation available, did you forget to pass options.WebSocketPolyfill?\"\n );\n }\n const websocket = new provider._WS(provider.url);\n websocket.binaryType = \"arraybuffer\";\n provider.ws = websocket;\n provider.wsconnecting = true;\n provider.wsconnected = false;\n provider.synced = false;\n\n websocket.addEventListener(\"message\", (event) => {\n if (typeof event.data === \"string\") {\n // Handle custom messages with __YPS: prefix\n if (event.data.startsWith(\"__YPS:\")) {\n const customMessage = event.data.slice(6); // Remove __YPS: prefix\n provider.emit(\"custom-message\", [customMessage]);\n }\n return;\n }\n provider.wsLastMessageReceived = time.getUnixTime();\n const encoder = readMessage(provider, new Uint8Array(event.data), true);\n if (encoding.length(encoder) > 1) {\n websocket.send(encoding.toUint8Array(encoder));\n }\n });\n websocket.addEventListener(\"error\", (event) => {\n provider.emit(\"connection-error\", [event, provider]);\n });\n websocket.addEventListener(\"close\", (event) => {\n provider.emit(\"connection-close\", [event, provider]);\n provider.ws = null;\n provider.wsconnecting = false;\n if (provider.wsconnected) {\n provider.wsconnected = false;\n provider.synced = false;\n // update awareness (all users except local left)\n const removedClients = Array.from(\n provider.awareness.getStates().keys()\n ).filter((client) => client !== provider.doc.clientID);\n awarenessProtocol.removeAwarenessStates(\n provider.awareness,\n removedClients,\n provider\n );\n // Clear stale meta for remote clients so their awareness\n // updates are accepted on reconnect (clock check starts fresh)\n for (const clientID of removedClients) {\n provider.awareness.meta.delete(clientID);\n }\n provider.emit(\"status\", [\n {\n status: \"disconnected\"\n }\n ]);\n } else {\n provider.wsUnsuccessfulReconnects++;\n }\n // Start with no reconnect timeout and increase timeout by\n // using exponential backoff starting with 100ms\n setTimeout(\n () => {\n if (provider.shouldConnect) {\n Promise.resolve(provider._reconnectWS()).catch((err) => {\n console.error(\"Reconnection failed\", err);\n });\n }\n },\n math.min(\n math.pow(2, provider.wsUnsuccessfulReconnects) * 100,\n provider.maxBackoffTime\n )\n );\n });\n websocket.addEventListener(\"open\", () => {\n provider.wsLastMessageReceived = time.getUnixTime();\n provider.wsconnecting = false;\n provider.wsconnected = true;\n provider.wsUnsuccessfulReconnects = 0;\n provider.emit(\"status\", [\n {\n status: \"connected\"\n }\n ]);\n // always send sync step 1 when connected\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, provider.doc);\n websocket.send(encoding.toUint8Array(encoder));\n // broadcast local awareness state\n if (provider.awareness.getLocalState() !== null) {\n // Re-set local state to bump the awareness clock, ensuring\n // remote clients accept the update even if they have stale meta\n provider.awareness.setLocalState(provider.awareness.getLocalState());\n const encoderAwarenessState = encoding.createEncoder();\n encoding.writeVarUint(encoderAwarenessState, messageAwareness);\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(provider.awareness, [\n provider.doc.clientID\n ])\n );\n websocket.send(encoding.toUint8Array(encoderAwarenessState));\n }\n });\n provider.emit(\"status\", [\n {\n status: \"connecting\"\n }\n ]);\n }\n}\n\nfunction broadcastMessage(provider: WebsocketProvider, buf: Uint8Array) {\n const ws = provider.ws;\n if (provider.wsconnected && ws && ws.readyState === ws.OPEN) {\n ws.send(buf);\n }\n if (provider.bcconnected) {\n bc.publish(provider.bcChannel, buf, provider);\n }\n}\n\ntype AwarenessUpdate = {\n added: number[];\n updated: number[];\n removed: number[];\n};\n\nconst DefaultWebSocket = typeof WebSocket === \"undefined\" ? null : WebSocket;\n\n/**\n * Websocket Provider for Yjs. Creates a websocket connection to sync the shared document.\n * The document name is attached to the provided url. I.e. the following example\n * creates a websocket connection to http://localhost:1234/my-document-name\n *\n * @example\n * import * as Y from 'yjs'\n * import { WebsocketProvider } from 'y-websocket'\n * const doc = new Y.Doc()\n * const provider = new WebsocketProvider('http://localhost:1234', 'my-document-name', doc)\n *\n * @extends {Observable<string>}\n */\nexport class WebsocketProvider extends Observable<string> {\n maxBackoffTime: number;\n bcChannel: string;\n url: string;\n roomname: string;\n doc: YDoc;\n _WS: typeof WebSocket;\n awareness: awarenessProtocol.Awareness;\n wsconnected: boolean;\n wsconnecting: boolean;\n bcconnected: boolean;\n disableBc: boolean;\n wsUnsuccessfulReconnects: number;\n messageHandlers: typeof messageHandlers;\n _synced: boolean;\n ws: WebSocket | null;\n wsLastMessageReceived: number;\n shouldConnect: boolean; // Whether to connect to other peers or not\n _resyncInterval: ReturnType<typeof setInterval> | number;\n _bcSubscriber: (message: Uint8Array, origin: unknown) => void;\n _updateHandler: (update: Uint8Array, origin: unknown) => void;\n _awarenessUpdateHandler: (update: AwarenessUpdate, origin: unknown) => void;\n _unloadHandler: () => void;\n\n constructor(\n serverUrl: string,\n roomname: string,\n doc: YDoc,\n {\n connect = true,\n awareness = new awarenessProtocol.Awareness(doc),\n params = {},\n isPrefixedUrl = false,\n WebSocketPolyfill = DefaultWebSocket, // Optionally provide a WebSocket polyfill\n resyncInterval = -1, // Request server state every `resyncInterval` milliseconds\n maxBackoffTime = 2500, // Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)\n disableBc = DEFAULT_DISABLE_BC // Disable cross-tab BroadcastChannel communication\n }: {\n connect?: boolean;\n awareness?: awarenessProtocol.Awareness;\n params?: { [s: string]: string };\n isPrefixedUrl?: boolean;\n WebSocketPolyfill?: typeof WebSocket | null;\n resyncInterval?: number;\n maxBackoffTime?: number;\n disableBc?: boolean;\n } = {}\n ) {\n super();\n // ensure that url is always ends with /\n while (serverUrl[serverUrl.length - 1] === \"/\") {\n serverUrl = serverUrl.slice(0, serverUrl.length - 1);\n }\n const encodedParams = url.encodeQueryParams(params);\n this.maxBackoffTime = maxBackoffTime;\n this.bcChannel = `${serverUrl}/${roomname}`;\n this.url = isPrefixedUrl\n ? serverUrl\n : `${serverUrl}/${roomname}${encodedParams.length === 0 ? \"\" : `?${encodedParams}`}`;\n this.roomname = roomname;\n this.doc = doc;\n this._WS = WebSocketPolyfill!;\n this.awareness = awareness;\n this.wsconnected = false;\n this.wsconnecting = false;\n this.bcconnected = false;\n this.disableBc = disableBc;\n this.wsUnsuccessfulReconnects = 0;\n this.messageHandlers = messageHandlers.slice();\n\n this._synced = false;\n\n this.ws = null;\n this.wsLastMessageReceived = 0;\n\n this.shouldConnect = connect;\n\n this._resyncInterval = 0;\n if (resyncInterval > 0) {\n this._resyncInterval = /** @type {any} */ setInterval(() => {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n // resend sync step 1\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, doc);\n this.ws.send(encoding.toUint8Array(encoder));\n }\n }, resyncInterval);\n }\n\n this._bcSubscriber = (data: Uint8Array, origin: unknown) => {\n if (origin !== this) {\n const encoder = readMessage(this, new Uint8Array(data), false);\n if (encoding.length(encoder) > 1) {\n bc.publish(this.bcChannel, encoding.toUint8Array(encoder), this);\n }\n }\n };\n /**\n * Listens to Yjs updates and sends them to remote peers (ws and broadcastchannel)\n */\n this._updateHandler = (update: Uint8Array, origin: unknown) => {\n if (origin !== this) {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeUpdate(encoder, update);\n broadcastMessage(this, encoding.toUint8Array(encoder));\n }\n };\n this.doc.on(\"update\", this._updateHandler);\n\n this._awarenessUpdateHandler = (\n { added, updated, removed }: AwarenessUpdate,\n _origin: unknown\n ) => {\n const changedClients = added.concat(updated).concat(removed);\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(awareness, changedClients)\n );\n broadcastMessage(this, encoding.toUint8Array(encoder));\n };\n this._unloadHandler = () => {\n awarenessProtocol.removeAwarenessStates(\n this.awareness,\n [doc.clientID],\n \"window unload\"\n );\n };\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"unload\", this._unloadHandler);\n } else if (\n typeof process !== \"undefined\" &&\n typeof process.on === \"function\"\n ) {\n process.on(\"exit\", this._unloadHandler);\n }\n // Listen on 'change' (not 'update') so that clock-only awareness\n // renewals (the 15-second heartbeat) do NOT produce network traffic.\n // Only actual state changes (cursor moved, name changed, etc.) are sent.\n // This allows Durable Objects to hibernate when sessions are idle.\n awareness.on(\"change\", this._awarenessUpdateHandler);\n\n // Disable the awareness protocol's built-in check interval.\n // It renews the local clock every 15s (causing wire traffic that defeats\n // DO hibernation) and removes remote peers after 30s of inactivity.\n // We handle peer cleanup via WebSocket close events instead.\n clearInterval(\n (\n awareness as unknown as {\n _checkInterval: ReturnType<typeof setInterval>;\n }\n )._checkInterval\n );\n if (connect) {\n this.connect();\n }\n }\n\n /**\n * @type {boolean}\n */\n get synced() {\n return this._synced;\n }\n\n set synced(state) {\n if (this._synced !== state) {\n this._synced = state;\n this.emit(\"synced\", [state]);\n this.emit(\"sync\", [state]);\n }\n }\n\n destroy() {\n if (this._resyncInterval !== 0) {\n clearInterval(this._resyncInterval);\n }\n this.disconnect();\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"unload\", this._unloadHandler);\n } else if (\n typeof process !== \"undefined\" &&\n typeof process.off === \"function\"\n ) {\n process.off(\"exit\", this._unloadHandler);\n }\n this.awareness.off(\"change\", this._awarenessUpdateHandler);\n this.doc.off(\"update\", this._updateHandler);\n super.destroy();\n }\n\n connectBc() {\n if (this.disableBc) {\n return;\n }\n if (!this.bcconnected) {\n bc.subscribe(this.bcChannel, this._bcSubscriber);\n this.bcconnected = true;\n }\n // send sync step1 to bc\n // write sync step 1\n const encoderSync = encoding.createEncoder();\n encoding.writeVarUint(encoderSync, messageSync);\n syncProtocol.writeSyncStep1(encoderSync, this.doc);\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderSync), this);\n // broadcast local state\n const encoderState = encoding.createEncoder();\n encoding.writeVarUint(encoderState, messageSync);\n syncProtocol.writeSyncStep2(encoderState, this.doc);\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderState), this);\n // write queryAwareness\n const encoderAwarenessQuery = encoding.createEncoder();\n encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessQuery),\n this\n );\n // broadcast local awareness state\n const encoderAwarenessState = encoding.createEncoder();\n encoding.writeVarUint(encoderAwarenessState, messageAwareness);\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(this.awareness, [\n this.doc.clientID\n ])\n );\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessState),\n this\n );\n }\n\n disconnectBc() {\n // broadcast message with local awareness state set to null (indicating disconnect)\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n this.awareness,\n [this.doc.clientID],\n new Map()\n )\n );\n broadcastMessage(this, encoding.toUint8Array(encoder));\n if (this.bcconnected) {\n bc.unsubscribe(this.bcChannel, this._bcSubscriber);\n this.bcconnected = false;\n }\n }\n\n disconnect() {\n this.shouldConnect = false;\n this.disconnectBc();\n if (this.ws !== null) {\n this.ws.close();\n }\n }\n\n /**\n * Called by the close handler to re-establish the WebSocket.\n * Subclasses (e.g. YProvider) override this to refresh dynamic\n * params before reconnecting.\n */\n _reconnectWS() {\n setupWS(this);\n }\n\n connect() {\n this.shouldConnect = true;\n if (!this.wsconnected && this.ws === null) {\n setupWS(this);\n this.connectBc();\n }\n }\n}\n\nfunction assertType(value: unknown, label: string, type: string) {\n if (typeof value !== type) {\n throw new Error(\n `Invalid \"${label}\" parameter provided to YProvider. Expected: ${type}, received: ${value as string}`\n );\n }\n}\n\ntype Params = Record<string, string | null | undefined>;\ntype ParamsProvider = Params | (() => Params | Promise<Params>);\ntype BaseProviderOptions = ConstructorParameters<typeof WebsocketProvider>[3];\n\ntype YProviderOptions = Omit<NonNullable<BaseProviderOptions>, \"params\"> & {\n connectionId?: string;\n party?: string;\n prefix?: string;\n params?: ParamsProvider;\n protocol?: \"ws\" | \"wss\";\n};\n\nexport default class YProvider extends WebsocketProvider {\n id: string;\n #params?: ParamsProvider;\n\n constructor(\n host: string,\n room: string,\n doc?: YDoc,\n options: YProviderOptions = {}\n ) {\n assertType(host, \"host\", \"string\");\n assertType(room, \"room\", \"string\");\n\n // strip the protocol from the beginning of `host` if any\n host = host.replace(/^(http|https|ws|wss):\\/\\//, \"\");\n\n // strip trailing slash from host if any\n if (host.endsWith(\"/\")) {\n host = host.slice(0, -1);\n }\n\n const serverUrl = `${\n options.protocol ||\n (host.startsWith(\"localhost:\") ||\n host.startsWith(\"127.0.0.1:\") ||\n host.startsWith(\"192.168.\") ||\n host.startsWith(\"10.\") ||\n (host.startsWith(\"172.\") &&\n host.split(\".\")[1] >= \"16\" &&\n host.split(\".\")[1] <= \"31\")\n ? \"ws\"\n : \"wss\")\n }://${host}${options.prefix || `/parties/${options.party || \"main\"}`}`;\n\n // use provided id, or generate a random one\n const id = options.connectionId ?? nanoid(10);\n\n // don't pass params to WebsocketProvider, we override them in connect()\n const { params, connect = true, ...rest } = options;\n\n // don't connect until we've updated the url parameters\n const baseOptions = {\n ...rest,\n isPrefixedUrl: !!options.prefix,\n connect: false\n };\n\n super(serverUrl, room, doc ?? new YDoc(), baseOptions);\n\n this.id = id;\n this.#params = params;\n\n if (connect) {\n void this.connect();\n }\n }\n\n async #resolveParams() {\n const nextParams =\n typeof this.#params === \"function\" ? await this.#params() : this.#params;\n const urlParams = new URLSearchParams([[\"_pk\", this.id]]);\n if (nextParams) {\n for (const [key, value] of Object.entries(nextParams)) {\n if (value !== null && value !== undefined) {\n urlParams.append(key, value);\n }\n }\n }\n const nextUrl = new URL(this.url);\n nextUrl.search = urlParams.toString();\n this.url = nextUrl.toString();\n }\n\n async connect() {\n try {\n await this.#resolveParams();\n super.connect();\n } catch (err) {\n console.error(\"Failed to open connecton to PartyServer\", err);\n throw err;\n }\n }\n\n async _reconnectWS() {\n try {\n await this.#resolveParams();\n } catch (err) {\n console.error(\n \"Failed to refresh params, reconnecting with stale params\",\n err\n );\n }\n super._reconnectWS();\n }\n\n sendMessage(message: string) {\n this.ws?.send(`__YPS:${message}`);\n }\n}\n"],"mappings":"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"}
|
package/dist/provider/index.js
CHANGED
|
@@ -10,7 +10,6 @@ import * as time from "lib0/time";
|
|
|
10
10
|
import * as url from "lib0/url";
|
|
11
11
|
import { nanoid } from "nanoid";
|
|
12
12
|
import * as authProtocol from "y-protocols/auth";
|
|
13
|
-
|
|
14
13
|
//#region src/provider/index.ts
|
|
15
14
|
const messageSync = 0;
|
|
16
15
|
const messageQueryAwareness = 3;
|
|
@@ -18,14 +17,8 @@ const messageAwareness = 1;
|
|
|
18
17
|
const messageAuth = 2;
|
|
19
18
|
const DEFAULT_DISABLE_BC = typeof window === "undefined";
|
|
20
19
|
const messageHandlers = [];
|
|
21
|
-
messageHandlers[
|
|
22
|
-
encoder,
|
|
23
|
-
decoder,
|
|
24
|
-
provider,
|
|
25
|
-
emitSynced,
|
|
26
|
-
_messageType
|
|
27
|
-
) => {
|
|
28
|
-
encoding.writeVarUint(encoder, messageSync);
|
|
20
|
+
messageHandlers[0] = (encoder, decoder, provider, emitSynced, _messageType) => {
|
|
21
|
+
encoding.writeVarUint(encoder, 0);
|
|
29
22
|
const syncMessageType = syncProtocol.readSyncMessage(
|
|
30
23
|
decoder,
|
|
31
24
|
encoder,
|
|
@@ -39,14 +32,14 @@ messageHandlers[messageSync] = (
|
|
|
39
32
|
)
|
|
40
33
|
provider.synced = true;
|
|
41
34
|
};
|
|
42
|
-
messageHandlers[
|
|
35
|
+
messageHandlers[3] = (
|
|
43
36
|
encoder,
|
|
44
37
|
_decoder,
|
|
45
38
|
provider,
|
|
46
39
|
_emitSynced,
|
|
47
40
|
_messageType
|
|
48
41
|
) => {
|
|
49
|
-
encoding.writeVarUint(encoder,
|
|
42
|
+
encoding.writeVarUint(encoder, 1);
|
|
50
43
|
encoding.writeVarUint8Array(
|
|
51
44
|
encoder,
|
|
52
45
|
awarenessProtocol.encodeAwarenessUpdate(
|
|
@@ -55,7 +48,7 @@ messageHandlers[messageQueryAwareness] = (
|
|
|
55
48
|
)
|
|
56
49
|
);
|
|
57
50
|
};
|
|
58
|
-
messageHandlers[
|
|
51
|
+
messageHandlers[1] = (
|
|
59
52
|
_encoder,
|
|
60
53
|
decoder,
|
|
61
54
|
provider,
|
|
@@ -68,7 +61,7 @@ messageHandlers[messageAwareness] = (
|
|
|
68
61
|
provider
|
|
69
62
|
);
|
|
70
63
|
};
|
|
71
|
-
messageHandlers[
|
|
64
|
+
messageHandlers[2] = (
|
|
72
65
|
_encoder,
|
|
73
66
|
decoder,
|
|
74
67
|
provider,
|
|
@@ -159,13 +152,13 @@ function setupWS(provider) {
|
|
|
159
152
|
provider.wsUnsuccessfulReconnects = 0;
|
|
160
153
|
provider.emit("status", [{ status: "connected" }]);
|
|
161
154
|
const encoder = encoding.createEncoder();
|
|
162
|
-
encoding.writeVarUint(encoder,
|
|
155
|
+
encoding.writeVarUint(encoder, 0);
|
|
163
156
|
syncProtocol.writeSyncStep1(encoder, provider.doc);
|
|
164
157
|
websocket.send(encoding.toUint8Array(encoder));
|
|
165
158
|
if (provider.awareness.getLocalState() !== null) {
|
|
166
159
|
provider.awareness.setLocalState(provider.awareness.getLocalState());
|
|
167
160
|
const encoderAwarenessState = encoding.createEncoder();
|
|
168
|
-
encoding.writeVarUint(encoderAwarenessState,
|
|
161
|
+
encoding.writeVarUint(encoderAwarenessState, 1);
|
|
169
162
|
encoding.writeVarUint8Array(
|
|
170
163
|
encoderAwarenessState,
|
|
171
164
|
awarenessProtocol.encodeAwarenessUpdate(provider.awareness, [
|
|
@@ -263,7 +256,7 @@ var WebsocketProvider = class extends Observable {
|
|
|
263
256
|
this._resyncInterval = setInterval(() => {
|
|
264
257
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
265
258
|
const encoder = encoding.createEncoder();
|
|
266
|
-
encoding.writeVarUint(encoder,
|
|
259
|
+
encoding.writeVarUint(encoder, 0);
|
|
267
260
|
syncProtocol.writeSyncStep1(encoder, doc);
|
|
268
261
|
this.ws.send(encoding.toUint8Array(encoder));
|
|
269
262
|
}
|
|
@@ -281,7 +274,7 @@ var WebsocketProvider = class extends Observable {
|
|
|
281
274
|
this._updateHandler = (update, origin) => {
|
|
282
275
|
if (origin !== this) {
|
|
283
276
|
const encoder = encoding.createEncoder();
|
|
284
|
-
encoding.writeVarUint(encoder,
|
|
277
|
+
encoding.writeVarUint(encoder, 0);
|
|
285
278
|
syncProtocol.writeUpdate(encoder, update);
|
|
286
279
|
broadcastMessage(this, encoding.toUint8Array(encoder));
|
|
287
280
|
}
|
|
@@ -290,7 +283,7 @@ var WebsocketProvider = class extends Observable {
|
|
|
290
283
|
this._awarenessUpdateHandler = ({ added, updated, removed }, _origin) => {
|
|
291
284
|
const changedClients = added.concat(updated).concat(removed);
|
|
292
285
|
const encoder = encoding.createEncoder();
|
|
293
|
-
encoding.writeVarUint(encoder,
|
|
286
|
+
encoding.writeVarUint(encoder, 1);
|
|
294
287
|
encoding.writeVarUint8Array(
|
|
295
288
|
encoder,
|
|
296
289
|
awarenessProtocol.encodeAwarenessUpdate(awareness, changedClients)
|
|
@@ -346,22 +339,22 @@ var WebsocketProvider = class extends Observable {
|
|
|
346
339
|
this.bcconnected = true;
|
|
347
340
|
}
|
|
348
341
|
const encoderSync = encoding.createEncoder();
|
|
349
|
-
encoding.writeVarUint(encoderSync,
|
|
342
|
+
encoding.writeVarUint(encoderSync, 0);
|
|
350
343
|
syncProtocol.writeSyncStep1(encoderSync, this.doc);
|
|
351
344
|
bc.publish(this.bcChannel, encoding.toUint8Array(encoderSync), this);
|
|
352
345
|
const encoderState = encoding.createEncoder();
|
|
353
|
-
encoding.writeVarUint(encoderState,
|
|
346
|
+
encoding.writeVarUint(encoderState, 0);
|
|
354
347
|
syncProtocol.writeSyncStep2(encoderState, this.doc);
|
|
355
348
|
bc.publish(this.bcChannel, encoding.toUint8Array(encoderState), this);
|
|
356
349
|
const encoderAwarenessQuery = encoding.createEncoder();
|
|
357
|
-
encoding.writeVarUint(encoderAwarenessQuery,
|
|
350
|
+
encoding.writeVarUint(encoderAwarenessQuery, 3);
|
|
358
351
|
bc.publish(
|
|
359
352
|
this.bcChannel,
|
|
360
353
|
encoding.toUint8Array(encoderAwarenessQuery),
|
|
361
354
|
this
|
|
362
355
|
);
|
|
363
356
|
const encoderAwarenessState = encoding.createEncoder();
|
|
364
|
-
encoding.writeVarUint(encoderAwarenessState,
|
|
357
|
+
encoding.writeVarUint(encoderAwarenessState, 1);
|
|
365
358
|
encoding.writeVarUint8Array(
|
|
366
359
|
encoderAwarenessState,
|
|
367
360
|
awarenessProtocol.encodeAwarenessUpdate(this.awareness, [
|
|
@@ -376,7 +369,7 @@ var WebsocketProvider = class extends Observable {
|
|
|
376
369
|
}
|
|
377
370
|
disconnectBc() {
|
|
378
371
|
const encoder = encoding.createEncoder();
|
|
379
|
-
encoding.writeVarUint(encoder,
|
|
372
|
+
encoding.writeVarUint(encoder, 1);
|
|
380
373
|
encoding.writeVarUint8Array(
|
|
381
374
|
encoder,
|
|
382
375
|
awarenessProtocol.encodeAwarenessUpdate(
|
|
@@ -475,7 +468,6 @@ var YProvider = class extends WebsocketProvider {
|
|
|
475
468
|
this.ws?.send(`__YPS:${message}`);
|
|
476
469
|
}
|
|
477
470
|
};
|
|
478
|
-
|
|
479
471
|
//#endregion
|
|
480
472
|
export {
|
|
481
473
|
WebsocketProvider,
|
|
@@ -485,4 +477,5 @@ export {
|
|
|
485
477
|
messageQueryAwareness,
|
|
486
478
|
messageSync
|
|
487
479
|
};
|
|
480
|
+
|
|
488
481
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["YDoc","#params","#resolveParams"],"sources":["../../src/provider/index.ts"],"sourcesContent":["import * as bc from \"lib0/broadcastchannel\";\nimport * as decoding from \"lib0/decoding\";\nimport * as encoding from \"lib0/encoding\";\nimport * as math from \"lib0/math\";\nimport { Observable } from \"lib0/observable\";\nimport * as time from \"lib0/time\";\nimport * as url from \"lib0/url\";\nimport { nanoid } from \"nanoid\";\nimport * as authProtocol from \"y-protocols/auth\";\nimport * as awarenessProtocol from \"y-protocols/awareness\";\nimport * as syncProtocol from \"y-protocols/sync\";\nimport { Doc as YDoc } from \"yjs\";\n\nexport const messageSync = 0;\nexport const messageQueryAwareness = 3;\nexport const messageAwareness = 1;\nexport const messageAuth = 2;\n\n// Disable BroadcastChannel by default in Cloudflare Workers / Node\nconst DEFAULT_DISABLE_BC = typeof window === \"undefined\";\n\nconst messageHandlers: Array<\n (\n encoder: encoding.Encoder,\n decoder: decoding.Decoder,\n provider: WebsocketProvider,\n emitSynced: boolean,\n messageType: number\n ) => void\n> = [];\n\nmessageHandlers[messageSync] = (\n encoder,\n decoder,\n provider,\n emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageSync);\n const syncMessageType = syncProtocol.readSyncMessage(\n decoder,\n encoder,\n provider.doc,\n provider\n );\n if (\n emitSynced &&\n syncMessageType === syncProtocol.messageYjsSyncStep2 &&\n !provider.synced\n ) {\n provider.synced = true;\n }\n};\n\nmessageHandlers[messageQueryAwareness] = (\n encoder,\n _decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n provider.awareness,\n Array.from(provider.awareness.getStates().keys())\n )\n );\n};\n\nmessageHandlers[messageAwareness] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n awarenessProtocol.applyAwarenessUpdate(\n provider.awareness,\n decoding.readVarUint8Array(decoder),\n provider\n );\n};\n\nmessageHandlers[messageAuth] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n authProtocol.readAuthMessage(decoder, provider.doc, (_ydoc, reason) =>\n permissionDeniedHandler(provider, reason)\n );\n};\n\nfunction permissionDeniedHandler(provider: WebsocketProvider, reason: string) {\n console.warn(`Permission denied to access ${provider.url}.\\n${reason}`);\n}\n\nfunction readMessage(\n provider: WebsocketProvider,\n buf: Uint8Array,\n emitSynced: boolean\n): encoding.Encoder {\n const decoder = decoding.createDecoder(buf);\n const encoder = encoding.createEncoder();\n const messageType = decoding.readVarUint(decoder);\n const messageHandler = provider.messageHandlers[messageType];\n if (/** @type {any} */ messageHandler) {\n messageHandler(encoder, decoder, provider, emitSynced, messageType);\n } else {\n console.error(\"Unable to compute message\");\n }\n return encoder;\n}\n\nfunction setupWS(provider: WebsocketProvider) {\n if (provider.shouldConnect && provider.ws === null) {\n if (!provider._WS) {\n throw new Error(\n \"No WebSocket implementation available, did you forget to pass options.WebSocketPolyfill?\"\n );\n }\n const websocket = new provider._WS(provider.url);\n websocket.binaryType = \"arraybuffer\";\n provider.ws = websocket;\n provider.wsconnecting = true;\n provider.wsconnected = false;\n provider.synced = false;\n\n websocket.addEventListener(\"message\", (event) => {\n if (typeof event.data === \"string\") {\n // Handle custom messages with __YPS: prefix\n if (event.data.startsWith(\"__YPS:\")) {\n const customMessage = event.data.slice(6); // Remove __YPS: prefix\n provider.emit(\"custom-message\", [customMessage]);\n }\n return;\n }\n provider.wsLastMessageReceived = time.getUnixTime();\n const encoder = readMessage(provider, new Uint8Array(event.data), true);\n if (encoding.length(encoder) > 1) {\n websocket.send(encoding.toUint8Array(encoder));\n }\n });\n websocket.addEventListener(\"error\", (event) => {\n provider.emit(\"connection-error\", [event, provider]);\n });\n websocket.addEventListener(\"close\", (event) => {\n provider.emit(\"connection-close\", [event, provider]);\n provider.ws = null;\n provider.wsconnecting = false;\n if (provider.wsconnected) {\n provider.wsconnected = false;\n provider.synced = false;\n // update awareness (all users except local left)\n const removedClients = Array.from(\n provider.awareness.getStates().keys()\n ).filter((client) => client !== provider.doc.clientID);\n awarenessProtocol.removeAwarenessStates(\n provider.awareness,\n removedClients,\n provider\n );\n // Clear stale meta for remote clients so their awareness\n // updates are accepted on reconnect (clock check starts fresh)\n for (const clientID of removedClients) {\n provider.awareness.meta.delete(clientID);\n }\n provider.emit(\"status\", [\n {\n status: \"disconnected\"\n }\n ]);\n } else {\n provider.wsUnsuccessfulReconnects++;\n }\n // Start with no reconnect timeout and increase timeout by\n // using exponential backoff starting with 100ms\n setTimeout(\n () => {\n if (provider.shouldConnect) {\n Promise.resolve(provider._reconnectWS()).catch((err) => {\n console.error(\"Reconnection failed\", err);\n });\n }\n },\n math.min(\n math.pow(2, provider.wsUnsuccessfulReconnects) * 100,\n provider.maxBackoffTime\n )\n );\n });\n websocket.addEventListener(\"open\", () => {\n provider.wsLastMessageReceived = time.getUnixTime();\n provider.wsconnecting = false;\n provider.wsconnected = true;\n provider.wsUnsuccessfulReconnects = 0;\n provider.emit(\"status\", [\n {\n status: \"connected\"\n }\n ]);\n // always send sync step 1 when connected\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, provider.doc);\n websocket.send(encoding.toUint8Array(encoder));\n // broadcast local awareness state\n if (provider.awareness.getLocalState() !== null) {\n // Re-set local state to bump the awareness clock, ensuring\n // remote clients accept the update even if they have stale meta\n provider.awareness.setLocalState(provider.awareness.getLocalState());\n const encoderAwarenessState = encoding.createEncoder();\n encoding.writeVarUint(encoderAwarenessState, messageAwareness);\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(provider.awareness, [\n provider.doc.clientID\n ])\n );\n websocket.send(encoding.toUint8Array(encoderAwarenessState));\n }\n });\n provider.emit(\"status\", [\n {\n status: \"connecting\"\n }\n ]);\n }\n}\n\nfunction broadcastMessage(provider: WebsocketProvider, buf: Uint8Array) {\n const ws = provider.ws;\n if (provider.wsconnected && ws && ws.readyState === ws.OPEN) {\n ws.send(buf);\n }\n if (provider.bcconnected) {\n bc.publish(provider.bcChannel, buf, provider);\n }\n}\n\ntype AwarenessUpdate = {\n added: number[];\n updated: number[];\n removed: number[];\n};\n\nconst DefaultWebSocket = typeof WebSocket === \"undefined\" ? null : WebSocket;\n\n/**\n * Websocket Provider for Yjs. Creates a websocket connection to sync the shared document.\n * The document name is attached to the provided url. I.e. the following example\n * creates a websocket connection to http://localhost:1234/my-document-name\n *\n * @example\n * import * as Y from 'yjs'\n * import { WebsocketProvider } from 'y-websocket'\n * const doc = new Y.Doc()\n * const provider = new WebsocketProvider('http://localhost:1234', 'my-document-name', doc)\n *\n * @extends {Observable<string>}\n */\nexport class WebsocketProvider extends Observable<string> {\n maxBackoffTime: number;\n bcChannel: string;\n url: string;\n roomname: string;\n doc: YDoc;\n _WS: typeof WebSocket;\n awareness: awarenessProtocol.Awareness;\n wsconnected: boolean;\n wsconnecting: boolean;\n bcconnected: boolean;\n disableBc: boolean;\n wsUnsuccessfulReconnects: number;\n messageHandlers: typeof messageHandlers;\n _synced: boolean;\n ws: WebSocket | null;\n wsLastMessageReceived: number;\n shouldConnect: boolean; // Whether to connect to other peers or not\n _resyncInterval: ReturnType<typeof setInterval> | number;\n _bcSubscriber: (message: Uint8Array, origin: unknown) => void;\n _updateHandler: (update: Uint8Array, origin: unknown) => void;\n _awarenessUpdateHandler: (update: AwarenessUpdate, origin: unknown) => void;\n _unloadHandler: () => void;\n\n constructor(\n serverUrl: string,\n roomname: string,\n doc: YDoc,\n {\n connect = true,\n awareness = new awarenessProtocol.Awareness(doc),\n params = {},\n isPrefixedUrl = false,\n WebSocketPolyfill = DefaultWebSocket, // Optionally provide a WebSocket polyfill\n resyncInterval = -1, // Request server state every `resyncInterval` milliseconds\n maxBackoffTime = 2500, // Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)\n disableBc = DEFAULT_DISABLE_BC // Disable cross-tab BroadcastChannel communication\n }: {\n connect?: boolean;\n awareness?: awarenessProtocol.Awareness;\n params?: { [s: string]: string };\n isPrefixedUrl?: boolean;\n WebSocketPolyfill?: typeof WebSocket | null;\n resyncInterval?: number;\n maxBackoffTime?: number;\n disableBc?: boolean;\n } = {}\n ) {\n super();\n // ensure that url is always ends with /\n while (serverUrl[serverUrl.length - 1] === \"/\") {\n serverUrl = serverUrl.slice(0, serverUrl.length - 1);\n }\n const encodedParams = url.encodeQueryParams(params);\n this.maxBackoffTime = maxBackoffTime;\n this.bcChannel = `${serverUrl}/${roomname}`;\n this.url = isPrefixedUrl\n ? serverUrl\n : `${serverUrl}/${roomname}${encodedParams.length === 0 ? \"\" : `?${encodedParams}`}`;\n this.roomname = roomname;\n this.doc = doc;\n this._WS = WebSocketPolyfill!;\n this.awareness = awareness;\n this.wsconnected = false;\n this.wsconnecting = false;\n this.bcconnected = false;\n this.disableBc = disableBc;\n this.wsUnsuccessfulReconnects = 0;\n this.messageHandlers = messageHandlers.slice();\n\n this._synced = false;\n\n this.ws = null;\n this.wsLastMessageReceived = 0;\n\n this.shouldConnect = connect;\n\n this._resyncInterval = 0;\n if (resyncInterval > 0) {\n this._resyncInterval = /** @type {any} */ setInterval(() => {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n // resend sync step 1\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, doc);\n this.ws.send(encoding.toUint8Array(encoder));\n }\n }, resyncInterval);\n }\n\n this._bcSubscriber = (data: Uint8Array, origin: unknown) => {\n if (origin !== this) {\n const encoder = readMessage(this, new Uint8Array(data), false);\n if (encoding.length(encoder) > 1) {\n bc.publish(this.bcChannel, encoding.toUint8Array(encoder), this);\n }\n }\n };\n /**\n * Listens to Yjs updates and sends them to remote peers (ws and broadcastchannel)\n */\n this._updateHandler = (update: Uint8Array, origin: unknown) => {\n if (origin !== this) {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeUpdate(encoder, update);\n broadcastMessage(this, encoding.toUint8Array(encoder));\n }\n };\n this.doc.on(\"update\", this._updateHandler);\n\n this._awarenessUpdateHandler = (\n { added, updated, removed }: AwarenessUpdate,\n _origin: unknown\n ) => {\n const changedClients = added.concat(updated).concat(removed);\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(awareness, changedClients)\n );\n broadcastMessage(this, encoding.toUint8Array(encoder));\n };\n this._unloadHandler = () => {\n awarenessProtocol.removeAwarenessStates(\n this.awareness,\n [doc.clientID],\n \"window unload\"\n );\n };\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"unload\", this._unloadHandler);\n } else if (\n typeof process !== \"undefined\" &&\n typeof process.on === \"function\"\n ) {\n process.on(\"exit\", this._unloadHandler);\n }\n // Listen on 'change' (not 'update') so that clock-only awareness\n // renewals (the 15-second heartbeat) do NOT produce network traffic.\n // Only actual state changes (cursor moved, name changed, etc.) are sent.\n // This allows Durable Objects to hibernate when sessions are idle.\n awareness.on(\"change\", this._awarenessUpdateHandler);\n\n // Disable the awareness protocol's built-in check interval.\n // It renews the local clock every 15s (causing wire traffic that defeats\n // DO hibernation) and removes remote peers after 30s of inactivity.\n // We handle peer cleanup via WebSocket close events instead.\n clearInterval(\n (\n awareness as unknown as {\n _checkInterval: ReturnType<typeof setInterval>;\n }\n )._checkInterval\n );\n if (connect) {\n this.connect();\n }\n }\n\n /**\n * @type {boolean}\n */\n get synced() {\n return this._synced;\n }\n\n set synced(state) {\n if (this._synced !== state) {\n this._synced = state;\n this.emit(\"synced\", [state]);\n this.emit(\"sync\", [state]);\n }\n }\n\n destroy() {\n if (this._resyncInterval !== 0) {\n clearInterval(this._resyncInterval);\n }\n this.disconnect();\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"unload\", this._unloadHandler);\n } else if (\n typeof process !== \"undefined\" &&\n typeof process.off === \"function\"\n ) {\n process.off(\"exit\", this._unloadHandler);\n }\n this.awareness.off(\"change\", this._awarenessUpdateHandler);\n this.doc.off(\"update\", this._updateHandler);\n super.destroy();\n }\n\n connectBc() {\n if (this.disableBc) {\n return;\n }\n if (!this.bcconnected) {\n bc.subscribe(this.bcChannel, this._bcSubscriber);\n this.bcconnected = true;\n }\n // send sync step1 to bc\n // write sync step 1\n const encoderSync = encoding.createEncoder();\n encoding.writeVarUint(encoderSync, messageSync);\n syncProtocol.writeSyncStep1(encoderSync, this.doc);\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderSync), this);\n // broadcast local state\n const encoderState = encoding.createEncoder();\n encoding.writeVarUint(encoderState, messageSync);\n syncProtocol.writeSyncStep2(encoderState, this.doc);\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderState), this);\n // write queryAwareness\n const encoderAwarenessQuery = encoding.createEncoder();\n encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessQuery),\n this\n );\n // broadcast local awareness state\n const encoderAwarenessState = encoding.createEncoder();\n encoding.writeVarUint(encoderAwarenessState, messageAwareness);\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(this.awareness, [\n this.doc.clientID\n ])\n );\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessState),\n this\n );\n }\n\n disconnectBc() {\n // broadcast message with local awareness state set to null (indicating disconnect)\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n this.awareness,\n [this.doc.clientID],\n new Map()\n )\n );\n broadcastMessage(this, encoding.toUint8Array(encoder));\n if (this.bcconnected) {\n bc.unsubscribe(this.bcChannel, this._bcSubscriber);\n this.bcconnected = false;\n }\n }\n\n disconnect() {\n this.shouldConnect = false;\n this.disconnectBc();\n if (this.ws !== null) {\n this.ws.close();\n }\n }\n\n /**\n * Called by the close handler to re-establish the WebSocket.\n * Subclasses (e.g. YProvider) override this to refresh dynamic\n * params before reconnecting.\n */\n _reconnectWS() {\n setupWS(this);\n }\n\n connect() {\n this.shouldConnect = true;\n if (!this.wsconnected && this.ws === null) {\n setupWS(this);\n this.connectBc();\n }\n }\n}\n\nfunction assertType(value: unknown, label: string, type: string) {\n if (typeof value !== type) {\n throw new Error(\n `Invalid \"${label}\" parameter provided to YProvider. Expected: ${type}, received: ${value as string}`\n );\n }\n}\n\ntype Params = Record<string, string | null | undefined>;\ntype ParamsProvider = Params | (() => Params | Promise<Params>);\ntype BaseProviderOptions = ConstructorParameters<typeof WebsocketProvider>[3];\n\ntype YProviderOptions = Omit<NonNullable<BaseProviderOptions>, \"params\"> & {\n connectionId?: string;\n party?: string;\n prefix?: string;\n params?: ParamsProvider;\n protocol?: \"ws\" | \"wss\";\n};\n\nexport default class YProvider extends WebsocketProvider {\n id: string;\n #params?: ParamsProvider;\n\n constructor(\n host: string,\n room: string,\n doc?: YDoc,\n options: YProviderOptions = {}\n ) {\n assertType(host, \"host\", \"string\");\n assertType(room, \"room\", \"string\");\n\n // strip the protocol from the beginning of `host` if any\n host = host.replace(/^(http|https|ws|wss):\\/\\//, \"\");\n\n // strip trailing slash from host if any\n if (host.endsWith(\"/\")) {\n host = host.slice(0, -1);\n }\n\n const serverUrl = `${\n options.protocol ||\n (host.startsWith(\"localhost:\") ||\n host.startsWith(\"127.0.0.1:\") ||\n host.startsWith(\"192.168.\") ||\n host.startsWith(\"10.\") ||\n (host.startsWith(\"172.\") &&\n host.split(\".\")[1] >= \"16\" &&\n host.split(\".\")[1] <= \"31\")\n ? \"ws\"\n : \"wss\")\n }://${host}${options.prefix || `/parties/${options.party || \"main\"}`}`;\n\n // use provided id, or generate a random one\n const id = options.connectionId ?? nanoid(10);\n\n // don't pass params to WebsocketProvider, we override them in connect()\n const { params, connect = true, ...rest } = options;\n\n // don't connect until we've updated the url parameters\n const baseOptions = {\n ...rest,\n isPrefixedUrl: !!options.prefix,\n connect: false\n };\n\n super(serverUrl, room, doc ?? new YDoc(), baseOptions);\n\n this.id = id;\n this.#params = params;\n\n if (connect) {\n void this.connect();\n }\n }\n\n async #resolveParams() {\n const nextParams =\n typeof this.#params === \"function\" ? await this.#params() : this.#params;\n const urlParams = new URLSearchParams([[\"_pk\", this.id]]);\n if (nextParams) {\n for (const [key, value] of Object.entries(nextParams)) {\n if (value !== null && value !== undefined) {\n urlParams.append(key, value);\n }\n }\n }\n const nextUrl = new URL(this.url);\n nextUrl.search = urlParams.toString();\n this.url = nextUrl.toString();\n }\n\n async connect() {\n try {\n await this.#resolveParams();\n super.connect();\n } catch (err) {\n console.error(\"Failed to open connecton to PartyServer\", err);\n throw err;\n }\n }\n\n async _reconnectWS() {\n try {\n await this.#resolveParams();\n } catch (err) {\n console.error(\n \"Failed to refresh params, reconnecting with stale params\",\n err\n );\n }\n super._reconnectWS();\n }\n\n sendMessage(message: string) {\n this.ws?.send(`__YPS:${message}`);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["YDoc","#params","#resolveParams"],"sources":["../../src/provider/index.ts"],"sourcesContent":["import * as bc from \"lib0/broadcastchannel\";\nimport * as decoding from \"lib0/decoding\";\nimport * as encoding from \"lib0/encoding\";\nimport * as math from \"lib0/math\";\nimport { Observable } from \"lib0/observable\";\nimport * as time from \"lib0/time\";\nimport * as url from \"lib0/url\";\nimport { nanoid } from \"nanoid\";\nimport * as authProtocol from \"y-protocols/auth\";\nimport * as awarenessProtocol from \"y-protocols/awareness\";\nimport * as syncProtocol from \"y-protocols/sync\";\nimport { Doc as YDoc } from \"yjs\";\n\nexport const messageSync = 0;\nexport const messageQueryAwareness = 3;\nexport const messageAwareness = 1;\nexport const messageAuth = 2;\n\n// Disable BroadcastChannel by default in Cloudflare Workers / Node\nconst DEFAULT_DISABLE_BC = typeof window === \"undefined\";\n\nconst messageHandlers: Array<\n (\n encoder: encoding.Encoder,\n decoder: decoding.Decoder,\n provider: WebsocketProvider,\n emitSynced: boolean,\n messageType: number\n ) => void\n> = [];\n\nmessageHandlers[messageSync] = (\n encoder,\n decoder,\n provider,\n emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageSync);\n const syncMessageType = syncProtocol.readSyncMessage(\n decoder,\n encoder,\n provider.doc,\n provider\n );\n if (\n emitSynced &&\n syncMessageType === syncProtocol.messageYjsSyncStep2 &&\n !provider.synced\n ) {\n provider.synced = true;\n }\n};\n\nmessageHandlers[messageQueryAwareness] = (\n encoder,\n _decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n provider.awareness,\n Array.from(provider.awareness.getStates().keys())\n )\n );\n};\n\nmessageHandlers[messageAwareness] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n awarenessProtocol.applyAwarenessUpdate(\n provider.awareness,\n decoding.readVarUint8Array(decoder),\n provider\n );\n};\n\nmessageHandlers[messageAuth] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n authProtocol.readAuthMessage(decoder, provider.doc, (_ydoc, reason) =>\n permissionDeniedHandler(provider, reason)\n );\n};\n\nfunction permissionDeniedHandler(provider: WebsocketProvider, reason: string) {\n console.warn(`Permission denied to access ${provider.url}.\\n${reason}`);\n}\n\nfunction readMessage(\n provider: WebsocketProvider,\n buf: Uint8Array,\n emitSynced: boolean\n): encoding.Encoder {\n const decoder = decoding.createDecoder(buf);\n const encoder = encoding.createEncoder();\n const messageType = decoding.readVarUint(decoder);\n const messageHandler = provider.messageHandlers[messageType];\n if (/** @type {any} */ messageHandler) {\n messageHandler(encoder, decoder, provider, emitSynced, messageType);\n } else {\n console.error(\"Unable to compute message\");\n }\n return encoder;\n}\n\nfunction setupWS(provider: WebsocketProvider) {\n if (provider.shouldConnect && provider.ws === null) {\n if (!provider._WS) {\n throw new Error(\n \"No WebSocket implementation available, did you forget to pass options.WebSocketPolyfill?\"\n );\n }\n const websocket = new provider._WS(provider.url);\n websocket.binaryType = \"arraybuffer\";\n provider.ws = websocket;\n provider.wsconnecting = true;\n provider.wsconnected = false;\n provider.synced = false;\n\n websocket.addEventListener(\"message\", (event) => {\n if (typeof event.data === \"string\") {\n // Handle custom messages with __YPS: prefix\n if (event.data.startsWith(\"__YPS:\")) {\n const customMessage = event.data.slice(6); // Remove __YPS: prefix\n provider.emit(\"custom-message\", [customMessage]);\n }\n return;\n }\n provider.wsLastMessageReceived = time.getUnixTime();\n const encoder = readMessage(provider, new Uint8Array(event.data), true);\n if (encoding.length(encoder) > 1) {\n websocket.send(encoding.toUint8Array(encoder));\n }\n });\n websocket.addEventListener(\"error\", (event) => {\n provider.emit(\"connection-error\", [event, provider]);\n });\n websocket.addEventListener(\"close\", (event) => {\n provider.emit(\"connection-close\", [event, provider]);\n provider.ws = null;\n provider.wsconnecting = false;\n if (provider.wsconnected) {\n provider.wsconnected = false;\n provider.synced = false;\n // update awareness (all users except local left)\n const removedClients = Array.from(\n provider.awareness.getStates().keys()\n ).filter((client) => client !== provider.doc.clientID);\n awarenessProtocol.removeAwarenessStates(\n provider.awareness,\n removedClients,\n provider\n );\n // Clear stale meta for remote clients so their awareness\n // updates are accepted on reconnect (clock check starts fresh)\n for (const clientID of removedClients) {\n provider.awareness.meta.delete(clientID);\n }\n provider.emit(\"status\", [\n {\n status: \"disconnected\"\n }\n ]);\n } else {\n provider.wsUnsuccessfulReconnects++;\n }\n // Start with no reconnect timeout and increase timeout by\n // using exponential backoff starting with 100ms\n setTimeout(\n () => {\n if (provider.shouldConnect) {\n Promise.resolve(provider._reconnectWS()).catch((err) => {\n console.error(\"Reconnection failed\", err);\n });\n }\n },\n math.min(\n math.pow(2, provider.wsUnsuccessfulReconnects) * 100,\n provider.maxBackoffTime\n )\n );\n });\n websocket.addEventListener(\"open\", () => {\n provider.wsLastMessageReceived = time.getUnixTime();\n provider.wsconnecting = false;\n provider.wsconnected = true;\n provider.wsUnsuccessfulReconnects = 0;\n provider.emit(\"status\", [\n {\n status: \"connected\"\n }\n ]);\n // always send sync step 1 when connected\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, provider.doc);\n websocket.send(encoding.toUint8Array(encoder));\n // broadcast local awareness state\n if (provider.awareness.getLocalState() !== null) {\n // Re-set local state to bump the awareness clock, ensuring\n // remote clients accept the update even if they have stale meta\n provider.awareness.setLocalState(provider.awareness.getLocalState());\n const encoderAwarenessState = encoding.createEncoder();\n encoding.writeVarUint(encoderAwarenessState, messageAwareness);\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(provider.awareness, [\n provider.doc.clientID\n ])\n );\n websocket.send(encoding.toUint8Array(encoderAwarenessState));\n }\n });\n provider.emit(\"status\", [\n {\n status: \"connecting\"\n }\n ]);\n }\n}\n\nfunction broadcastMessage(provider: WebsocketProvider, buf: Uint8Array) {\n const ws = provider.ws;\n if (provider.wsconnected && ws && ws.readyState === ws.OPEN) {\n ws.send(buf);\n }\n if (provider.bcconnected) {\n bc.publish(provider.bcChannel, buf, provider);\n }\n}\n\ntype AwarenessUpdate = {\n added: number[];\n updated: number[];\n removed: number[];\n};\n\nconst DefaultWebSocket = typeof WebSocket === \"undefined\" ? null : WebSocket;\n\n/**\n * Websocket Provider for Yjs. Creates a websocket connection to sync the shared document.\n * The document name is attached to the provided url. I.e. the following example\n * creates a websocket connection to http://localhost:1234/my-document-name\n *\n * @example\n * import * as Y from 'yjs'\n * import { WebsocketProvider } from 'y-websocket'\n * const doc = new Y.Doc()\n * const provider = new WebsocketProvider('http://localhost:1234', 'my-document-name', doc)\n *\n * @extends {Observable<string>}\n */\nexport class WebsocketProvider extends Observable<string> {\n maxBackoffTime: number;\n bcChannel: string;\n url: string;\n roomname: string;\n doc: YDoc;\n _WS: typeof WebSocket;\n awareness: awarenessProtocol.Awareness;\n wsconnected: boolean;\n wsconnecting: boolean;\n bcconnected: boolean;\n disableBc: boolean;\n wsUnsuccessfulReconnects: number;\n messageHandlers: typeof messageHandlers;\n _synced: boolean;\n ws: WebSocket | null;\n wsLastMessageReceived: number;\n shouldConnect: boolean; // Whether to connect to other peers or not\n _resyncInterval: ReturnType<typeof setInterval> | number;\n _bcSubscriber: (message: Uint8Array, origin: unknown) => void;\n _updateHandler: (update: Uint8Array, origin: unknown) => void;\n _awarenessUpdateHandler: (update: AwarenessUpdate, origin: unknown) => void;\n _unloadHandler: () => void;\n\n constructor(\n serverUrl: string,\n roomname: string,\n doc: YDoc,\n {\n connect = true,\n awareness = new awarenessProtocol.Awareness(doc),\n params = {},\n isPrefixedUrl = false,\n WebSocketPolyfill = DefaultWebSocket, // Optionally provide a WebSocket polyfill\n resyncInterval = -1, // Request server state every `resyncInterval` milliseconds\n maxBackoffTime = 2500, // Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)\n disableBc = DEFAULT_DISABLE_BC // Disable cross-tab BroadcastChannel communication\n }: {\n connect?: boolean;\n awareness?: awarenessProtocol.Awareness;\n params?: { [s: string]: string };\n isPrefixedUrl?: boolean;\n WebSocketPolyfill?: typeof WebSocket | null;\n resyncInterval?: number;\n maxBackoffTime?: number;\n disableBc?: boolean;\n } = {}\n ) {\n super();\n // ensure that url is always ends with /\n while (serverUrl[serverUrl.length - 1] === \"/\") {\n serverUrl = serverUrl.slice(0, serverUrl.length - 1);\n }\n const encodedParams = url.encodeQueryParams(params);\n this.maxBackoffTime = maxBackoffTime;\n this.bcChannel = `${serverUrl}/${roomname}`;\n this.url = isPrefixedUrl\n ? serverUrl\n : `${serverUrl}/${roomname}${encodedParams.length === 0 ? \"\" : `?${encodedParams}`}`;\n this.roomname = roomname;\n this.doc = doc;\n this._WS = WebSocketPolyfill!;\n this.awareness = awareness;\n this.wsconnected = false;\n this.wsconnecting = false;\n this.bcconnected = false;\n this.disableBc = disableBc;\n this.wsUnsuccessfulReconnects = 0;\n this.messageHandlers = messageHandlers.slice();\n\n this._synced = false;\n\n this.ws = null;\n this.wsLastMessageReceived = 0;\n\n this.shouldConnect = connect;\n\n this._resyncInterval = 0;\n if (resyncInterval > 0) {\n this._resyncInterval = /** @type {any} */ setInterval(() => {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n // resend sync step 1\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, doc);\n this.ws.send(encoding.toUint8Array(encoder));\n }\n }, resyncInterval);\n }\n\n this._bcSubscriber = (data: Uint8Array, origin: unknown) => {\n if (origin !== this) {\n const encoder = readMessage(this, new Uint8Array(data), false);\n if (encoding.length(encoder) > 1) {\n bc.publish(this.bcChannel, encoding.toUint8Array(encoder), this);\n }\n }\n };\n /**\n * Listens to Yjs updates and sends them to remote peers (ws and broadcastchannel)\n */\n this._updateHandler = (update: Uint8Array, origin: unknown) => {\n if (origin !== this) {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeUpdate(encoder, update);\n broadcastMessage(this, encoding.toUint8Array(encoder));\n }\n };\n this.doc.on(\"update\", this._updateHandler);\n\n this._awarenessUpdateHandler = (\n { added, updated, removed }: AwarenessUpdate,\n _origin: unknown\n ) => {\n const changedClients = added.concat(updated).concat(removed);\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(awareness, changedClients)\n );\n broadcastMessage(this, encoding.toUint8Array(encoder));\n };\n this._unloadHandler = () => {\n awarenessProtocol.removeAwarenessStates(\n this.awareness,\n [doc.clientID],\n \"window unload\"\n );\n };\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"unload\", this._unloadHandler);\n } else if (\n typeof process !== \"undefined\" &&\n typeof process.on === \"function\"\n ) {\n process.on(\"exit\", this._unloadHandler);\n }\n // Listen on 'change' (not 'update') so that clock-only awareness\n // renewals (the 15-second heartbeat) do NOT produce network traffic.\n // Only actual state changes (cursor moved, name changed, etc.) are sent.\n // This allows Durable Objects to hibernate when sessions are idle.\n awareness.on(\"change\", this._awarenessUpdateHandler);\n\n // Disable the awareness protocol's built-in check interval.\n // It renews the local clock every 15s (causing wire traffic that defeats\n // DO hibernation) and removes remote peers after 30s of inactivity.\n // We handle peer cleanup via WebSocket close events instead.\n clearInterval(\n (\n awareness as unknown as {\n _checkInterval: ReturnType<typeof setInterval>;\n }\n )._checkInterval\n );\n if (connect) {\n this.connect();\n }\n }\n\n /**\n * @type {boolean}\n */\n get synced() {\n return this._synced;\n }\n\n set synced(state) {\n if (this._synced !== state) {\n this._synced = state;\n this.emit(\"synced\", [state]);\n this.emit(\"sync\", [state]);\n }\n }\n\n destroy() {\n if (this._resyncInterval !== 0) {\n clearInterval(this._resyncInterval);\n }\n this.disconnect();\n if (typeof window !== \"undefined\") {\n window.removeEventListener(\"unload\", this._unloadHandler);\n } else if (\n typeof process !== \"undefined\" &&\n typeof process.off === \"function\"\n ) {\n process.off(\"exit\", this._unloadHandler);\n }\n this.awareness.off(\"change\", this._awarenessUpdateHandler);\n this.doc.off(\"update\", this._updateHandler);\n super.destroy();\n }\n\n connectBc() {\n if (this.disableBc) {\n return;\n }\n if (!this.bcconnected) {\n bc.subscribe(this.bcChannel, this._bcSubscriber);\n this.bcconnected = true;\n }\n // send sync step1 to bc\n // write sync step 1\n const encoderSync = encoding.createEncoder();\n encoding.writeVarUint(encoderSync, messageSync);\n syncProtocol.writeSyncStep1(encoderSync, this.doc);\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderSync), this);\n // broadcast local state\n const encoderState = encoding.createEncoder();\n encoding.writeVarUint(encoderState, messageSync);\n syncProtocol.writeSyncStep2(encoderState, this.doc);\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderState), this);\n // write queryAwareness\n const encoderAwarenessQuery = encoding.createEncoder();\n encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessQuery),\n this\n );\n // broadcast local awareness state\n const encoderAwarenessState = encoding.createEncoder();\n encoding.writeVarUint(encoderAwarenessState, messageAwareness);\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(this.awareness, [\n this.doc.clientID\n ])\n );\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessState),\n this\n );\n }\n\n disconnectBc() {\n // broadcast message with local awareness state set to null (indicating disconnect)\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n this.awareness,\n [this.doc.clientID],\n new Map()\n )\n );\n broadcastMessage(this, encoding.toUint8Array(encoder));\n if (this.bcconnected) {\n bc.unsubscribe(this.bcChannel, this._bcSubscriber);\n this.bcconnected = false;\n }\n }\n\n disconnect() {\n this.shouldConnect = false;\n this.disconnectBc();\n if (this.ws !== null) {\n this.ws.close();\n }\n }\n\n /**\n * Called by the close handler to re-establish the WebSocket.\n * Subclasses (e.g. YProvider) override this to refresh dynamic\n * params before reconnecting.\n */\n _reconnectWS() {\n setupWS(this);\n }\n\n connect() {\n this.shouldConnect = true;\n if (!this.wsconnected && this.ws === null) {\n setupWS(this);\n this.connectBc();\n }\n }\n}\n\nfunction assertType(value: unknown, label: string, type: string) {\n if (typeof value !== type) {\n throw new Error(\n `Invalid \"${label}\" parameter provided to YProvider. Expected: ${type}, received: ${value as string}`\n );\n }\n}\n\ntype Params = Record<string, string | null | undefined>;\ntype ParamsProvider = Params | (() => Params | Promise<Params>);\ntype BaseProviderOptions = ConstructorParameters<typeof WebsocketProvider>[3];\n\ntype YProviderOptions = Omit<NonNullable<BaseProviderOptions>, \"params\"> & {\n connectionId?: string;\n party?: string;\n prefix?: string;\n params?: ParamsProvider;\n protocol?: \"ws\" | \"wss\";\n};\n\nexport default class YProvider extends WebsocketProvider {\n id: string;\n #params?: ParamsProvider;\n\n constructor(\n host: string,\n room: string,\n doc?: YDoc,\n options: YProviderOptions = {}\n ) {\n assertType(host, \"host\", \"string\");\n assertType(room, \"room\", \"string\");\n\n // strip the protocol from the beginning of `host` if any\n host = host.replace(/^(http|https|ws|wss):\\/\\//, \"\");\n\n // strip trailing slash from host if any\n if (host.endsWith(\"/\")) {\n host = host.slice(0, -1);\n }\n\n const serverUrl = `${\n options.protocol ||\n (host.startsWith(\"localhost:\") ||\n host.startsWith(\"127.0.0.1:\") ||\n host.startsWith(\"192.168.\") ||\n host.startsWith(\"10.\") ||\n (host.startsWith(\"172.\") &&\n host.split(\".\")[1] >= \"16\" &&\n host.split(\".\")[1] <= \"31\")\n ? \"ws\"\n : \"wss\")\n }://${host}${options.prefix || `/parties/${options.party || \"main\"}`}`;\n\n // use provided id, or generate a random one\n const id = options.connectionId ?? nanoid(10);\n\n // don't pass params to WebsocketProvider, we override them in connect()\n const { params, connect = true, ...rest } = options;\n\n // don't connect until we've updated the url parameters\n const baseOptions = {\n ...rest,\n isPrefixedUrl: !!options.prefix,\n connect: false\n };\n\n super(serverUrl, room, doc ?? new YDoc(), baseOptions);\n\n this.id = id;\n this.#params = params;\n\n if (connect) {\n void this.connect();\n }\n }\n\n async #resolveParams() {\n const nextParams =\n typeof this.#params === \"function\" ? await this.#params() : this.#params;\n const urlParams = new URLSearchParams([[\"_pk\", this.id]]);\n if (nextParams) {\n for (const [key, value] of Object.entries(nextParams)) {\n if (value !== null && value !== undefined) {\n urlParams.append(key, value);\n }\n }\n }\n const nextUrl = new URL(this.url);\n nextUrl.search = urlParams.toString();\n this.url = nextUrl.toString();\n }\n\n async connect() {\n try {\n await this.#resolveParams();\n super.connect();\n } catch (err) {\n console.error(\"Failed to open connecton to PartyServer\", err);\n throw err;\n }\n }\n\n async _reconnectWS() {\n try {\n await this.#resolveParams();\n } catch (err) {\n console.error(\n \"Failed to refresh params, reconnecting with stale params\",\n err\n );\n }\n super._reconnectWS();\n }\n\n sendMessage(message: string) {\n this.ws?.send(`__YPS:${message}`);\n }\n}\n"],"mappings":"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"}
|
package/dist/provider/react.cjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
require("../chunk-CKQMccvm.cjs");
|
|
2
2
|
const require_provider_index = require("./index.cjs");
|
|
3
3
|
let react = require("react");
|
|
4
|
-
|
|
5
4
|
//#region src/provider/react.tsx
|
|
6
5
|
function useYProvider(yProviderOptions) {
|
|
7
6
|
const { host, room, party, doc, options, prefix } = yProviderOptions;
|
|
@@ -28,7 +27,7 @@ function useYProvider(yProviderOptions) {
|
|
|
28
27
|
}, [provider]);
|
|
29
28
|
return provider;
|
|
30
29
|
}
|
|
31
|
-
|
|
32
30
|
//#endregion
|
|
33
31
|
module.exports = useYProvider;
|
|
32
|
+
|
|
34
33
|
//# sourceMappingURL=react.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.cjs","names":["YProvider"],"sources":["../../src/provider/react.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nimport YProvider from \"./index\";\n\nimport type * as Y from \"yjs\";\n\ntype UseYProviderOptions = {\n host?: string | undefined;\n room: string;\n party?: string;\n doc?: Y.Doc;\n prefix?: string;\n options?: ConstructorParameters<typeof YProvider>[3];\n};\n\nexport default function useYProvider(yProviderOptions: UseYProviderOptions) {\n const { host, room, party, doc, options, prefix } = yProviderOptions;\n const [provider] = useState<YProvider>(\n () =>\n new YProvider(\n host ||\n (typeof window !== \"undefined\"\n ? window.location.host\n : \"dummy-domain.com\"),\n room,\n doc,\n {\n connect: false,\n party,\n prefix,\n ...options\n }\n )\n );\n\n useEffect(() => {\n void provider.connect();\n return () => provider.disconnect();\n }, [provider]);\n return provider;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"react.cjs","names":["YProvider"],"sources":["../../src/provider/react.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nimport YProvider from \"./index\";\n\nimport type * as Y from \"yjs\";\n\ntype UseYProviderOptions = {\n host?: string | undefined;\n room: string;\n party?: string;\n doc?: Y.Doc;\n prefix?: string;\n options?: ConstructorParameters<typeof YProvider>[3];\n};\n\nexport default function useYProvider(yProviderOptions: UseYProviderOptions) {\n const { host, room, party, doc, options, prefix } = yProviderOptions;\n const [provider] = useState<YProvider>(\n () =>\n new YProvider(\n host ||\n (typeof window !== \"undefined\"\n ? window.location.host\n : \"dummy-domain.com\"),\n room,\n doc,\n {\n connect: false,\n party,\n prefix,\n ...options\n }\n )\n );\n\n useEffect(() => {\n void provider.connect();\n return () => provider.disconnect();\n }, [provider]);\n return provider;\n}\n"],"mappings":";;;;AAeA,SAAwB,aAAa,kBAAuC;CAC1E,MAAM,EAAE,MAAM,MAAM,OAAO,KAAK,SAAS,WAAW;CACpD,MAAM,CAAC,aAAA,GAAA,MAAA,gBAEH,IAAIA,uBAAAA,QACF,SACG,OAAO,WAAW,cACf,OAAO,SAAS,OAChB,qBACN,MACA,KACA;EACE,SAAS;EACT;EACA;EACA,GAAG;EACJ,CACF,CACJ;AAED,EAAA,GAAA,MAAA,iBAAgB;AACT,WAAS,SAAS;AACvB,eAAa,SAAS,YAAY;IACjC,CAAC,SAAS,CAAC;AACd,QAAO"}
|
package/dist/provider/react.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import YProvider from "./index.js";
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
|
-
|
|
4
3
|
//#region src/provider/react.tsx
|
|
5
4
|
function useYProvider(yProviderOptions) {
|
|
6
5
|
const { host, room, party, doc, options, prefix } = yProviderOptions;
|
|
@@ -27,7 +26,7 @@ function useYProvider(yProviderOptions) {
|
|
|
27
26
|
}, [provider]);
|
|
28
27
|
return provider;
|
|
29
28
|
}
|
|
30
|
-
|
|
31
29
|
//#endregion
|
|
32
30
|
export { useYProvider as default };
|
|
31
|
+
|
|
33
32
|
//# sourceMappingURL=react.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","names":[],"sources":["../../src/provider/react.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nimport YProvider from \"./index\";\n\nimport type * as Y from \"yjs\";\n\ntype UseYProviderOptions = {\n host?: string | undefined;\n room: string;\n party?: string;\n doc?: Y.Doc;\n prefix?: string;\n options?: ConstructorParameters<typeof YProvider>[3];\n};\n\nexport default function useYProvider(yProviderOptions: UseYProviderOptions) {\n const { host, room, party, doc, options, prefix } = yProviderOptions;\n const [provider] = useState<YProvider>(\n () =>\n new YProvider(\n host ||\n (typeof window !== \"undefined\"\n ? window.location.host\n : \"dummy-domain.com\"),\n room,\n doc,\n {\n connect: false,\n party,\n prefix,\n ...options\n }\n )\n );\n\n useEffect(() => {\n void provider.connect();\n return () => provider.disconnect();\n }, [provider]);\n return provider;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"react.js","names":[],"sources":["../../src/provider/react.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nimport YProvider from \"./index\";\n\nimport type * as Y from \"yjs\";\n\ntype UseYProviderOptions = {\n host?: string | undefined;\n room: string;\n party?: string;\n doc?: Y.Doc;\n prefix?: string;\n options?: ConstructorParameters<typeof YProvider>[3];\n};\n\nexport default function useYProvider(yProviderOptions: UseYProviderOptions) {\n const { host, room, party, doc, options, prefix } = yProviderOptions;\n const [provider] = useState<YProvider>(\n () =>\n new YProvider(\n host ||\n (typeof window !== \"undefined\"\n ? window.location.host\n : \"dummy-domain.com\"),\n room,\n doc,\n {\n connect: false,\n party,\n prefix,\n ...options\n }\n )\n );\n\n useEffect(() => {\n void provider.connect();\n return () => provider.disconnect();\n }, [provider]);\n return provider;\n}\n"],"mappings":";;;AAeA,SAAwB,aAAa,kBAAuC;CAC1E,MAAM,EAAE,MAAM,MAAM,OAAO,KAAK,SAAS,WAAW;CACpD,MAAM,CAAC,YAAY,eAEf,IAAI,UACF,SACG,OAAO,WAAW,cACf,OAAO,SAAS,OAChB,qBACN,MACA,KACA;EACE,SAAS;EACT;EACA;EACA,GAAG;EACJ,CACF,CACJ;AAED,iBAAgB;AACT,WAAS,SAAS;AACvB,eAAa,SAAS,YAAY;IACjC,CAAC,SAAS,CAAC;AACd,QAAO"}
|
package/dist/server/index.cjs
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_chunk = require("../chunk-
|
|
2
|
+
const require_chunk = require("../chunk-CKQMccvm.cjs");
|
|
3
3
|
let lib0_decoding = require("lib0/decoding");
|
|
4
|
-
lib0_decoding = require_chunk.__toESM(lib0_decoding);
|
|
4
|
+
lib0_decoding = require_chunk.__toESM(lib0_decoding, 1);
|
|
5
5
|
let lib0_encoding = require("lib0/encoding");
|
|
6
|
-
lib0_encoding = require_chunk.__toESM(lib0_encoding);
|
|
6
|
+
lib0_encoding = require_chunk.__toESM(lib0_encoding, 1);
|
|
7
7
|
let lodash_debounce = require("lodash.debounce");
|
|
8
|
-
lodash_debounce = require_chunk.__toESM(lodash_debounce);
|
|
8
|
+
lodash_debounce = require_chunk.__toESM(lodash_debounce, 1);
|
|
9
9
|
let partyserver = require("partyserver");
|
|
10
10
|
let y_protocols_awareness = require("y-protocols/awareness");
|
|
11
|
-
y_protocols_awareness = require_chunk.__toESM(y_protocols_awareness);
|
|
11
|
+
y_protocols_awareness = require_chunk.__toESM(y_protocols_awareness, 1);
|
|
12
12
|
let y_protocols_sync = require("y-protocols/sync");
|
|
13
|
-
y_protocols_sync = require_chunk.__toESM(y_protocols_sync);
|
|
13
|
+
y_protocols_sync = require_chunk.__toESM(y_protocols_sync, 1);
|
|
14
14
|
let yjs = require("yjs");
|
|
15
|
-
|
|
16
15
|
//#region src/server/index.ts
|
|
17
16
|
const snapshotOrigin = Symbol("snapshot-origin");
|
|
18
17
|
const wsReadyStateConnecting = 0;
|
|
@@ -359,8 +358,8 @@ function withYjs(Base) {
|
|
|
359
358
|
return YjsMixin;
|
|
360
359
|
}
|
|
361
360
|
const YServer = withYjs(partyserver.Server);
|
|
362
|
-
|
|
363
361
|
//#endregion
|
|
364
362
|
exports.YServer = YServer;
|
|
365
363
|
exports.withYjs = withYjs;
|
|
364
|
+
|
|
366
365
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["YDoc","awarenessProtocol","decoding","syncProtocol","UndoManager","XmlText","XmlElement","XmlFragment","encoding","Server"],"sources":["../../src/server/index.ts"],"sourcesContent":["import * as decoding from \"lib0/decoding\";\nimport * as encoding from \"lib0/encoding\";\nimport debounce from \"lodash.debounce\";\nimport type { Connection, ConnectionContext, WSMessage } from \"partyserver\";\nimport { Server } from \"partyserver\";\nimport * as awarenessProtocol from \"y-protocols/awareness\";\nimport * as syncProtocol from \"y-protocols/sync\";\nimport {\n applyUpdate,\n Doc as YDoc,\n encodeStateAsUpdate,\n encodeStateVector,\n UndoManager,\n XmlText,\n XmlElement,\n XmlFragment\n} from \"yjs\";\n\nconst snapshotOrigin = Symbol(\"snapshot-origin\");\ntype YjsRootType =\n | \"Text\"\n | \"Map\"\n | \"Array\"\n | \"XmlText\"\n | \"XmlElement\"\n | \"XmlFragment\";\n\nconst wsReadyStateConnecting = 0;\nconst wsReadyStateOpen = 1;\n// oxlint-disable-next-line no-unused-vars\nconst wsReadyStateClosing = 2;\n// oxlint-disable-next-line no-unused-vars\nconst wsReadyStateClosed = 3;\n\nconst messageSync = 0;\nconst messageAwareness = 1;\n// oxlint-disable-next-line no-unused-vars\nconst messageAuth = 2;\n\n/**\n * Internal key used in connection.setState() to track which awareness\n * client IDs are controlled by each connection. This survives hibernation\n * because connection state is persisted to WebSocket attachments.\n */\nconst AWARENESS_IDS_KEY = \"__ypsAwarenessIds\";\n\ntype YServerConnectionState = {\n [AWARENESS_IDS_KEY]?: number[];\n [key: string]: unknown;\n};\n\nfunction getAwarenessIds(conn: Connection): number[] {\n try {\n const state = conn.state as YServerConnectionState | null;\n return state?.[AWARENESS_IDS_KEY] ?? [];\n } catch {\n return [];\n }\n}\n\nfunction setAwarenessIds(conn: Connection, ids: number[]): void {\n try {\n conn.setState((prev: YServerConnectionState | null) => ({\n ...prev,\n [AWARENESS_IDS_KEY]: ids\n }));\n } catch {\n // ignore — may fail if connection is already closed\n }\n}\n\nclass WSSharedDoc extends YDoc {\n awareness: awarenessProtocol.Awareness;\n\n constructor() {\n super({ gc: true });\n this.awareness = new awarenessProtocol.Awareness(this);\n this.awareness.setLocalState(null);\n\n // Disable the awareness protocol's built-in check interval.\n // It renews the local clock every 15s and removes peers after 30s,\n // but we handle peer cleanup via onClose instead. Clearing it here\n // prevents it from defeating Durable Object hibernation.\n clearInterval(\n (\n this.awareness as unknown as {\n _checkInterval: ReturnType<typeof setInterval>;\n }\n )._checkInterval\n );\n }\n}\n\nconst CALLBACK_DEFAULTS = {\n debounceWait: 2000,\n debounceMaxWait: 10000,\n timeout: 5000\n};\n\nfunction readSyncMessage(\n decoder: decoding.Decoder,\n encoder: encoding.Encoder,\n doc: YDoc,\n transactionOrigin: Connection,\n readOnly = false\n) {\n const messageType = decoding.readVarUint(decoder);\n switch (messageType) {\n case syncProtocol.messageYjsSyncStep1:\n syncProtocol.readSyncStep1(decoder, encoder, doc);\n break;\n case syncProtocol.messageYjsSyncStep2:\n if (!readOnly)\n syncProtocol.readSyncStep2(decoder, doc, transactionOrigin);\n break;\n case syncProtocol.messageYjsUpdate:\n if (!readOnly) syncProtocol.readUpdate(decoder, doc, transactionOrigin);\n break;\n default:\n throw new Error(\"Unknown message type\");\n }\n return messageType;\n}\n\nfunction send(conn: Connection, m: Uint8Array): void {\n if (\n conn.readyState !== undefined &&\n conn.readyState !== wsReadyStateConnecting &&\n conn.readyState !== wsReadyStateOpen\n ) {\n return;\n }\n try {\n conn.send(m);\n } catch {\n // connection is broken, ignore\n }\n}\n\nexport interface CallbackOptions {\n debounceWait?: number;\n debounceMaxWait?: number;\n timeout?: number;\n}\n\ntype ServerClass = new (...args: any[]) => Server;\n\nexport interface YjsInstance {\n readonly document: WSSharedDoc;\n onLoad(): Promise<YDoc | void>;\n onSave(): Promise<void>;\n unstable_replaceDocument(\n snapshotUpdate: Uint8Array,\n getMetadata?: (key: string) => YjsRootType\n ): void;\n isReadOnly(connection: Connection): boolean;\n onCustomMessage(connection: Connection, message: string): void;\n sendCustomMessage(connection: Connection, message: string): void;\n broadcastCustomMessage(message: string, excludeConnection?: Connection): void;\n handleMessage(connection: Connection, message: WSMessage): void;\n}\n\nexport interface YjsStatic {\n callbackOptions: CallbackOptions;\n}\n\nexport function withYjs<TBase extends ServerClass>(\n Base: TBase\n): TBase & YjsStatic & (new (...args: any[]) => YjsInstance) {\n class YjsMixin extends Base {\n static callbackOptions: CallbackOptions = {};\n\n readonly document: WSSharedDoc = new WSSharedDoc();\n\n async onLoad(): Promise<YDoc | void> {\n // to be implemented by the user\n return;\n }\n\n async onSave(): Promise<void> {\n // to be implemented by the user\n }\n\n /**\n * Replaces the document with a different state using Yjs UndoManager key remapping.\n *\n * @param snapshotUpdate - The snapshot update to replace the document with.\n * @param getMetadata (optional) - A function that returns the type of the root for a given key.\n */\n unstable_replaceDocument(\n snapshotUpdate: Uint8Array,\n getMetadata: (key: string) => YjsRootType = () => \"Map\"\n ): void {\n try {\n const doc = this.document;\n const snapshotDoc = new YDoc();\n applyUpdate(snapshotDoc, snapshotUpdate, snapshotOrigin);\n\n const currentStateVector = encodeStateVector(doc);\n const snapshotStateVector = encodeStateVector(snapshotDoc);\n\n const changesSinceSnapshotUpdate = encodeStateAsUpdate(\n doc,\n snapshotStateVector\n );\n\n const undoManager = new UndoManager(\n [...snapshotDoc.share.keys()].map((key) => {\n const type = getMetadata(key);\n if (type === \"Text\") {\n return snapshotDoc.getText(key);\n } else if (type === \"Map\") {\n return snapshotDoc.getMap(key);\n } else if (type === \"Array\") {\n return snapshotDoc.getArray(key);\n } else if (type === \"XmlText\") {\n return snapshotDoc.get(key, XmlText);\n } else if (type === \"XmlElement\") {\n return snapshotDoc.get(key, XmlElement);\n } else if (type === \"XmlFragment\") {\n return snapshotDoc.get(key, XmlFragment);\n }\n throw new Error(`Unknown root type: ${type} for key: ${key}`);\n }),\n {\n trackedOrigins: new Set([snapshotOrigin])\n }\n );\n\n applyUpdate(snapshotDoc, changesSinceSnapshotUpdate, snapshotOrigin);\n undoManager.undo();\n\n const documentChangesSinceSnapshotUpdate = encodeStateAsUpdate(\n snapshotDoc,\n currentStateVector\n );\n\n applyUpdate(this.document, documentChangesSinceSnapshotUpdate);\n } catch (error) {\n throw new Error(\n `Failed to replace document: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n }\n }\n\n async onStart(): Promise<void> {\n const src = await this.onLoad();\n if (src != null) {\n const state = encodeStateAsUpdate(src);\n applyUpdate(this.document, state);\n }\n\n // Broadcast doc updates to all connections.\n // Uses this.getConnections() which works for both hibernate and non-hibernate\n // modes and survives DO hibernation (unlike an in-memory Map).\n this.document.on(\"update\", (update: Uint8Array) => {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeUpdate(encoder, update);\n const message = encoding.toUint8Array(encoder);\n for (const conn of this.getConnections()) {\n send(conn, message);\n }\n });\n\n // Track which awareness clientIDs each connection controls.\n // Stored in connection.setState() so it survives hibernation.\n // When conn is null (internal changes like removeAwarenessStates on close),\n // broadcast the update to remaining connections.\n // When conn is non-null (client message), handleMessage broadcasts directly.\n this.document.awareness.on(\n \"update\",\n (\n {\n added,\n updated,\n removed\n }: {\n added: Array<number>;\n updated: Array<number>;\n removed: Array<number>;\n },\n conn: Connection | null\n ) => {\n if (conn !== null) {\n // Track which clientIDs this connection controls\n try {\n const currentIds = new Set(getAwarenessIds(conn));\n for (const clientID of added) currentIds.add(clientID);\n for (const clientID of removed) currentIds.delete(clientID);\n setAwarenessIds(conn, [...currentIds]);\n } catch (_e) {\n // ignore — best-effort tracking\n }\n } else {\n // Internal awareness change (e.g. removeAwarenessStates on close)\n // — broadcast to all remaining connections\n const changedClients = added.concat(updated, removed);\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n this.document.awareness,\n changedClients\n )\n );\n const buff = encoding.toUint8Array(encoder);\n for (const c of this.getConnections()) {\n send(c, buff);\n }\n }\n }\n );\n\n // Debounced persistence handler\n const ctor = this.constructor as typeof YjsMixin;\n this.document.on(\n \"update\",\n debounce(\n (_update: Uint8Array, _origin: Connection, _doc: YDoc) => {\n try {\n this.onSave().catch((err) => {\n console.error(\"failed to persist:\", err);\n });\n } catch (err) {\n console.error(\"failed to persist:\", err);\n }\n },\n ctor.callbackOptions.debounceWait || CALLBACK_DEFAULTS.debounceWait,\n {\n maxWait:\n ctor.callbackOptions.debounceMaxWait ||\n CALLBACK_DEFAULTS.debounceMaxWait\n }\n )\n );\n\n // After hibernation wake-up, the doc is empty but existing connections\n // survive. Re-sync by sending sync step 1 to all connections — they'll\n // respond with sync step 2 containing their full state.\n // On first start there are no connections, so this is a no-op.\n const syncEncoder = encoding.createEncoder();\n encoding.writeVarUint(syncEncoder, messageSync);\n syncProtocol.writeSyncStep1(syncEncoder, this.document);\n const syncMessage = encoding.toUint8Array(syncEncoder);\n for (const conn of this.getConnections()) {\n send(conn, syncMessage);\n }\n }\n\n // oxlint-disable-next-line no-unused-vars\n isReadOnly(connection: Connection): boolean {\n // to be implemented by the user\n return false;\n }\n\n /**\n * Handle custom string messages from the client.\n * Override this method to implement custom message handling.\n * @param connection - The connection that sent the message\n * @param message - The custom message string (without the __YPS: prefix)\n */\n // oxlint-disable-next-line no-unused-vars\n onCustomMessage(connection: Connection, message: string): void {\n // to be implemented by the user\n console.warn(\n `Received custom message but onCustomMessage is not implemented in ${this.constructor.name}:`,\n message\n );\n }\n\n /**\n * Send a custom string message to a specific connection.\n * @param connection - The connection to send the message to\n * @param message - The custom message string to send\n */\n sendCustomMessage(connection: Connection, message: string): void {\n if (\n connection.readyState !== undefined &&\n connection.readyState !== wsReadyStateConnecting &&\n connection.readyState !== wsReadyStateOpen\n ) {\n return;\n }\n try {\n connection.send(`__YPS:${message}`);\n } catch (e) {\n console.warn(\"Failed to send custom message\", e);\n }\n }\n\n /**\n * Broadcast a custom string message to all connected clients.\n * @param message - The custom message string to broadcast\n * @param excludeConnection - Optional connection to exclude from the broadcast\n */\n broadcastCustomMessage(\n message: string,\n excludeConnection?: Connection\n ): void {\n const formattedMessage = `__YPS:${message}`;\n for (const conn of this.getConnections()) {\n if (excludeConnection && conn === excludeConnection) {\n continue;\n }\n if (\n conn.readyState !== undefined &&\n conn.readyState !== wsReadyStateConnecting &&\n conn.readyState !== wsReadyStateOpen\n ) {\n continue;\n }\n try {\n conn.send(formattedMessage);\n } catch (e) {\n console.warn(\"Failed to broadcast custom message\", e);\n }\n }\n }\n\n handleMessage(connection: Connection, message: WSMessage) {\n if (typeof message === \"string\") {\n // Handle custom messages with __YPS: prefix\n if (message.startsWith(\"__YPS:\")) {\n const customMessage = message.slice(6); // Remove __YPS: prefix\n this.onCustomMessage(connection, customMessage);\n return;\n }\n console.warn(\n `Received non-prefixed string message. Custom messages should be sent using sendMessage() on the provider.`\n );\n return;\n }\n try {\n const encoder = encoding.createEncoder();\n // Convert ArrayBuffer to Uint8Array if needed (ArrayBufferView like Uint8Array can be used directly)\n const uint8Array =\n message instanceof Uint8Array\n ? message\n : message instanceof ArrayBuffer\n ? new Uint8Array(message)\n : new Uint8Array(\n message.buffer,\n message.byteOffset,\n message.byteLength\n );\n const decoder = decoding.createDecoder(uint8Array);\n const messageType = decoding.readVarUint(decoder);\n switch (messageType) {\n case messageSync:\n encoding.writeVarUint(encoder, messageSync);\n readSyncMessage(\n decoder,\n encoder,\n this.document,\n connection,\n this.isReadOnly(connection)\n );\n\n // If the `encoder` only contains the type of reply message and no\n // message, there is no need to send the message. When `encoder` only\n // contains the type of reply, its length is 1.\n if (encoding.length(encoder) > 1) {\n send(connection, encoding.toUint8Array(encoder));\n }\n break;\n case messageAwareness: {\n const awarenessData = decoding.readVarUint8Array(decoder);\n awarenessProtocol.applyAwarenessUpdate(\n this.document.awareness,\n awarenessData,\n connection\n );\n // Forward raw awareness bytes to all connections\n const awarenessEncoder = encoding.createEncoder();\n encoding.writeVarUint(awarenessEncoder, messageAwareness);\n encoding.writeVarUint8Array(awarenessEncoder, awarenessData);\n const awarenessBuff = encoding.toUint8Array(awarenessEncoder);\n for (const c of this.getConnections()) {\n send(c, awarenessBuff);\n }\n break;\n }\n }\n } catch (err) {\n console.error(err);\n // @ts-expect-error - TODO: fix this\n this.document.emit(\"error\", [err]);\n }\n }\n\n onMessage(conn: Connection, message: WSMessage) {\n this.handleMessage(conn, message);\n }\n\n onClose(\n connection: Connection<unknown>,\n _code: number,\n _reason: string,\n _wasClean: boolean\n ): void | Promise<void> {\n // Read controlled awareness clientIDs from connection state\n // (survives hibernation unlike an in-memory Map)\n const controlledIds = getAwarenessIds(connection);\n if (controlledIds.length > 0) {\n awarenessProtocol.removeAwarenessStates(\n this.document.awareness,\n controlledIds,\n null\n );\n }\n }\n\n // TODO: explore why onError gets triggered when a connection closes\n\n onConnect(\n conn: Connection<unknown>,\n _ctx: ConnectionContext\n ): void | Promise<void> {\n // Note: awareness IDs are lazily initialized when the first awareness\n // message is received — no need to call setAwarenessIds(conn, []) here\n\n // send sync step 1\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, this.document);\n send(conn, encoding.toUint8Array(encoder));\n const awarenessStates = this.document.awareness.getStates();\n if (awarenessStates.size > 0) {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n this.document.awareness,\n Array.from(awarenessStates.keys())\n )\n );\n send(conn, encoding.toUint8Array(encoder));\n }\n }\n }\n\n return YjsMixin as unknown as TBase &\n YjsStatic &\n (new (...args: any[]) => YjsInstance);\n}\n\nexport const YServer = withYjs(Server);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["YDoc","awarenessProtocol","decoding","syncProtocol","UndoManager","XmlText","XmlElement","XmlFragment","encoding","Server"],"sources":["../../src/server/index.ts"],"sourcesContent":["import * as decoding from \"lib0/decoding\";\nimport * as encoding from \"lib0/encoding\";\nimport debounce from \"lodash.debounce\";\nimport type { Connection, ConnectionContext, WSMessage } from \"partyserver\";\nimport { Server } from \"partyserver\";\nimport * as awarenessProtocol from \"y-protocols/awareness\";\nimport * as syncProtocol from \"y-protocols/sync\";\nimport {\n applyUpdate,\n Doc as YDoc,\n encodeStateAsUpdate,\n encodeStateVector,\n UndoManager,\n XmlText,\n XmlElement,\n XmlFragment\n} from \"yjs\";\n\nconst snapshotOrigin = Symbol(\"snapshot-origin\");\ntype YjsRootType =\n | \"Text\"\n | \"Map\"\n | \"Array\"\n | \"XmlText\"\n | \"XmlElement\"\n | \"XmlFragment\";\n\nconst wsReadyStateConnecting = 0;\nconst wsReadyStateOpen = 1;\n// oxlint-disable-next-line no-unused-vars\nconst wsReadyStateClosing = 2;\n// oxlint-disable-next-line no-unused-vars\nconst wsReadyStateClosed = 3;\n\nconst messageSync = 0;\nconst messageAwareness = 1;\n// oxlint-disable-next-line no-unused-vars\nconst messageAuth = 2;\n\n/**\n * Internal key used in connection.setState() to track which awareness\n * client IDs are controlled by each connection. This survives hibernation\n * because connection state is persisted to WebSocket attachments.\n */\nconst AWARENESS_IDS_KEY = \"__ypsAwarenessIds\";\n\ntype YServerConnectionState = {\n [AWARENESS_IDS_KEY]?: number[];\n [key: string]: unknown;\n};\n\nfunction getAwarenessIds(conn: Connection): number[] {\n try {\n const state = conn.state as YServerConnectionState | null;\n return state?.[AWARENESS_IDS_KEY] ?? [];\n } catch {\n return [];\n }\n}\n\nfunction setAwarenessIds(conn: Connection, ids: number[]): void {\n try {\n conn.setState((prev: YServerConnectionState | null) => ({\n ...prev,\n [AWARENESS_IDS_KEY]: ids\n }));\n } catch {\n // ignore — may fail if connection is already closed\n }\n}\n\nclass WSSharedDoc extends YDoc {\n awareness: awarenessProtocol.Awareness;\n\n constructor() {\n super({ gc: true });\n this.awareness = new awarenessProtocol.Awareness(this);\n this.awareness.setLocalState(null);\n\n // Disable the awareness protocol's built-in check interval.\n // It renews the local clock every 15s and removes peers after 30s,\n // but we handle peer cleanup via onClose instead. Clearing it here\n // prevents it from defeating Durable Object hibernation.\n clearInterval(\n (\n this.awareness as unknown as {\n _checkInterval: ReturnType<typeof setInterval>;\n }\n )._checkInterval\n );\n }\n}\n\nconst CALLBACK_DEFAULTS = {\n debounceWait: 2000,\n debounceMaxWait: 10000,\n timeout: 5000\n};\n\nfunction readSyncMessage(\n decoder: decoding.Decoder,\n encoder: encoding.Encoder,\n doc: YDoc,\n transactionOrigin: Connection,\n readOnly = false\n) {\n const messageType = decoding.readVarUint(decoder);\n switch (messageType) {\n case syncProtocol.messageYjsSyncStep1:\n syncProtocol.readSyncStep1(decoder, encoder, doc);\n break;\n case syncProtocol.messageYjsSyncStep2:\n if (!readOnly)\n syncProtocol.readSyncStep2(decoder, doc, transactionOrigin);\n break;\n case syncProtocol.messageYjsUpdate:\n if (!readOnly) syncProtocol.readUpdate(decoder, doc, transactionOrigin);\n break;\n default:\n throw new Error(\"Unknown message type\");\n }\n return messageType;\n}\n\nfunction send(conn: Connection, m: Uint8Array): void {\n if (\n conn.readyState !== undefined &&\n conn.readyState !== wsReadyStateConnecting &&\n conn.readyState !== wsReadyStateOpen\n ) {\n return;\n }\n try {\n conn.send(m);\n } catch {\n // connection is broken, ignore\n }\n}\n\nexport interface CallbackOptions {\n debounceWait?: number;\n debounceMaxWait?: number;\n timeout?: number;\n}\n\ntype ServerClass = new (...args: any[]) => Server;\n\nexport interface YjsInstance {\n readonly document: WSSharedDoc;\n onLoad(): Promise<YDoc | void>;\n onSave(): Promise<void>;\n unstable_replaceDocument(\n snapshotUpdate: Uint8Array,\n getMetadata?: (key: string) => YjsRootType\n ): void;\n isReadOnly(connection: Connection): boolean;\n onCustomMessage(connection: Connection, message: string): void;\n sendCustomMessage(connection: Connection, message: string): void;\n broadcastCustomMessage(message: string, excludeConnection?: Connection): void;\n handleMessage(connection: Connection, message: WSMessage): void;\n}\n\nexport interface YjsStatic {\n callbackOptions: CallbackOptions;\n}\n\nexport function withYjs<TBase extends ServerClass>(\n Base: TBase\n): TBase & YjsStatic & (new (...args: any[]) => YjsInstance) {\n class YjsMixin extends Base {\n static callbackOptions: CallbackOptions = {};\n\n readonly document: WSSharedDoc = new WSSharedDoc();\n\n async onLoad(): Promise<YDoc | void> {\n // to be implemented by the user\n return;\n }\n\n async onSave(): Promise<void> {\n // to be implemented by the user\n }\n\n /**\n * Replaces the document with a different state using Yjs UndoManager key remapping.\n *\n * @param snapshotUpdate - The snapshot update to replace the document with.\n * @param getMetadata (optional) - A function that returns the type of the root for a given key.\n */\n unstable_replaceDocument(\n snapshotUpdate: Uint8Array,\n getMetadata: (key: string) => YjsRootType = () => \"Map\"\n ): void {\n try {\n const doc = this.document;\n const snapshotDoc = new YDoc();\n applyUpdate(snapshotDoc, snapshotUpdate, snapshotOrigin);\n\n const currentStateVector = encodeStateVector(doc);\n const snapshotStateVector = encodeStateVector(snapshotDoc);\n\n const changesSinceSnapshotUpdate = encodeStateAsUpdate(\n doc,\n snapshotStateVector\n );\n\n const undoManager = new UndoManager(\n [...snapshotDoc.share.keys()].map((key) => {\n const type = getMetadata(key);\n if (type === \"Text\") {\n return snapshotDoc.getText(key);\n } else if (type === \"Map\") {\n return snapshotDoc.getMap(key);\n } else if (type === \"Array\") {\n return snapshotDoc.getArray(key);\n } else if (type === \"XmlText\") {\n return snapshotDoc.get(key, XmlText);\n } else if (type === \"XmlElement\") {\n return snapshotDoc.get(key, XmlElement);\n } else if (type === \"XmlFragment\") {\n return snapshotDoc.get(key, XmlFragment);\n }\n throw new Error(`Unknown root type: ${type} for key: ${key}`);\n }),\n {\n trackedOrigins: new Set([snapshotOrigin])\n }\n );\n\n applyUpdate(snapshotDoc, changesSinceSnapshotUpdate, snapshotOrigin);\n undoManager.undo();\n\n const documentChangesSinceSnapshotUpdate = encodeStateAsUpdate(\n snapshotDoc,\n currentStateVector\n );\n\n applyUpdate(this.document, documentChangesSinceSnapshotUpdate);\n } catch (error) {\n throw new Error(\n `Failed to replace document: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n }\n }\n\n async onStart(): Promise<void> {\n const src = await this.onLoad();\n if (src != null) {\n const state = encodeStateAsUpdate(src);\n applyUpdate(this.document, state);\n }\n\n // Broadcast doc updates to all connections.\n // Uses this.getConnections() which works for both hibernate and non-hibernate\n // modes and survives DO hibernation (unlike an in-memory Map).\n this.document.on(\"update\", (update: Uint8Array) => {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeUpdate(encoder, update);\n const message = encoding.toUint8Array(encoder);\n for (const conn of this.getConnections()) {\n send(conn, message);\n }\n });\n\n // Track which awareness clientIDs each connection controls.\n // Stored in connection.setState() so it survives hibernation.\n // When conn is null (internal changes like removeAwarenessStates on close),\n // broadcast the update to remaining connections.\n // When conn is non-null (client message), handleMessage broadcasts directly.\n this.document.awareness.on(\n \"update\",\n (\n {\n added,\n updated,\n removed\n }: {\n added: Array<number>;\n updated: Array<number>;\n removed: Array<number>;\n },\n conn: Connection | null\n ) => {\n if (conn !== null) {\n // Track which clientIDs this connection controls\n try {\n const currentIds = new Set(getAwarenessIds(conn));\n for (const clientID of added) currentIds.add(clientID);\n for (const clientID of removed) currentIds.delete(clientID);\n setAwarenessIds(conn, [...currentIds]);\n } catch (_e) {\n // ignore — best-effort tracking\n }\n } else {\n // Internal awareness change (e.g. removeAwarenessStates on close)\n // — broadcast to all remaining connections\n const changedClients = added.concat(updated, removed);\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n this.document.awareness,\n changedClients\n )\n );\n const buff = encoding.toUint8Array(encoder);\n for (const c of this.getConnections()) {\n send(c, buff);\n }\n }\n }\n );\n\n // Debounced persistence handler\n const ctor = this.constructor as typeof YjsMixin;\n this.document.on(\n \"update\",\n debounce(\n (_update: Uint8Array, _origin: Connection, _doc: YDoc) => {\n try {\n this.onSave().catch((err) => {\n console.error(\"failed to persist:\", err);\n });\n } catch (err) {\n console.error(\"failed to persist:\", err);\n }\n },\n ctor.callbackOptions.debounceWait || CALLBACK_DEFAULTS.debounceWait,\n {\n maxWait:\n ctor.callbackOptions.debounceMaxWait ||\n CALLBACK_DEFAULTS.debounceMaxWait\n }\n )\n );\n\n // After hibernation wake-up, the doc is empty but existing connections\n // survive. Re-sync by sending sync step 1 to all connections — they'll\n // respond with sync step 2 containing their full state.\n // On first start there are no connections, so this is a no-op.\n const syncEncoder = encoding.createEncoder();\n encoding.writeVarUint(syncEncoder, messageSync);\n syncProtocol.writeSyncStep1(syncEncoder, this.document);\n const syncMessage = encoding.toUint8Array(syncEncoder);\n for (const conn of this.getConnections()) {\n send(conn, syncMessage);\n }\n }\n\n // oxlint-disable-next-line no-unused-vars\n isReadOnly(connection: Connection): boolean {\n // to be implemented by the user\n return false;\n }\n\n /**\n * Handle custom string messages from the client.\n * Override this method to implement custom message handling.\n * @param connection - The connection that sent the message\n * @param message - The custom message string (without the __YPS: prefix)\n */\n // oxlint-disable-next-line no-unused-vars\n onCustomMessage(connection: Connection, message: string): void {\n // to be implemented by the user\n console.warn(\n `Received custom message but onCustomMessage is not implemented in ${this.constructor.name}:`,\n message\n );\n }\n\n /**\n * Send a custom string message to a specific connection.\n * @param connection - The connection to send the message to\n * @param message - The custom message string to send\n */\n sendCustomMessage(connection: Connection, message: string): void {\n if (\n connection.readyState !== undefined &&\n connection.readyState !== wsReadyStateConnecting &&\n connection.readyState !== wsReadyStateOpen\n ) {\n return;\n }\n try {\n connection.send(`__YPS:${message}`);\n } catch (e) {\n console.warn(\"Failed to send custom message\", e);\n }\n }\n\n /**\n * Broadcast a custom string message to all connected clients.\n * @param message - The custom message string to broadcast\n * @param excludeConnection - Optional connection to exclude from the broadcast\n */\n broadcastCustomMessage(\n message: string,\n excludeConnection?: Connection\n ): void {\n const formattedMessage = `__YPS:${message}`;\n for (const conn of this.getConnections()) {\n if (excludeConnection && conn === excludeConnection) {\n continue;\n }\n if (\n conn.readyState !== undefined &&\n conn.readyState !== wsReadyStateConnecting &&\n conn.readyState !== wsReadyStateOpen\n ) {\n continue;\n }\n try {\n conn.send(formattedMessage);\n } catch (e) {\n console.warn(\"Failed to broadcast custom message\", e);\n }\n }\n }\n\n handleMessage(connection: Connection, message: WSMessage) {\n if (typeof message === \"string\") {\n // Handle custom messages with __YPS: prefix\n if (message.startsWith(\"__YPS:\")) {\n const customMessage = message.slice(6); // Remove __YPS: prefix\n this.onCustomMessage(connection, customMessage);\n return;\n }\n console.warn(\n `Received non-prefixed string message. Custom messages should be sent using sendMessage() on the provider.`\n );\n return;\n }\n try {\n const encoder = encoding.createEncoder();\n // Convert ArrayBuffer to Uint8Array if needed (ArrayBufferView like Uint8Array can be used directly)\n const uint8Array =\n message instanceof Uint8Array\n ? message\n : message instanceof ArrayBuffer\n ? new Uint8Array(message)\n : new Uint8Array(\n message.buffer,\n message.byteOffset,\n message.byteLength\n );\n const decoder = decoding.createDecoder(uint8Array);\n const messageType = decoding.readVarUint(decoder);\n switch (messageType) {\n case messageSync:\n encoding.writeVarUint(encoder, messageSync);\n readSyncMessage(\n decoder,\n encoder,\n this.document,\n connection,\n this.isReadOnly(connection)\n );\n\n // If the `encoder` only contains the type of reply message and no\n // message, there is no need to send the message. When `encoder` only\n // contains the type of reply, its length is 1.\n if (encoding.length(encoder) > 1) {\n send(connection, encoding.toUint8Array(encoder));\n }\n break;\n case messageAwareness: {\n const awarenessData = decoding.readVarUint8Array(decoder);\n awarenessProtocol.applyAwarenessUpdate(\n this.document.awareness,\n awarenessData,\n connection\n );\n // Forward raw awareness bytes to all connections\n const awarenessEncoder = encoding.createEncoder();\n encoding.writeVarUint(awarenessEncoder, messageAwareness);\n encoding.writeVarUint8Array(awarenessEncoder, awarenessData);\n const awarenessBuff = encoding.toUint8Array(awarenessEncoder);\n for (const c of this.getConnections()) {\n send(c, awarenessBuff);\n }\n break;\n }\n }\n } catch (err) {\n console.error(err);\n // @ts-expect-error - TODO: fix this\n this.document.emit(\"error\", [err]);\n }\n }\n\n onMessage(conn: Connection, message: WSMessage) {\n this.handleMessage(conn, message);\n }\n\n onClose(\n connection: Connection<unknown>,\n _code: number,\n _reason: string,\n _wasClean: boolean\n ): void | Promise<void> {\n // Read controlled awareness clientIDs from connection state\n // (survives hibernation unlike an in-memory Map)\n const controlledIds = getAwarenessIds(connection);\n if (controlledIds.length > 0) {\n awarenessProtocol.removeAwarenessStates(\n this.document.awareness,\n controlledIds,\n null\n );\n }\n }\n\n // TODO: explore why onError gets triggered when a connection closes\n\n onConnect(\n conn: Connection<unknown>,\n _ctx: ConnectionContext\n ): void | Promise<void> {\n // Note: awareness IDs are lazily initialized when the first awareness\n // message is received — no need to call setAwarenessIds(conn, []) here\n\n // send sync step 1\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, this.document);\n send(conn, encoding.toUint8Array(encoder));\n const awarenessStates = this.document.awareness.getStates();\n if (awarenessStates.size > 0) {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n this.document.awareness,\n Array.from(awarenessStates.keys())\n )\n );\n send(conn, encoding.toUint8Array(encoder));\n }\n }\n }\n\n return YjsMixin as unknown as TBase &\n YjsStatic &\n (new (...args: any[]) => YjsInstance);\n}\n\nexport const YServer = withYjs(Server);\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,MAAM,iBAAiB,OAAO,kBAAkB;AAShD,MAAM,yBAAyB;AAC/B,MAAM,mBAAmB;AAMzB,MAAM,cAAc;AACpB,MAAM,mBAAmB;;;;;;AASzB,MAAM,oBAAoB;AAO1B,SAAS,gBAAgB,MAA4B;AACnD,KAAI;AAEF,SADc,KAAK,QACJ,sBAAsB,EAAE;SACjC;AACN,SAAO,EAAE;;;AAIb,SAAS,gBAAgB,MAAkB,KAAqB;AAC9D,KAAI;AACF,OAAK,UAAU,UAAyC;GACtD,GAAG;IACF,oBAAoB;GACtB,EAAE;SACG;;AAKV,IAAM,cAAN,cAA0BA,IAAAA,IAAK;CAC7B;CAEA,cAAc;AACZ,QAAM,EAAE,IAAI,MAAM,CAAC;AACnB,OAAK,YAAY,IAAIC,sBAAkB,UAAU,KAAK;AACtD,OAAK,UAAU,cAAc,KAAK;AAMlC,gBAEI,KAAK,UAGL,eACH;;;AAIL,MAAM,oBAAoB;CACxB,cAAc;CACd,iBAAiB;CACjB,SAAS;CACV;AAED,SAAS,gBACP,SACA,SACA,KACA,mBACA,WAAW,OACX;CACA,MAAM,cAAcC,cAAS,YAAY,QAAQ;AACjD,SAAQ,aAAR;EACE,KAAKC,iBAAa;AAChB,oBAAa,cAAc,SAAS,SAAS,IAAI;AACjD;EACF,KAAKA,iBAAa;AAChB,OAAI,CAAC,SACH,kBAAa,cAAc,SAAS,KAAK,kBAAkB;AAC7D;EACF,KAAKA,iBAAa;AAChB,OAAI,CAAC,SAAU,kBAAa,WAAW,SAAS,KAAK,kBAAkB;AACvE;EACF,QACE,OAAM,IAAI,MAAM,uBAAuB;;AAE3C,QAAO;;AAGT,SAAS,KAAK,MAAkB,GAAqB;AACnD,KACE,KAAK,eAAe,KAAA,KACpB,KAAK,eAAe,0BACpB,KAAK,eAAe,iBAEpB;AAEF,KAAI;AACF,OAAK,KAAK,EAAE;SACN;;AAgCV,SAAgB,QACd,MAC2D;CAC3D,MAAM,iBAAiB,KAAK;EAC1B,OAAO,kBAAmC,EAAE;EAE5C,WAAiC,IAAI,aAAa;EAElD,MAAM,SAA+B;EAKrC,MAAM,SAAwB;;;;;;;EAU9B,yBACE,gBACA,oBAAkD,OAC5C;AACN,OAAI;IACF,MAAM,MAAM,KAAK;IACjB,MAAM,cAAc,IAAIH,IAAAA,KAAM;AAC9B,KAAA,GAAA,IAAA,aAAY,aAAa,gBAAgB,eAAe;IAExD,MAAM,sBAAA,GAAA,IAAA,mBAAuC,IAAI;IAGjD,MAAM,8BAAA,GAAA,IAAA,qBACJ,MAAA,GAAA,IAAA,mBAH4C,YAIzB,CACpB;IAED,MAAM,cAAc,IAAII,IAAAA,YACtB,CAAC,GAAG,YAAY,MAAM,MAAM,CAAC,CAAC,KAAK,QAAQ;KACzC,MAAM,OAAO,YAAY,IAAI;AAC7B,SAAI,SAAS,OACX,QAAO,YAAY,QAAQ,IAAI;cACtB,SAAS,MAClB,QAAO,YAAY,OAAO,IAAI;cACrB,SAAS,QAClB,QAAO,YAAY,SAAS,IAAI;cACvB,SAAS,UAClB,QAAO,YAAY,IAAI,KAAKC,IAAAA,QAAQ;cAC3B,SAAS,aAClB,QAAO,YAAY,IAAI,KAAKC,IAAAA,WAAW;cAC9B,SAAS,cAClB,QAAO,YAAY,IAAI,KAAKC,IAAAA,YAAY;AAE1C,WAAM,IAAI,MAAM,sBAAsB,KAAK,YAAY,MAAM;MAC7D,EACF,EACE,gBAAgB,IAAI,IAAI,CAAC,eAAe,CAAC,EAC1C,CACF;AAED,KAAA,GAAA,IAAA,aAAY,aAAa,4BAA4B,eAAe;AACpE,gBAAY,MAAM;IAElB,MAAM,sCAAA,GAAA,IAAA,qBACJ,aACA,mBACD;AAED,KAAA,GAAA,IAAA,aAAY,KAAK,UAAU,mCAAmC;YACvD,OAAO;AACd,UAAM,IAAI,MACR,+BAA+B,iBAAiB,QAAQ,MAAM,UAAU,kBACzE;;;EAIL,MAAM,UAAyB;GAC7B,MAAM,MAAM,MAAM,KAAK,QAAQ;AAC/B,OAAI,OAAO,MAAM;IACf,MAAM,SAAA,GAAA,IAAA,qBAA4B,IAAI;AACtC,KAAA,GAAA,IAAA,aAAY,KAAK,UAAU,MAAM;;AAMnC,QAAK,SAAS,GAAG,WAAW,WAAuB;IACjD,MAAM,UAAUC,cAAS,eAAe;AACxC,kBAAS,aAAa,SAAS,YAAY;AAC3C,qBAAa,YAAY,SAAS,OAAO;IACzC,MAAM,UAAUA,cAAS,aAAa,QAAQ;AAC9C,SAAK,MAAM,QAAQ,KAAK,gBAAgB,CACtC,MAAK,MAAM,QAAQ;KAErB;AAOF,QAAK,SAAS,UAAU,GACtB,WAEE,EACE,OACA,SACA,WAMF,SACG;AACH,QAAI,SAAS,KAEX,KAAI;KACF,MAAM,aAAa,IAAI,IAAI,gBAAgB,KAAK,CAAC;AACjD,UAAK,MAAM,YAAY,MAAO,YAAW,IAAI,SAAS;AACtD,UAAK,MAAM,YAAY,QAAS,YAAW,OAAO,SAAS;AAC3D,qBAAgB,MAAM,CAAC,GAAG,WAAW,CAAC;aAC/B,IAAI;SAGR;KAGL,MAAM,iBAAiB,MAAM,OAAO,SAAS,QAAQ;KACrD,MAAM,UAAUA,cAAS,eAAe;AACxC,mBAAS,aAAa,SAAS,iBAAiB;AAChD,mBAAS,mBACP,SACAP,sBAAkB,sBAChB,KAAK,SAAS,WACd,eACD,CACF;KACD,MAAM,OAAOO,cAAS,aAAa,QAAQ;AAC3C,UAAK,MAAM,KAAK,KAAK,gBAAgB,CACnC,MAAK,GAAG,KAAK;;KAIpB;GAGD,MAAM,OAAO,KAAK;AAClB,QAAK,SAAS,GACZ,WAAA,GAAA,gBAAA,UAEG,SAAqB,SAAqB,SAAe;AACxD,QAAI;AACF,UAAK,QAAQ,CAAC,OAAO,QAAQ;AAC3B,cAAQ,MAAM,sBAAsB,IAAI;OACxC;aACK,KAAK;AACZ,aAAQ,MAAM,sBAAsB,IAAI;;MAG5C,KAAK,gBAAgB,gBAAgB,kBAAkB,cACvD,EACE,SACE,KAAK,gBAAgB,mBACrB,kBAAkB,iBACrB,CACF,CACF;GAMD,MAAM,cAAcA,cAAS,eAAe;AAC5C,iBAAS,aAAa,aAAa,YAAY;AAC/C,oBAAa,eAAe,aAAa,KAAK,SAAS;GACvD,MAAM,cAAcA,cAAS,aAAa,YAAY;AACtD,QAAK,MAAM,QAAQ,KAAK,gBAAgB,CACtC,MAAK,MAAM,YAAY;;EAK3B,WAAW,YAAiC;AAE1C,UAAO;;;;;;;;EAUT,gBAAgB,YAAwB,SAAuB;AAE7D,WAAQ,KACN,qEAAqE,KAAK,YAAY,KAAK,IAC3F,QACD;;;;;;;EAQH,kBAAkB,YAAwB,SAAuB;AAC/D,OACE,WAAW,eAAe,KAAA,KAC1B,WAAW,eAAe,0BAC1B,WAAW,eAAe,iBAE1B;AAEF,OAAI;AACF,eAAW,KAAK,SAAS,UAAU;YAC5B,GAAG;AACV,YAAQ,KAAK,iCAAiC,EAAE;;;;;;;;EASpD,uBACE,SACA,mBACM;GACN,MAAM,mBAAmB,SAAS;AAClC,QAAK,MAAM,QAAQ,KAAK,gBAAgB,EAAE;AACxC,QAAI,qBAAqB,SAAS,kBAChC;AAEF,QACE,KAAK,eAAe,KAAA,KACpB,KAAK,eAAe,0BACpB,KAAK,eAAe,iBAEpB;AAEF,QAAI;AACF,UAAK,KAAK,iBAAiB;aACpB,GAAG;AACV,aAAQ,KAAK,sCAAsC,EAAE;;;;EAK3D,cAAc,YAAwB,SAAoB;AACxD,OAAI,OAAO,YAAY,UAAU;AAE/B,QAAI,QAAQ,WAAW,SAAS,EAAE;KAChC,MAAM,gBAAgB,QAAQ,MAAM,EAAE;AACtC,UAAK,gBAAgB,YAAY,cAAc;AAC/C;;AAEF,YAAQ,KACN,4GACD;AACD;;AAEF,OAAI;IACF,MAAM,UAAUA,cAAS,eAAe;IAExC,MAAM,aACJ,mBAAmB,aACf,UACA,mBAAmB,cACjB,IAAI,WAAW,QAAQ,GACvB,IAAI,WACF,QAAQ,QACR,QAAQ,YACR,QAAQ,WACT;IACT,MAAM,UAAUN,cAAS,cAAc,WAAW;AAElD,YADoBA,cAAS,YAAY,QACtB,EAAnB;KACE,KAAK;AACH,oBAAS,aAAa,SAAS,YAAY;AAC3C,sBACE,SACA,SACA,KAAK,UACL,YACA,KAAK,WAAW,WAAW,CAC5B;AAKD,UAAIM,cAAS,OAAO,QAAQ,GAAG,EAC7B,MAAK,YAAYA,cAAS,aAAa,QAAQ,CAAC;AAElD;KACF,KAAK,kBAAkB;MACrB,MAAM,gBAAgBN,cAAS,kBAAkB,QAAQ;AACzD,4BAAkB,qBAChB,KAAK,SAAS,WACd,eACA,WACD;MAED,MAAM,mBAAmBM,cAAS,eAAe;AACjD,oBAAS,aAAa,kBAAkB,iBAAiB;AACzD,oBAAS,mBAAmB,kBAAkB,cAAc;MAC5D,MAAM,gBAAgBA,cAAS,aAAa,iBAAiB;AAC7D,WAAK,MAAM,KAAK,KAAK,gBAAgB,CACnC,MAAK,GAAG,cAAc;AAExB;;;YAGG,KAAK;AACZ,YAAQ,MAAM,IAAI;AAElB,SAAK,SAAS,KAAK,SAAS,CAAC,IAAI,CAAC;;;EAItC,UAAU,MAAkB,SAAoB;AAC9C,QAAK,cAAc,MAAM,QAAQ;;EAGnC,QACE,YACA,OACA,SACA,WACsB;GAGtB,MAAM,gBAAgB,gBAAgB,WAAW;AACjD,OAAI,cAAc,SAAS,EACzB,uBAAkB,sBAChB,KAAK,SAAS,WACd,eACA,KACD;;EAML,UACE,MACA,MACsB;GAKtB,MAAM,UAAUA,cAAS,eAAe;AACxC,iBAAS,aAAa,SAAS,YAAY;AAC3C,oBAAa,eAAe,SAAS,KAAK,SAAS;AACnD,QAAK,MAAMA,cAAS,aAAa,QAAQ,CAAC;GAC1C,MAAM,kBAAkB,KAAK,SAAS,UAAU,WAAW;AAC3D,OAAI,gBAAgB,OAAO,GAAG;IAC5B,MAAM,UAAUA,cAAS,eAAe;AACxC,kBAAS,aAAa,SAAS,iBAAiB;AAChD,kBAAS,mBACP,SACAP,sBAAkB,sBAChB,KAAK,SAAS,WACd,MAAM,KAAK,gBAAgB,MAAM,CAAC,CACnC,CACF;AACD,SAAK,MAAMO,cAAS,aAAa,QAAQ,CAAC;;;;AAKhD,QAAO;;AAKT,MAAa,UAAU,QAAQC,YAAAA,OAAO"}
|
package/dist/server/index.js
CHANGED
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
encodeStateAsUpdate,
|
|
15
15
|
encodeStateVector
|
|
16
16
|
} from "yjs";
|
|
17
|
-
|
|
18
17
|
//#region src/server/index.ts
|
|
19
18
|
const snapshotOrigin = Symbol("snapshot-origin");
|
|
20
19
|
const wsReadyStateConnecting = 0;
|
|
@@ -355,7 +354,7 @@ function withYjs(Base) {
|
|
|
355
354
|
return YjsMixin;
|
|
356
355
|
}
|
|
357
356
|
const YServer = withYjs(Server);
|
|
358
|
-
|
|
359
357
|
//#endregion
|
|
360
358
|
export { YServer, withYjs };
|
|
359
|
+
|
|
361
360
|
//# sourceMappingURL=index.js.map
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["YDoc"],"sources":["../../src/server/index.ts"],"sourcesContent":["import * as decoding from \"lib0/decoding\";\nimport * as encoding from \"lib0/encoding\";\nimport debounce from \"lodash.debounce\";\nimport type { Connection, ConnectionContext, WSMessage } from \"partyserver\";\nimport { Server } from \"partyserver\";\nimport * as awarenessProtocol from \"y-protocols/awareness\";\nimport * as syncProtocol from \"y-protocols/sync\";\nimport {\n applyUpdate,\n Doc as YDoc,\n encodeStateAsUpdate,\n encodeStateVector,\n UndoManager,\n XmlText,\n XmlElement,\n XmlFragment\n} from \"yjs\";\n\nconst snapshotOrigin = Symbol(\"snapshot-origin\");\ntype YjsRootType =\n | \"Text\"\n | \"Map\"\n | \"Array\"\n | \"XmlText\"\n | \"XmlElement\"\n | \"XmlFragment\";\n\nconst wsReadyStateConnecting = 0;\nconst wsReadyStateOpen = 1;\n// oxlint-disable-next-line no-unused-vars\nconst wsReadyStateClosing = 2;\n// oxlint-disable-next-line no-unused-vars\nconst wsReadyStateClosed = 3;\n\nconst messageSync = 0;\nconst messageAwareness = 1;\n// oxlint-disable-next-line no-unused-vars\nconst messageAuth = 2;\n\n/**\n * Internal key used in connection.setState() to track which awareness\n * client IDs are controlled by each connection. This survives hibernation\n * because connection state is persisted to WebSocket attachments.\n */\nconst AWARENESS_IDS_KEY = \"__ypsAwarenessIds\";\n\ntype YServerConnectionState = {\n [AWARENESS_IDS_KEY]?: number[];\n [key: string]: unknown;\n};\n\nfunction getAwarenessIds(conn: Connection): number[] {\n try {\n const state = conn.state as YServerConnectionState | null;\n return state?.[AWARENESS_IDS_KEY] ?? [];\n } catch {\n return [];\n }\n}\n\nfunction setAwarenessIds(conn: Connection, ids: number[]): void {\n try {\n conn.setState((prev: YServerConnectionState | null) => ({\n ...prev,\n [AWARENESS_IDS_KEY]: ids\n }));\n } catch {\n // ignore — may fail if connection is already closed\n }\n}\n\nclass WSSharedDoc extends YDoc {\n awareness: awarenessProtocol.Awareness;\n\n constructor() {\n super({ gc: true });\n this.awareness = new awarenessProtocol.Awareness(this);\n this.awareness.setLocalState(null);\n\n // Disable the awareness protocol's built-in check interval.\n // It renews the local clock every 15s and removes peers after 30s,\n // but we handle peer cleanup via onClose instead. Clearing it here\n // prevents it from defeating Durable Object hibernation.\n clearInterval(\n (\n this.awareness as unknown as {\n _checkInterval: ReturnType<typeof setInterval>;\n }\n )._checkInterval\n );\n }\n}\n\nconst CALLBACK_DEFAULTS = {\n debounceWait: 2000,\n debounceMaxWait: 10000,\n timeout: 5000\n};\n\nfunction readSyncMessage(\n decoder: decoding.Decoder,\n encoder: encoding.Encoder,\n doc: YDoc,\n transactionOrigin: Connection,\n readOnly = false\n) {\n const messageType = decoding.readVarUint(decoder);\n switch (messageType) {\n case syncProtocol.messageYjsSyncStep1:\n syncProtocol.readSyncStep1(decoder, encoder, doc);\n break;\n case syncProtocol.messageYjsSyncStep2:\n if (!readOnly)\n syncProtocol.readSyncStep2(decoder, doc, transactionOrigin);\n break;\n case syncProtocol.messageYjsUpdate:\n if (!readOnly) syncProtocol.readUpdate(decoder, doc, transactionOrigin);\n break;\n default:\n throw new Error(\"Unknown message type\");\n }\n return messageType;\n}\n\nfunction send(conn: Connection, m: Uint8Array): void {\n if (\n conn.readyState !== undefined &&\n conn.readyState !== wsReadyStateConnecting &&\n conn.readyState !== wsReadyStateOpen\n ) {\n return;\n }\n try {\n conn.send(m);\n } catch {\n // connection is broken, ignore\n }\n}\n\nexport interface CallbackOptions {\n debounceWait?: number;\n debounceMaxWait?: number;\n timeout?: number;\n}\n\ntype ServerClass = new (...args: any[]) => Server;\n\nexport interface YjsInstance {\n readonly document: WSSharedDoc;\n onLoad(): Promise<YDoc | void>;\n onSave(): Promise<void>;\n unstable_replaceDocument(\n snapshotUpdate: Uint8Array,\n getMetadata?: (key: string) => YjsRootType\n ): void;\n isReadOnly(connection: Connection): boolean;\n onCustomMessage(connection: Connection, message: string): void;\n sendCustomMessage(connection: Connection, message: string): void;\n broadcastCustomMessage(message: string, excludeConnection?: Connection): void;\n handleMessage(connection: Connection, message: WSMessage): void;\n}\n\nexport interface YjsStatic {\n callbackOptions: CallbackOptions;\n}\n\nexport function withYjs<TBase extends ServerClass>(\n Base: TBase\n): TBase & YjsStatic & (new (...args: any[]) => YjsInstance) {\n class YjsMixin extends Base {\n static callbackOptions: CallbackOptions = {};\n\n readonly document: WSSharedDoc = new WSSharedDoc();\n\n async onLoad(): Promise<YDoc | void> {\n // to be implemented by the user\n return;\n }\n\n async onSave(): Promise<void> {\n // to be implemented by the user\n }\n\n /**\n * Replaces the document with a different state using Yjs UndoManager key remapping.\n *\n * @param snapshotUpdate - The snapshot update to replace the document with.\n * @param getMetadata (optional) - A function that returns the type of the root for a given key.\n */\n unstable_replaceDocument(\n snapshotUpdate: Uint8Array,\n getMetadata: (key: string) => YjsRootType = () => \"Map\"\n ): void {\n try {\n const doc = this.document;\n const snapshotDoc = new YDoc();\n applyUpdate(snapshotDoc, snapshotUpdate, snapshotOrigin);\n\n const currentStateVector = encodeStateVector(doc);\n const snapshotStateVector = encodeStateVector(snapshotDoc);\n\n const changesSinceSnapshotUpdate = encodeStateAsUpdate(\n doc,\n snapshotStateVector\n );\n\n const undoManager = new UndoManager(\n [...snapshotDoc.share.keys()].map((key) => {\n const type = getMetadata(key);\n if (type === \"Text\") {\n return snapshotDoc.getText(key);\n } else if (type === \"Map\") {\n return snapshotDoc.getMap(key);\n } else if (type === \"Array\") {\n return snapshotDoc.getArray(key);\n } else if (type === \"XmlText\") {\n return snapshotDoc.get(key, XmlText);\n } else if (type === \"XmlElement\") {\n return snapshotDoc.get(key, XmlElement);\n } else if (type === \"XmlFragment\") {\n return snapshotDoc.get(key, XmlFragment);\n }\n throw new Error(`Unknown root type: ${type} for key: ${key}`);\n }),\n {\n trackedOrigins: new Set([snapshotOrigin])\n }\n );\n\n applyUpdate(snapshotDoc, changesSinceSnapshotUpdate, snapshotOrigin);\n undoManager.undo();\n\n const documentChangesSinceSnapshotUpdate = encodeStateAsUpdate(\n snapshotDoc,\n currentStateVector\n );\n\n applyUpdate(this.document, documentChangesSinceSnapshotUpdate);\n } catch (error) {\n throw new Error(\n `Failed to replace document: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n }\n }\n\n async onStart(): Promise<void> {\n const src = await this.onLoad();\n if (src != null) {\n const state = encodeStateAsUpdate(src);\n applyUpdate(this.document, state);\n }\n\n // Broadcast doc updates to all connections.\n // Uses this.getConnections() which works for both hibernate and non-hibernate\n // modes and survives DO hibernation (unlike an in-memory Map).\n this.document.on(\"update\", (update: Uint8Array) => {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeUpdate(encoder, update);\n const message = encoding.toUint8Array(encoder);\n for (const conn of this.getConnections()) {\n send(conn, message);\n }\n });\n\n // Track which awareness clientIDs each connection controls.\n // Stored in connection.setState() so it survives hibernation.\n // When conn is null (internal changes like removeAwarenessStates on close),\n // broadcast the update to remaining connections.\n // When conn is non-null (client message), handleMessage broadcasts directly.\n this.document.awareness.on(\n \"update\",\n (\n {\n added,\n updated,\n removed\n }: {\n added: Array<number>;\n updated: Array<number>;\n removed: Array<number>;\n },\n conn: Connection | null\n ) => {\n if (conn !== null) {\n // Track which clientIDs this connection controls\n try {\n const currentIds = new Set(getAwarenessIds(conn));\n for (const clientID of added) currentIds.add(clientID);\n for (const clientID of removed) currentIds.delete(clientID);\n setAwarenessIds(conn, [...currentIds]);\n } catch (_e) {\n // ignore — best-effort tracking\n }\n } else {\n // Internal awareness change (e.g. removeAwarenessStates on close)\n // — broadcast to all remaining connections\n const changedClients = added.concat(updated, removed);\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n this.document.awareness,\n changedClients\n )\n );\n const buff = encoding.toUint8Array(encoder);\n for (const c of this.getConnections()) {\n send(c, buff);\n }\n }\n }\n );\n\n // Debounced persistence handler\n const ctor = this.constructor as typeof YjsMixin;\n this.document.on(\n \"update\",\n debounce(\n (_update: Uint8Array, _origin: Connection, _doc: YDoc) => {\n try {\n this.onSave().catch((err) => {\n console.error(\"failed to persist:\", err);\n });\n } catch (err) {\n console.error(\"failed to persist:\", err);\n }\n },\n ctor.callbackOptions.debounceWait || CALLBACK_DEFAULTS.debounceWait,\n {\n maxWait:\n ctor.callbackOptions.debounceMaxWait ||\n CALLBACK_DEFAULTS.debounceMaxWait\n }\n )\n );\n\n // After hibernation wake-up, the doc is empty but existing connections\n // survive. Re-sync by sending sync step 1 to all connections — they'll\n // respond with sync step 2 containing their full state.\n // On first start there are no connections, so this is a no-op.\n const syncEncoder = encoding.createEncoder();\n encoding.writeVarUint(syncEncoder, messageSync);\n syncProtocol.writeSyncStep1(syncEncoder, this.document);\n const syncMessage = encoding.toUint8Array(syncEncoder);\n for (const conn of this.getConnections()) {\n send(conn, syncMessage);\n }\n }\n\n // oxlint-disable-next-line no-unused-vars\n isReadOnly(connection: Connection): boolean {\n // to be implemented by the user\n return false;\n }\n\n /**\n * Handle custom string messages from the client.\n * Override this method to implement custom message handling.\n * @param connection - The connection that sent the message\n * @param message - The custom message string (without the __YPS: prefix)\n */\n // oxlint-disable-next-line no-unused-vars\n onCustomMessage(connection: Connection, message: string): void {\n // to be implemented by the user\n console.warn(\n `Received custom message but onCustomMessage is not implemented in ${this.constructor.name}:`,\n message\n );\n }\n\n /**\n * Send a custom string message to a specific connection.\n * @param connection - The connection to send the message to\n * @param message - The custom message string to send\n */\n sendCustomMessage(connection: Connection, message: string): void {\n if (\n connection.readyState !== undefined &&\n connection.readyState !== wsReadyStateConnecting &&\n connection.readyState !== wsReadyStateOpen\n ) {\n return;\n }\n try {\n connection.send(`__YPS:${message}`);\n } catch (e) {\n console.warn(\"Failed to send custom message\", e);\n }\n }\n\n /**\n * Broadcast a custom string message to all connected clients.\n * @param message - The custom message string to broadcast\n * @param excludeConnection - Optional connection to exclude from the broadcast\n */\n broadcastCustomMessage(\n message: string,\n excludeConnection?: Connection\n ): void {\n const formattedMessage = `__YPS:${message}`;\n for (const conn of this.getConnections()) {\n if (excludeConnection && conn === excludeConnection) {\n continue;\n }\n if (\n conn.readyState !== undefined &&\n conn.readyState !== wsReadyStateConnecting &&\n conn.readyState !== wsReadyStateOpen\n ) {\n continue;\n }\n try {\n conn.send(formattedMessage);\n } catch (e) {\n console.warn(\"Failed to broadcast custom message\", e);\n }\n }\n }\n\n handleMessage(connection: Connection, message: WSMessage) {\n if (typeof message === \"string\") {\n // Handle custom messages with __YPS: prefix\n if (message.startsWith(\"__YPS:\")) {\n const customMessage = message.slice(6); // Remove __YPS: prefix\n this.onCustomMessage(connection, customMessage);\n return;\n }\n console.warn(\n `Received non-prefixed string message. Custom messages should be sent using sendMessage() on the provider.`\n );\n return;\n }\n try {\n const encoder = encoding.createEncoder();\n // Convert ArrayBuffer to Uint8Array if needed (ArrayBufferView like Uint8Array can be used directly)\n const uint8Array =\n message instanceof Uint8Array\n ? message\n : message instanceof ArrayBuffer\n ? new Uint8Array(message)\n : new Uint8Array(\n message.buffer,\n message.byteOffset,\n message.byteLength\n );\n const decoder = decoding.createDecoder(uint8Array);\n const messageType = decoding.readVarUint(decoder);\n switch (messageType) {\n case messageSync:\n encoding.writeVarUint(encoder, messageSync);\n readSyncMessage(\n decoder,\n encoder,\n this.document,\n connection,\n this.isReadOnly(connection)\n );\n\n // If the `encoder` only contains the type of reply message and no\n // message, there is no need to send the message. When `encoder` only\n // contains the type of reply, its length is 1.\n if (encoding.length(encoder) > 1) {\n send(connection, encoding.toUint8Array(encoder));\n }\n break;\n case messageAwareness: {\n const awarenessData = decoding.readVarUint8Array(decoder);\n awarenessProtocol.applyAwarenessUpdate(\n this.document.awareness,\n awarenessData,\n connection\n );\n // Forward raw awareness bytes to all connections\n const awarenessEncoder = encoding.createEncoder();\n encoding.writeVarUint(awarenessEncoder, messageAwareness);\n encoding.writeVarUint8Array(awarenessEncoder, awarenessData);\n const awarenessBuff = encoding.toUint8Array(awarenessEncoder);\n for (const c of this.getConnections()) {\n send(c, awarenessBuff);\n }\n break;\n }\n }\n } catch (err) {\n console.error(err);\n // @ts-expect-error - TODO: fix this\n this.document.emit(\"error\", [err]);\n }\n }\n\n onMessage(conn: Connection, message: WSMessage) {\n this.handleMessage(conn, message);\n }\n\n onClose(\n connection: Connection<unknown>,\n _code: number,\n _reason: string,\n _wasClean: boolean\n ): void | Promise<void> {\n // Read controlled awareness clientIDs from connection state\n // (survives hibernation unlike an in-memory Map)\n const controlledIds = getAwarenessIds(connection);\n if (controlledIds.length > 0) {\n awarenessProtocol.removeAwarenessStates(\n this.document.awareness,\n controlledIds,\n null\n );\n }\n }\n\n // TODO: explore why onError gets triggered when a connection closes\n\n onConnect(\n conn: Connection<unknown>,\n _ctx: ConnectionContext\n ): void | Promise<void> {\n // Note: awareness IDs are lazily initialized when the first awareness\n // message is received — no need to call setAwarenessIds(conn, []) here\n\n // send sync step 1\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, this.document);\n send(conn, encoding.toUint8Array(encoder));\n const awarenessStates = this.document.awareness.getStates();\n if (awarenessStates.size > 0) {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n this.document.awareness,\n Array.from(awarenessStates.keys())\n )\n );\n send(conn, encoding.toUint8Array(encoder));\n }\n }\n }\n\n return YjsMixin as unknown as TBase &\n YjsStatic &\n (new (...args: any[]) => YjsInstance);\n}\n\nexport const YServer = withYjs(Server);\n"],"mappings":";;;;;;;;;AAkBA,MAAM,iBAAiB,OAAO,kBAAkB;AAShD,MAAM,yBAAyB;AAC/B,MAAM,mBAAmB;AAMzB,MAAM,cAAc;AACpB,MAAM,mBAAmB;;;;;;AASzB,MAAM,oBAAoB;AAO1B,SAAS,gBAAgB,MAA4B;AACnD,KAAI;AAEF,SADc,KAAK,QACJ,sBAAsB,EAAE;SACjC;AACN,SAAO,EAAE;;;AAIb,SAAS,gBAAgB,MAAkB,KAAqB;AAC9D,KAAI;AACF,OAAK,UAAU,UAAyC;GACtD,GAAG;IACF,oBAAoB;GACtB,EAAE;SACG;;AAKV,IAAM,cAAN,cAA0BA,IAAK;CAC7B;CAEA,cAAc;AACZ,QAAM,EAAE,IAAI,MAAM,CAAC;AACnB,OAAK,YAAY,IAAI,kBAAkB,UAAU,KAAK;AACtD,OAAK,UAAU,cAAc,KAAK;AAMlC,gBAEI,KAAK,UAGL,eACH;;;AAIL,MAAM,oBAAoB;CACxB,cAAc;CACd,iBAAiB;CACjB,SAAS;CACV;AAED,SAAS,gBACP,SACA,SACA,KACA,mBACA,WAAW,OACX;CACA,MAAM,cAAc,SAAS,YAAY,QAAQ;AACjD,SAAQ,aAAR;EACE,KAAK,aAAa;AAChB,gBAAa,cAAc,SAAS,SAAS,IAAI;AACjD;EACF,KAAK,aAAa;AAChB,OAAI,CAAC,SACH,cAAa,cAAc,SAAS,KAAK,kBAAkB;AAC7D;EACF,KAAK,aAAa;AAChB,OAAI,CAAC,SAAU,cAAa,WAAW,SAAS,KAAK,kBAAkB;AACvE;EACF,QACE,OAAM,IAAI,MAAM,uBAAuB;;AAE3C,QAAO;;AAGT,SAAS,KAAK,MAAkB,GAAqB;AACnD,KACE,KAAK,eAAe,UACpB,KAAK,eAAe,0BACpB,KAAK,eAAe,iBAEpB;AAEF,KAAI;AACF,OAAK,KAAK,EAAE;SACN;;AAgCV,SAAgB,QACd,MAC2D;CAC3D,MAAM,iBAAiB,KAAK;EAC1B,OAAO,kBAAmC,EAAE;EAE5C,AAAS,WAAwB,IAAI,aAAa;EAElD,MAAM,SAA+B;EAKrC,MAAM,SAAwB;;;;;;;EAU9B,yBACE,gBACA,oBAAkD,OAC5C;AACN,OAAI;IACF,MAAM,MAAM,KAAK;IACjB,MAAM,cAAc,IAAIA,KAAM;AAC9B,gBAAY,aAAa,gBAAgB,eAAe;IAExD,MAAM,qBAAqB,kBAAkB,IAAI;IAGjD,MAAM,6BAA6B,oBACjC,KAH0B,kBAAkB,YAAY,CAKzD;IAED,MAAM,cAAc,IAAI,YACtB,CAAC,GAAG,YAAY,MAAM,MAAM,CAAC,CAAC,KAAK,QAAQ;KACzC,MAAM,OAAO,YAAY,IAAI;AAC7B,SAAI,SAAS,OACX,QAAO,YAAY,QAAQ,IAAI;cACtB,SAAS,MAClB,QAAO,YAAY,OAAO,IAAI;cACrB,SAAS,QAClB,QAAO,YAAY,SAAS,IAAI;cACvB,SAAS,UAClB,QAAO,YAAY,IAAI,KAAK,QAAQ;cAC3B,SAAS,aAClB,QAAO,YAAY,IAAI,KAAK,WAAW;cAC9B,SAAS,cAClB,QAAO,YAAY,IAAI,KAAK,YAAY;AAE1C,WAAM,IAAI,MAAM,sBAAsB,KAAK,YAAY,MAAM;MAC7D,EACF,EACE,gBAAgB,IAAI,IAAI,CAAC,eAAe,CAAC,EAC1C,CACF;AAED,gBAAY,aAAa,4BAA4B,eAAe;AACpE,gBAAY,MAAM;IAElB,MAAM,qCAAqC,oBACzC,aACA,mBACD;AAED,gBAAY,KAAK,UAAU,mCAAmC;YACvD,OAAO;AACd,UAAM,IAAI,MACR,+BAA+B,iBAAiB,QAAQ,MAAM,UAAU,kBACzE;;;EAIL,MAAM,UAAyB;GAC7B,MAAM,MAAM,MAAM,KAAK,QAAQ;AAC/B,OAAI,OAAO,MAAM;IACf,MAAM,QAAQ,oBAAoB,IAAI;AACtC,gBAAY,KAAK,UAAU,MAAM;;AAMnC,QAAK,SAAS,GAAG,WAAW,WAAuB;IACjD,MAAM,UAAU,SAAS,eAAe;AACxC,aAAS,aAAa,SAAS,YAAY;AAC3C,iBAAa,YAAY,SAAS,OAAO;IACzC,MAAM,UAAU,SAAS,aAAa,QAAQ;AAC9C,SAAK,MAAM,QAAQ,KAAK,gBAAgB,CACtC,MAAK,MAAM,QAAQ;KAErB;AAOF,QAAK,SAAS,UAAU,GACtB,WAEE,EACE,OACA,SACA,WAMF,SACG;AACH,QAAI,SAAS,KAEX,KAAI;KACF,MAAM,aAAa,IAAI,IAAI,gBAAgB,KAAK,CAAC;AACjD,UAAK,MAAM,YAAY,MAAO,YAAW,IAAI,SAAS;AACtD,UAAK,MAAM,YAAY,QAAS,YAAW,OAAO,SAAS;AAC3D,qBAAgB,MAAM,CAAC,GAAG,WAAW,CAAC;aAC/B,IAAI;SAGR;KAGL,MAAM,iBAAiB,MAAM,OAAO,SAAS,QAAQ;KACrD,MAAM,UAAU,SAAS,eAAe;AACxC,cAAS,aAAa,SAAS,iBAAiB;AAChD,cAAS,mBACP,SACA,kBAAkB,sBAChB,KAAK,SAAS,WACd,eACD,CACF;KACD,MAAM,OAAO,SAAS,aAAa,QAAQ;AAC3C,UAAK,MAAM,KAAK,KAAK,gBAAgB,CACnC,MAAK,GAAG,KAAK;;KAIpB;GAGD,MAAM,OAAO,KAAK;AAClB,QAAK,SAAS,GACZ,UACA,UACG,SAAqB,SAAqB,SAAe;AACxD,QAAI;AACF,UAAK,QAAQ,CAAC,OAAO,QAAQ;AAC3B,cAAQ,MAAM,sBAAsB,IAAI;OACxC;aACK,KAAK;AACZ,aAAQ,MAAM,sBAAsB,IAAI;;MAG5C,KAAK,gBAAgB,gBAAgB,kBAAkB,cACvD,EACE,SACE,KAAK,gBAAgB,mBACrB,kBAAkB,iBACrB,CACF,CACF;GAMD,MAAM,cAAc,SAAS,eAAe;AAC5C,YAAS,aAAa,aAAa,YAAY;AAC/C,gBAAa,eAAe,aAAa,KAAK,SAAS;GACvD,MAAM,cAAc,SAAS,aAAa,YAAY;AACtD,QAAK,MAAM,QAAQ,KAAK,gBAAgB,CACtC,MAAK,MAAM,YAAY;;EAK3B,WAAW,YAAiC;AAE1C,UAAO;;;;;;;;EAUT,gBAAgB,YAAwB,SAAuB;AAE7D,WAAQ,KACN,qEAAqE,KAAK,YAAY,KAAK,IAC3F,QACD;;;;;;;EAQH,kBAAkB,YAAwB,SAAuB;AAC/D,OACE,WAAW,eAAe,UAC1B,WAAW,eAAe,0BAC1B,WAAW,eAAe,iBAE1B;AAEF,OAAI;AACF,eAAW,KAAK,SAAS,UAAU;YAC5B,GAAG;AACV,YAAQ,KAAK,iCAAiC,EAAE;;;;;;;;EASpD,uBACE,SACA,mBACM;GACN,MAAM,mBAAmB,SAAS;AAClC,QAAK,MAAM,QAAQ,KAAK,gBAAgB,EAAE;AACxC,QAAI,qBAAqB,SAAS,kBAChC;AAEF,QACE,KAAK,eAAe,UACpB,KAAK,eAAe,0BACpB,KAAK,eAAe,iBAEpB;AAEF,QAAI;AACF,UAAK,KAAK,iBAAiB;aACpB,GAAG;AACV,aAAQ,KAAK,sCAAsC,EAAE;;;;EAK3D,cAAc,YAAwB,SAAoB;AACxD,OAAI,OAAO,YAAY,UAAU;AAE/B,QAAI,QAAQ,WAAW,SAAS,EAAE;KAChC,MAAM,gBAAgB,QAAQ,MAAM,EAAE;AACtC,UAAK,gBAAgB,YAAY,cAAc;AAC/C;;AAEF,YAAQ,KACN,4GACD;AACD;;AAEF,OAAI;IACF,MAAM,UAAU,SAAS,eAAe;IAExC,MAAM,aACJ,mBAAmB,aACf,UACA,mBAAmB,cACjB,IAAI,WAAW,QAAQ,GACvB,IAAI,WACF,QAAQ,QACR,QAAQ,YACR,QAAQ,WACT;IACT,MAAM,UAAU,SAAS,cAAc,WAAW;AAElD,YADoB,SAAS,YAAY,QAAQ,EACjD;KACE,KAAK;AACH,eAAS,aAAa,SAAS,YAAY;AAC3C,sBACE,SACA,SACA,KAAK,UACL,YACA,KAAK,WAAW,WAAW,CAC5B;AAKD,UAAI,SAAS,OAAO,QAAQ,GAAG,EAC7B,MAAK,YAAY,SAAS,aAAa,QAAQ,CAAC;AAElD;KACF,KAAK,kBAAkB;MACrB,MAAM,gBAAgB,SAAS,kBAAkB,QAAQ;AACzD,wBAAkB,qBAChB,KAAK,SAAS,WACd,eACA,WACD;MAED,MAAM,mBAAmB,SAAS,eAAe;AACjD,eAAS,aAAa,kBAAkB,iBAAiB;AACzD,eAAS,mBAAmB,kBAAkB,cAAc;MAC5D,MAAM,gBAAgB,SAAS,aAAa,iBAAiB;AAC7D,WAAK,MAAM,KAAK,KAAK,gBAAgB,CACnC,MAAK,GAAG,cAAc;AAExB;;;YAGG,KAAK;AACZ,YAAQ,MAAM,IAAI;AAElB,SAAK,SAAS,KAAK,SAAS,CAAC,IAAI,CAAC;;;EAItC,UAAU,MAAkB,SAAoB;AAC9C,QAAK,cAAc,MAAM,QAAQ;;EAGnC,QACE,YACA,OACA,SACA,WACsB;GAGtB,MAAM,gBAAgB,gBAAgB,WAAW;AACjD,OAAI,cAAc,SAAS,EACzB,mBAAkB,sBAChB,KAAK,SAAS,WACd,eACA,KACD;;EAML,UACE,MACA,MACsB;GAKtB,MAAM,UAAU,SAAS,eAAe;AACxC,YAAS,aAAa,SAAS,YAAY;AAC3C,gBAAa,eAAe,SAAS,KAAK,SAAS;AACnD,QAAK,MAAM,SAAS,aAAa,QAAQ,CAAC;GAC1C,MAAM,kBAAkB,KAAK,SAAS,UAAU,WAAW;AAC3D,OAAI,gBAAgB,OAAO,GAAG;IAC5B,MAAM,UAAU,SAAS,eAAe;AACxC,aAAS,aAAa,SAAS,iBAAiB;AAChD,aAAS,mBACP,SACA,kBAAkB,sBAChB,KAAK,SAAS,WACd,MAAM,KAAK,gBAAgB,MAAM,CAAC,CACnC,CACF;AACD,SAAK,MAAM,SAAS,aAAa,QAAQ,CAAC;;;;AAKhD,QAAO;;AAKT,MAAa,UAAU,QAAQ,OAAO"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["YDoc"],"sources":["../../src/server/index.ts"],"sourcesContent":["import * as decoding from \"lib0/decoding\";\nimport * as encoding from \"lib0/encoding\";\nimport debounce from \"lodash.debounce\";\nimport type { Connection, ConnectionContext, WSMessage } from \"partyserver\";\nimport { Server } from \"partyserver\";\nimport * as awarenessProtocol from \"y-protocols/awareness\";\nimport * as syncProtocol from \"y-protocols/sync\";\nimport {\n applyUpdate,\n Doc as YDoc,\n encodeStateAsUpdate,\n encodeStateVector,\n UndoManager,\n XmlText,\n XmlElement,\n XmlFragment\n} from \"yjs\";\n\nconst snapshotOrigin = Symbol(\"snapshot-origin\");\ntype YjsRootType =\n | \"Text\"\n | \"Map\"\n | \"Array\"\n | \"XmlText\"\n | \"XmlElement\"\n | \"XmlFragment\";\n\nconst wsReadyStateConnecting = 0;\nconst wsReadyStateOpen = 1;\n// oxlint-disable-next-line no-unused-vars\nconst wsReadyStateClosing = 2;\n// oxlint-disable-next-line no-unused-vars\nconst wsReadyStateClosed = 3;\n\nconst messageSync = 0;\nconst messageAwareness = 1;\n// oxlint-disable-next-line no-unused-vars\nconst messageAuth = 2;\n\n/**\n * Internal key used in connection.setState() to track which awareness\n * client IDs are controlled by each connection. This survives hibernation\n * because connection state is persisted to WebSocket attachments.\n */\nconst AWARENESS_IDS_KEY = \"__ypsAwarenessIds\";\n\ntype YServerConnectionState = {\n [AWARENESS_IDS_KEY]?: number[];\n [key: string]: unknown;\n};\n\nfunction getAwarenessIds(conn: Connection): number[] {\n try {\n const state = conn.state as YServerConnectionState | null;\n return state?.[AWARENESS_IDS_KEY] ?? [];\n } catch {\n return [];\n }\n}\n\nfunction setAwarenessIds(conn: Connection, ids: number[]): void {\n try {\n conn.setState((prev: YServerConnectionState | null) => ({\n ...prev,\n [AWARENESS_IDS_KEY]: ids\n }));\n } catch {\n // ignore — may fail if connection is already closed\n }\n}\n\nclass WSSharedDoc extends YDoc {\n awareness: awarenessProtocol.Awareness;\n\n constructor() {\n super({ gc: true });\n this.awareness = new awarenessProtocol.Awareness(this);\n this.awareness.setLocalState(null);\n\n // Disable the awareness protocol's built-in check interval.\n // It renews the local clock every 15s and removes peers after 30s,\n // but we handle peer cleanup via onClose instead. Clearing it here\n // prevents it from defeating Durable Object hibernation.\n clearInterval(\n (\n this.awareness as unknown as {\n _checkInterval: ReturnType<typeof setInterval>;\n }\n )._checkInterval\n );\n }\n}\n\nconst CALLBACK_DEFAULTS = {\n debounceWait: 2000,\n debounceMaxWait: 10000,\n timeout: 5000\n};\n\nfunction readSyncMessage(\n decoder: decoding.Decoder,\n encoder: encoding.Encoder,\n doc: YDoc,\n transactionOrigin: Connection,\n readOnly = false\n) {\n const messageType = decoding.readVarUint(decoder);\n switch (messageType) {\n case syncProtocol.messageYjsSyncStep1:\n syncProtocol.readSyncStep1(decoder, encoder, doc);\n break;\n case syncProtocol.messageYjsSyncStep2:\n if (!readOnly)\n syncProtocol.readSyncStep2(decoder, doc, transactionOrigin);\n break;\n case syncProtocol.messageYjsUpdate:\n if (!readOnly) syncProtocol.readUpdate(decoder, doc, transactionOrigin);\n break;\n default:\n throw new Error(\"Unknown message type\");\n }\n return messageType;\n}\n\nfunction send(conn: Connection, m: Uint8Array): void {\n if (\n conn.readyState !== undefined &&\n conn.readyState !== wsReadyStateConnecting &&\n conn.readyState !== wsReadyStateOpen\n ) {\n return;\n }\n try {\n conn.send(m);\n } catch {\n // connection is broken, ignore\n }\n}\n\nexport interface CallbackOptions {\n debounceWait?: number;\n debounceMaxWait?: number;\n timeout?: number;\n}\n\ntype ServerClass = new (...args: any[]) => Server;\n\nexport interface YjsInstance {\n readonly document: WSSharedDoc;\n onLoad(): Promise<YDoc | void>;\n onSave(): Promise<void>;\n unstable_replaceDocument(\n snapshotUpdate: Uint8Array,\n getMetadata?: (key: string) => YjsRootType\n ): void;\n isReadOnly(connection: Connection): boolean;\n onCustomMessage(connection: Connection, message: string): void;\n sendCustomMessage(connection: Connection, message: string): void;\n broadcastCustomMessage(message: string, excludeConnection?: Connection): void;\n handleMessage(connection: Connection, message: WSMessage): void;\n}\n\nexport interface YjsStatic {\n callbackOptions: CallbackOptions;\n}\n\nexport function withYjs<TBase extends ServerClass>(\n Base: TBase\n): TBase & YjsStatic & (new (...args: any[]) => YjsInstance) {\n class YjsMixin extends Base {\n static callbackOptions: CallbackOptions = {};\n\n readonly document: WSSharedDoc = new WSSharedDoc();\n\n async onLoad(): Promise<YDoc | void> {\n // to be implemented by the user\n return;\n }\n\n async onSave(): Promise<void> {\n // to be implemented by the user\n }\n\n /**\n * Replaces the document with a different state using Yjs UndoManager key remapping.\n *\n * @param snapshotUpdate - The snapshot update to replace the document with.\n * @param getMetadata (optional) - A function that returns the type of the root for a given key.\n */\n unstable_replaceDocument(\n snapshotUpdate: Uint8Array,\n getMetadata: (key: string) => YjsRootType = () => \"Map\"\n ): void {\n try {\n const doc = this.document;\n const snapshotDoc = new YDoc();\n applyUpdate(snapshotDoc, snapshotUpdate, snapshotOrigin);\n\n const currentStateVector = encodeStateVector(doc);\n const snapshotStateVector = encodeStateVector(snapshotDoc);\n\n const changesSinceSnapshotUpdate = encodeStateAsUpdate(\n doc,\n snapshotStateVector\n );\n\n const undoManager = new UndoManager(\n [...snapshotDoc.share.keys()].map((key) => {\n const type = getMetadata(key);\n if (type === \"Text\") {\n return snapshotDoc.getText(key);\n } else if (type === \"Map\") {\n return snapshotDoc.getMap(key);\n } else if (type === \"Array\") {\n return snapshotDoc.getArray(key);\n } else if (type === \"XmlText\") {\n return snapshotDoc.get(key, XmlText);\n } else if (type === \"XmlElement\") {\n return snapshotDoc.get(key, XmlElement);\n } else if (type === \"XmlFragment\") {\n return snapshotDoc.get(key, XmlFragment);\n }\n throw new Error(`Unknown root type: ${type} for key: ${key}`);\n }),\n {\n trackedOrigins: new Set([snapshotOrigin])\n }\n );\n\n applyUpdate(snapshotDoc, changesSinceSnapshotUpdate, snapshotOrigin);\n undoManager.undo();\n\n const documentChangesSinceSnapshotUpdate = encodeStateAsUpdate(\n snapshotDoc,\n currentStateVector\n );\n\n applyUpdate(this.document, documentChangesSinceSnapshotUpdate);\n } catch (error) {\n throw new Error(\n `Failed to replace document: ${error instanceof Error ? error.message : \"Unknown error\"}`\n );\n }\n }\n\n async onStart(): Promise<void> {\n const src = await this.onLoad();\n if (src != null) {\n const state = encodeStateAsUpdate(src);\n applyUpdate(this.document, state);\n }\n\n // Broadcast doc updates to all connections.\n // Uses this.getConnections() which works for both hibernate and non-hibernate\n // modes and survives DO hibernation (unlike an in-memory Map).\n this.document.on(\"update\", (update: Uint8Array) => {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeUpdate(encoder, update);\n const message = encoding.toUint8Array(encoder);\n for (const conn of this.getConnections()) {\n send(conn, message);\n }\n });\n\n // Track which awareness clientIDs each connection controls.\n // Stored in connection.setState() so it survives hibernation.\n // When conn is null (internal changes like removeAwarenessStates on close),\n // broadcast the update to remaining connections.\n // When conn is non-null (client message), handleMessage broadcasts directly.\n this.document.awareness.on(\n \"update\",\n (\n {\n added,\n updated,\n removed\n }: {\n added: Array<number>;\n updated: Array<number>;\n removed: Array<number>;\n },\n conn: Connection | null\n ) => {\n if (conn !== null) {\n // Track which clientIDs this connection controls\n try {\n const currentIds = new Set(getAwarenessIds(conn));\n for (const clientID of added) currentIds.add(clientID);\n for (const clientID of removed) currentIds.delete(clientID);\n setAwarenessIds(conn, [...currentIds]);\n } catch (_e) {\n // ignore — best-effort tracking\n }\n } else {\n // Internal awareness change (e.g. removeAwarenessStates on close)\n // — broadcast to all remaining connections\n const changedClients = added.concat(updated, removed);\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n this.document.awareness,\n changedClients\n )\n );\n const buff = encoding.toUint8Array(encoder);\n for (const c of this.getConnections()) {\n send(c, buff);\n }\n }\n }\n );\n\n // Debounced persistence handler\n const ctor = this.constructor as typeof YjsMixin;\n this.document.on(\n \"update\",\n debounce(\n (_update: Uint8Array, _origin: Connection, _doc: YDoc) => {\n try {\n this.onSave().catch((err) => {\n console.error(\"failed to persist:\", err);\n });\n } catch (err) {\n console.error(\"failed to persist:\", err);\n }\n },\n ctor.callbackOptions.debounceWait || CALLBACK_DEFAULTS.debounceWait,\n {\n maxWait:\n ctor.callbackOptions.debounceMaxWait ||\n CALLBACK_DEFAULTS.debounceMaxWait\n }\n )\n );\n\n // After hibernation wake-up, the doc is empty but existing connections\n // survive. Re-sync by sending sync step 1 to all connections — they'll\n // respond with sync step 2 containing their full state.\n // On first start there are no connections, so this is a no-op.\n const syncEncoder = encoding.createEncoder();\n encoding.writeVarUint(syncEncoder, messageSync);\n syncProtocol.writeSyncStep1(syncEncoder, this.document);\n const syncMessage = encoding.toUint8Array(syncEncoder);\n for (const conn of this.getConnections()) {\n send(conn, syncMessage);\n }\n }\n\n // oxlint-disable-next-line no-unused-vars\n isReadOnly(connection: Connection): boolean {\n // to be implemented by the user\n return false;\n }\n\n /**\n * Handle custom string messages from the client.\n * Override this method to implement custom message handling.\n * @param connection - The connection that sent the message\n * @param message - The custom message string (without the __YPS: prefix)\n */\n // oxlint-disable-next-line no-unused-vars\n onCustomMessage(connection: Connection, message: string): void {\n // to be implemented by the user\n console.warn(\n `Received custom message but onCustomMessage is not implemented in ${this.constructor.name}:`,\n message\n );\n }\n\n /**\n * Send a custom string message to a specific connection.\n * @param connection - The connection to send the message to\n * @param message - The custom message string to send\n */\n sendCustomMessage(connection: Connection, message: string): void {\n if (\n connection.readyState !== undefined &&\n connection.readyState !== wsReadyStateConnecting &&\n connection.readyState !== wsReadyStateOpen\n ) {\n return;\n }\n try {\n connection.send(`__YPS:${message}`);\n } catch (e) {\n console.warn(\"Failed to send custom message\", e);\n }\n }\n\n /**\n * Broadcast a custom string message to all connected clients.\n * @param message - The custom message string to broadcast\n * @param excludeConnection - Optional connection to exclude from the broadcast\n */\n broadcastCustomMessage(\n message: string,\n excludeConnection?: Connection\n ): void {\n const formattedMessage = `__YPS:${message}`;\n for (const conn of this.getConnections()) {\n if (excludeConnection && conn === excludeConnection) {\n continue;\n }\n if (\n conn.readyState !== undefined &&\n conn.readyState !== wsReadyStateConnecting &&\n conn.readyState !== wsReadyStateOpen\n ) {\n continue;\n }\n try {\n conn.send(formattedMessage);\n } catch (e) {\n console.warn(\"Failed to broadcast custom message\", e);\n }\n }\n }\n\n handleMessage(connection: Connection, message: WSMessage) {\n if (typeof message === \"string\") {\n // Handle custom messages with __YPS: prefix\n if (message.startsWith(\"__YPS:\")) {\n const customMessage = message.slice(6); // Remove __YPS: prefix\n this.onCustomMessage(connection, customMessage);\n return;\n }\n console.warn(\n `Received non-prefixed string message. Custom messages should be sent using sendMessage() on the provider.`\n );\n return;\n }\n try {\n const encoder = encoding.createEncoder();\n // Convert ArrayBuffer to Uint8Array if needed (ArrayBufferView like Uint8Array can be used directly)\n const uint8Array =\n message instanceof Uint8Array\n ? message\n : message instanceof ArrayBuffer\n ? new Uint8Array(message)\n : new Uint8Array(\n message.buffer,\n message.byteOffset,\n message.byteLength\n );\n const decoder = decoding.createDecoder(uint8Array);\n const messageType = decoding.readVarUint(decoder);\n switch (messageType) {\n case messageSync:\n encoding.writeVarUint(encoder, messageSync);\n readSyncMessage(\n decoder,\n encoder,\n this.document,\n connection,\n this.isReadOnly(connection)\n );\n\n // If the `encoder` only contains the type of reply message and no\n // message, there is no need to send the message. When `encoder` only\n // contains the type of reply, its length is 1.\n if (encoding.length(encoder) > 1) {\n send(connection, encoding.toUint8Array(encoder));\n }\n break;\n case messageAwareness: {\n const awarenessData = decoding.readVarUint8Array(decoder);\n awarenessProtocol.applyAwarenessUpdate(\n this.document.awareness,\n awarenessData,\n connection\n );\n // Forward raw awareness bytes to all connections\n const awarenessEncoder = encoding.createEncoder();\n encoding.writeVarUint(awarenessEncoder, messageAwareness);\n encoding.writeVarUint8Array(awarenessEncoder, awarenessData);\n const awarenessBuff = encoding.toUint8Array(awarenessEncoder);\n for (const c of this.getConnections()) {\n send(c, awarenessBuff);\n }\n break;\n }\n }\n } catch (err) {\n console.error(err);\n // @ts-expect-error - TODO: fix this\n this.document.emit(\"error\", [err]);\n }\n }\n\n onMessage(conn: Connection, message: WSMessage) {\n this.handleMessage(conn, message);\n }\n\n onClose(\n connection: Connection<unknown>,\n _code: number,\n _reason: string,\n _wasClean: boolean\n ): void | Promise<void> {\n // Read controlled awareness clientIDs from connection state\n // (survives hibernation unlike an in-memory Map)\n const controlledIds = getAwarenessIds(connection);\n if (controlledIds.length > 0) {\n awarenessProtocol.removeAwarenessStates(\n this.document.awareness,\n controlledIds,\n null\n );\n }\n }\n\n // TODO: explore why onError gets triggered when a connection closes\n\n onConnect(\n conn: Connection<unknown>,\n _ctx: ConnectionContext\n ): void | Promise<void> {\n // Note: awareness IDs are lazily initialized when the first awareness\n // message is received — no need to call setAwarenessIds(conn, []) here\n\n // send sync step 1\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, this.document);\n send(conn, encoding.toUint8Array(encoder));\n const awarenessStates = this.document.awareness.getStates();\n if (awarenessStates.size > 0) {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n this.document.awareness,\n Array.from(awarenessStates.keys())\n )\n );\n send(conn, encoding.toUint8Array(encoder));\n }\n }\n }\n\n return YjsMixin as unknown as TBase &\n YjsStatic &\n (new (...args: any[]) => YjsInstance);\n}\n\nexport const YServer = withYjs(Server);\n"],"mappings":";;;;;;;;AAkBA,MAAM,iBAAiB,OAAO,kBAAkB;AAShD,MAAM,yBAAyB;AAC/B,MAAM,mBAAmB;AAMzB,MAAM,cAAc;AACpB,MAAM,mBAAmB;;;;;;AASzB,MAAM,oBAAoB;AAO1B,SAAS,gBAAgB,MAA4B;AACnD,KAAI;AAEF,SADc,KAAK,QACJ,sBAAsB,EAAE;SACjC;AACN,SAAO,EAAE;;;AAIb,SAAS,gBAAgB,MAAkB,KAAqB;AAC9D,KAAI;AACF,OAAK,UAAU,UAAyC;GACtD,GAAG;IACF,oBAAoB;GACtB,EAAE;SACG;;AAKV,IAAM,cAAN,cAA0BA,IAAK;CAC7B;CAEA,cAAc;AACZ,QAAM,EAAE,IAAI,MAAM,CAAC;AACnB,OAAK,YAAY,IAAI,kBAAkB,UAAU,KAAK;AACtD,OAAK,UAAU,cAAc,KAAK;AAMlC,gBAEI,KAAK,UAGL,eACH;;;AAIL,MAAM,oBAAoB;CACxB,cAAc;CACd,iBAAiB;CACjB,SAAS;CACV;AAED,SAAS,gBACP,SACA,SACA,KACA,mBACA,WAAW,OACX;CACA,MAAM,cAAc,SAAS,YAAY,QAAQ;AACjD,SAAQ,aAAR;EACE,KAAK,aAAa;AAChB,gBAAa,cAAc,SAAS,SAAS,IAAI;AACjD;EACF,KAAK,aAAa;AAChB,OAAI,CAAC,SACH,cAAa,cAAc,SAAS,KAAK,kBAAkB;AAC7D;EACF,KAAK,aAAa;AAChB,OAAI,CAAC,SAAU,cAAa,WAAW,SAAS,KAAK,kBAAkB;AACvE;EACF,QACE,OAAM,IAAI,MAAM,uBAAuB;;AAE3C,QAAO;;AAGT,SAAS,KAAK,MAAkB,GAAqB;AACnD,KACE,KAAK,eAAe,KAAA,KACpB,KAAK,eAAe,0BACpB,KAAK,eAAe,iBAEpB;AAEF,KAAI;AACF,OAAK,KAAK,EAAE;SACN;;AAgCV,SAAgB,QACd,MAC2D;CAC3D,MAAM,iBAAiB,KAAK;EAC1B,OAAO,kBAAmC,EAAE;EAE5C,WAAiC,IAAI,aAAa;EAElD,MAAM,SAA+B;EAKrC,MAAM,SAAwB;;;;;;;EAU9B,yBACE,gBACA,oBAAkD,OAC5C;AACN,OAAI;IACF,MAAM,MAAM,KAAK;IACjB,MAAM,cAAc,IAAIA,KAAM;AAC9B,gBAAY,aAAa,gBAAgB,eAAe;IAExD,MAAM,qBAAqB,kBAAkB,IAAI;IAGjD,MAAM,6BAA6B,oBACjC,KAH0B,kBAAkB,YAIzB,CACpB;IAED,MAAM,cAAc,IAAI,YACtB,CAAC,GAAG,YAAY,MAAM,MAAM,CAAC,CAAC,KAAK,QAAQ;KACzC,MAAM,OAAO,YAAY,IAAI;AAC7B,SAAI,SAAS,OACX,QAAO,YAAY,QAAQ,IAAI;cACtB,SAAS,MAClB,QAAO,YAAY,OAAO,IAAI;cACrB,SAAS,QAClB,QAAO,YAAY,SAAS,IAAI;cACvB,SAAS,UAClB,QAAO,YAAY,IAAI,KAAK,QAAQ;cAC3B,SAAS,aAClB,QAAO,YAAY,IAAI,KAAK,WAAW;cAC9B,SAAS,cAClB,QAAO,YAAY,IAAI,KAAK,YAAY;AAE1C,WAAM,IAAI,MAAM,sBAAsB,KAAK,YAAY,MAAM;MAC7D,EACF,EACE,gBAAgB,IAAI,IAAI,CAAC,eAAe,CAAC,EAC1C,CACF;AAED,gBAAY,aAAa,4BAA4B,eAAe;AACpE,gBAAY,MAAM;IAElB,MAAM,qCAAqC,oBACzC,aACA,mBACD;AAED,gBAAY,KAAK,UAAU,mCAAmC;YACvD,OAAO;AACd,UAAM,IAAI,MACR,+BAA+B,iBAAiB,QAAQ,MAAM,UAAU,kBACzE;;;EAIL,MAAM,UAAyB;GAC7B,MAAM,MAAM,MAAM,KAAK,QAAQ;AAC/B,OAAI,OAAO,MAAM;IACf,MAAM,QAAQ,oBAAoB,IAAI;AACtC,gBAAY,KAAK,UAAU,MAAM;;AAMnC,QAAK,SAAS,GAAG,WAAW,WAAuB;IACjD,MAAM,UAAU,SAAS,eAAe;AACxC,aAAS,aAAa,SAAS,YAAY;AAC3C,iBAAa,YAAY,SAAS,OAAO;IACzC,MAAM,UAAU,SAAS,aAAa,QAAQ;AAC9C,SAAK,MAAM,QAAQ,KAAK,gBAAgB,CACtC,MAAK,MAAM,QAAQ;KAErB;AAOF,QAAK,SAAS,UAAU,GACtB,WAEE,EACE,OACA,SACA,WAMF,SACG;AACH,QAAI,SAAS,KAEX,KAAI;KACF,MAAM,aAAa,IAAI,IAAI,gBAAgB,KAAK,CAAC;AACjD,UAAK,MAAM,YAAY,MAAO,YAAW,IAAI,SAAS;AACtD,UAAK,MAAM,YAAY,QAAS,YAAW,OAAO,SAAS;AAC3D,qBAAgB,MAAM,CAAC,GAAG,WAAW,CAAC;aAC/B,IAAI;SAGR;KAGL,MAAM,iBAAiB,MAAM,OAAO,SAAS,QAAQ;KACrD,MAAM,UAAU,SAAS,eAAe;AACxC,cAAS,aAAa,SAAS,iBAAiB;AAChD,cAAS,mBACP,SACA,kBAAkB,sBAChB,KAAK,SAAS,WACd,eACD,CACF;KACD,MAAM,OAAO,SAAS,aAAa,QAAQ;AAC3C,UAAK,MAAM,KAAK,KAAK,gBAAgB,CACnC,MAAK,GAAG,KAAK;;KAIpB;GAGD,MAAM,OAAO,KAAK;AAClB,QAAK,SAAS,GACZ,UACA,UACG,SAAqB,SAAqB,SAAe;AACxD,QAAI;AACF,UAAK,QAAQ,CAAC,OAAO,QAAQ;AAC3B,cAAQ,MAAM,sBAAsB,IAAI;OACxC;aACK,KAAK;AACZ,aAAQ,MAAM,sBAAsB,IAAI;;MAG5C,KAAK,gBAAgB,gBAAgB,kBAAkB,cACvD,EACE,SACE,KAAK,gBAAgB,mBACrB,kBAAkB,iBACrB,CACF,CACF;GAMD,MAAM,cAAc,SAAS,eAAe;AAC5C,YAAS,aAAa,aAAa,YAAY;AAC/C,gBAAa,eAAe,aAAa,KAAK,SAAS;GACvD,MAAM,cAAc,SAAS,aAAa,YAAY;AACtD,QAAK,MAAM,QAAQ,KAAK,gBAAgB,CACtC,MAAK,MAAM,YAAY;;EAK3B,WAAW,YAAiC;AAE1C,UAAO;;;;;;;;EAUT,gBAAgB,YAAwB,SAAuB;AAE7D,WAAQ,KACN,qEAAqE,KAAK,YAAY,KAAK,IAC3F,QACD;;;;;;;EAQH,kBAAkB,YAAwB,SAAuB;AAC/D,OACE,WAAW,eAAe,KAAA,KAC1B,WAAW,eAAe,0BAC1B,WAAW,eAAe,iBAE1B;AAEF,OAAI;AACF,eAAW,KAAK,SAAS,UAAU;YAC5B,GAAG;AACV,YAAQ,KAAK,iCAAiC,EAAE;;;;;;;;EASpD,uBACE,SACA,mBACM;GACN,MAAM,mBAAmB,SAAS;AAClC,QAAK,MAAM,QAAQ,KAAK,gBAAgB,EAAE;AACxC,QAAI,qBAAqB,SAAS,kBAChC;AAEF,QACE,KAAK,eAAe,KAAA,KACpB,KAAK,eAAe,0BACpB,KAAK,eAAe,iBAEpB;AAEF,QAAI;AACF,UAAK,KAAK,iBAAiB;aACpB,GAAG;AACV,aAAQ,KAAK,sCAAsC,EAAE;;;;EAK3D,cAAc,YAAwB,SAAoB;AACxD,OAAI,OAAO,YAAY,UAAU;AAE/B,QAAI,QAAQ,WAAW,SAAS,EAAE;KAChC,MAAM,gBAAgB,QAAQ,MAAM,EAAE;AACtC,UAAK,gBAAgB,YAAY,cAAc;AAC/C;;AAEF,YAAQ,KACN,4GACD;AACD;;AAEF,OAAI;IACF,MAAM,UAAU,SAAS,eAAe;IAExC,MAAM,aACJ,mBAAmB,aACf,UACA,mBAAmB,cACjB,IAAI,WAAW,QAAQ,GACvB,IAAI,WACF,QAAQ,QACR,QAAQ,YACR,QAAQ,WACT;IACT,MAAM,UAAU,SAAS,cAAc,WAAW;AAElD,YADoB,SAAS,YAAY,QACtB,EAAnB;KACE,KAAK;AACH,eAAS,aAAa,SAAS,YAAY;AAC3C,sBACE,SACA,SACA,KAAK,UACL,YACA,KAAK,WAAW,WAAW,CAC5B;AAKD,UAAI,SAAS,OAAO,QAAQ,GAAG,EAC7B,MAAK,YAAY,SAAS,aAAa,QAAQ,CAAC;AAElD;KACF,KAAK,kBAAkB;MACrB,MAAM,gBAAgB,SAAS,kBAAkB,QAAQ;AACzD,wBAAkB,qBAChB,KAAK,SAAS,WACd,eACA,WACD;MAED,MAAM,mBAAmB,SAAS,eAAe;AACjD,eAAS,aAAa,kBAAkB,iBAAiB;AACzD,eAAS,mBAAmB,kBAAkB,cAAc;MAC5D,MAAM,gBAAgB,SAAS,aAAa,iBAAiB;AAC7D,WAAK,MAAM,KAAK,KAAK,gBAAgB,CACnC,MAAK,GAAG,cAAc;AAExB;;;YAGG,KAAK;AACZ,YAAQ,MAAM,IAAI;AAElB,SAAK,SAAS,KAAK,SAAS,CAAC,IAAI,CAAC;;;EAItC,UAAU,MAAkB,SAAoB;AAC9C,QAAK,cAAc,MAAM,QAAQ;;EAGnC,QACE,YACA,OACA,SACA,WACsB;GAGtB,MAAM,gBAAgB,gBAAgB,WAAW;AACjD,OAAI,cAAc,SAAS,EACzB,mBAAkB,sBAChB,KAAK,SAAS,WACd,eACA,KACD;;EAML,UACE,MACA,MACsB;GAKtB,MAAM,UAAU,SAAS,eAAe;AACxC,YAAS,aAAa,SAAS,YAAY;AAC3C,gBAAa,eAAe,SAAS,KAAK,SAAS;AACnD,QAAK,MAAM,SAAS,aAAa,QAAQ,CAAC;GAC1C,MAAM,kBAAkB,KAAK,SAAS,UAAU,WAAW;AAC3D,OAAI,gBAAgB,OAAO,GAAG;IAC5B,MAAM,UAAU,SAAS,eAAe;AACxC,aAAS,aAAa,SAAS,iBAAiB;AAChD,aAAS,mBACP,SACA,kBAAkB,sBAChB,KAAK,SAAS,WACd,MAAM,KAAK,gBAAgB,MAAM,CAAC,CACnC,CACF;AACD,SAAK,MAAM,SAAS,aAAa,QAAQ,CAAC;;;;AAKhD,QAAO;;AAKT,MAAa,UAAU,QAAQ,OAAO"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "y-partyserver",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"collaboration",
|
|
@@ -58,18 +58,19 @@
|
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"lib0": "^0.2.117",
|
|
60
60
|
"lodash.debounce": "^4.0.8",
|
|
61
|
-
"nanoid": "^5.1.
|
|
61
|
+
"nanoid": "^5.1.9",
|
|
62
62
|
"y-protocols": "^1.0.7"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@cloudflare/workers-types": "^4.
|
|
65
|
+
"@cloudflare/workers-types": "^4.20260424.1",
|
|
66
66
|
"@types/lodash.debounce": "^4.0.9",
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
67
|
+
"@types/node": "25.6.0",
|
|
68
|
+
"partyserver": "^0.5.0",
|
|
69
|
+
"ws": "^8.20.0",
|
|
70
|
+
"yjs": "^13.6.30"
|
|
70
71
|
},
|
|
71
72
|
"peerDependencies": {
|
|
72
|
-
"@cloudflare/workers-types": "^4.
|
|
73
|
+
"@cloudflare/workers-types": "^4.20260424.1",
|
|
73
74
|
"partyserver": ">=0.2.0 <1.0.0",
|
|
74
75
|
"yjs": "^13.6.14"
|
|
75
76
|
}
|