y-partyserver 0.0.0-2b263f6 → 0.0.0-3f3b01e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -6
- package/dist/{chunk-UKCMZSNL.js → chunk-TFXFSMIH.js} +2 -2
- package/dist/chunk-TFXFSMIH.js.map +1 -0
- package/dist/{chunk-UVQRROFJ.js → chunk-TXEGN7W6.js} +10 -8
- package/dist/chunk-TXEGN7W6.js.map +1 -0
- package/dist/provider/index.d.ts +7 -7
- package/dist/provider/index.js +4 -4
- package/dist/provider/react.d.ts +5 -6
- package/dist/provider/react.js +6 -5
- package/dist/provider/react.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/package.json +9 -9
- package/dist/chunk-UKCMZSNL.js.map +0 -1
- package/dist/chunk-UVQRROFJ.js.map +0 -1
package/README.md
CHANGED
|
@@ -25,18 +25,16 @@ export default class Document extends YjsServer {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// wire it up to your fetch handler
|
|
28
|
-
export {
|
|
29
|
-
async fetch(request: Request): Promise<Response> {
|
|
28
|
+
export default {
|
|
29
|
+
async fetch(request: Request, env: Env): Promise<Response> {
|
|
30
30
|
return (
|
|
31
31
|
// this will route requests to /parties/document/:id
|
|
32
32
|
// to the Document Durable Object
|
|
33
|
-
(await routePartykitRequest(request,
|
|
33
|
+
(await routePartykitRequest(request, env)) ||
|
|
34
34
|
new Response("Not Found", { status: 404 })
|
|
35
35
|
);
|
|
36
36
|
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
} satisfies ExportedHandler<Env>;
|
|
40
38
|
```
|
|
41
39
|
|
|
42
40
|
Step 2: Configure `wrangler.toml`
|
|
@@ -11,7 +11,7 @@ var sendChunked = (data, ws) => {
|
|
|
11
11
|
}
|
|
12
12
|
if (!warnedAboutLargeMessage) {
|
|
13
13
|
console.warn(
|
|
14
|
-
"[y-
|
|
14
|
+
"[y-partyserver]",
|
|
15
15
|
"The Y.js update size exceeds 1MB, which is the maximum size for an individual update. The update will be split into chunks. This is an experimental feature.",
|
|
16
16
|
`Message size: ${(data.byteLength / 1e3 / 1e3).toFixed(1)}MB`
|
|
17
17
|
);
|
|
@@ -123,4 +123,4 @@ export {
|
|
|
123
123
|
sendChunked,
|
|
124
124
|
handleChunked
|
|
125
125
|
};
|
|
126
|
-
//# sourceMappingURL=chunk-
|
|
126
|
+
//# sourceMappingURL=chunk-TFXFSMIH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/chunking.ts"],"sourcesContent":["// This file contains a shared implementation of chunking logic for binary\n// WebSocket messages. Because the Workers platform limits individual\n// WebSocket messages to 1MB, we need to split larger messages into chunks.\n\nimport type { Connection } from \"partyserver\";\n\nexport const CHUNK_MAX_SIZE = 1_000_000;\n\nconst BATCH_SENTINEL = \"y-pk-batch\";\nconst TRACE_ENABLED = false;\nconst trace = (...args: unknown[]) => TRACE_ENABLED && console.log(...args);\n\nlet warnedAboutLargeMessage = false;\n\ntype MessageData = ArrayBufferLike | string;\ntype MessageHandler = (conn: Connection, message: MessageData) => void;\ntype Batch = {\n id: string;\n type: \"start\" | \"end\";\n size: number;\n count: number;\n};\n\n/**\n * Takes an ArrayBuffer and sends it in chunks to the provided send function,\n * along with a start and end marker.\n *\n * 1. The sender splits the message into chunks of 1MB or less.\n * 2. The sender sends a chunk start marker\n * 3. The sender sends each chunk as a individual packet\n * 4. The sender sends a chunk end marker\n */\nexport const sendChunked = (data: Uint8Array, ws: WebSocket) => {\n if (data.byteLength <= CHUNK_MAX_SIZE) {\n ws.send(data);\n return;\n }\n\n if (!warnedAboutLargeMessage) {\n console.warn(\n \"[y-partyserver]\",\n \"The Y.js update size exceeds 1MB, which is the maximum size for an individual update. The update will be split into chunks. This is an experimental feature.\",\n `Message size: ${(data.byteLength / 1000 / 1000).toFixed(1)}MB`\n );\n warnedAboutLargeMessage = true;\n }\n\n const id = (Date.now() + Math.random()).toString(36).substring(10);\n const chunks = Math.ceil(data.byteLength / CHUNK_MAX_SIZE);\n\n ws.send(\n serializeBatchMarker({\n id,\n type: \"start\",\n size: data.byteLength,\n count: chunks\n })\n );\n\n let sentSize = 0;\n let sentChunks = 0;\n for (let i = 0; i < chunks; i++) {\n const chunk = data.slice(CHUNK_MAX_SIZE * i, CHUNK_MAX_SIZE * (i + 1));\n ws.send(chunk);\n sentChunks += 1;\n sentSize += chunk.byteLength;\n }\n\n ws.send(\n serializeBatchMarker({\n id,\n type: \"end\",\n size: sentSize,\n count: sentChunks\n })\n );\n};\n\n/**\n * Creates a WebSocket message handler that can handle chunked messages.\n *\n * Reassembles the chunks into a single ArrayBuffer and pass it to the\n * provided receive function.\n *\n * 1. The server receives a chunk start marker\n * 2. The server pools each chunk until it receives a chunk end marker\n * 3. The server validates that the received data matches the expected size\n * 4. The server forwards the message to handlers\n */\nexport const handleChunked = (\n receive: (conn: Connection, data: MessageData) => void\n): MessageHandler => {\n let batch: ArrayBuffer[] | undefined;\n let start: Batch | undefined;\n\n return (connection, message) => {\n if (typeof message === \"string\") {\n return;\n }\n if (isBatchSentinel(message)) {\n const marker = parseBatchMarker(message);\n if (marker.type === \"start\") {\n batch = [];\n start = marker;\n }\n\n if (marker.type === \"end\") {\n if (batch) {\n try {\n // validate start and end markers match\n assertEquality(start?.id, marker.id, \"client id\");\n assertEquality(start?.count, marker.count, \"client counts\");\n assertEquality(start?.size, marker.size, \"client size\");\n\n // combine chunks into single buffer\n const size = batch.reduce(\n (sum, buffer) => sum + buffer.byteLength,\n 0\n );\n const bytes = new Uint8Array(size);\n let bytesWritten = 0;\n for (const chunk of batch) {\n bytes.set(new Uint8Array(chunk), bytesWritten);\n bytesWritten += chunk.byteLength;\n }\n\n // validate data as read matches expected\n assertEquality(marker.count, batch.length, \"received batch count\");\n assertEquality(marker.size, bytesWritten, \"client size\");\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore typescript hell\n receive(connection, bytes);\n } catch (e) {\n console.error(e);\n throw e;\n } finally {\n batch = undefined;\n start = undefined;\n }\n }\n }\n } else if (batch) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore typescript hell\n batch.push(message);\n } else {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore typescript hell\n receive(connection, new Uint8Array(message));\n }\n };\n};\n\nfunction assertEquality(expected: unknown, actual: unknown, label: string) {\n if (expected !== actual) {\n throw new Error(\n `Mismatching ${label}! Expected ${expected as string}, got ${actual as string}`\n );\n } else {\n trace(`Matching ${label}: ${expected as string}`);\n }\n}\n\n/** Checks whether a message is batch marker */\nfunction isBatchSentinel(msg: MessageData): msg is string {\n return typeof msg === \"string\" && msg.startsWith(BATCH_SENTINEL);\n}\n\n/** Encodes a batch marker message so that it can be safely parsed */\nfunction serializeBatchMarker(batch: Batch): string {\n return `${BATCH_SENTINEL}#${JSON.stringify(batch)}`;\n}\n\n/** Parses a batch marker messages and throws if its invalid */\nexport function parseBatchMarker(msg: string) {\n const [sentinel, data] = msg.split(\"#\", 2);\n if (sentinel !== BATCH_SENTINEL) {\n throw new Error(\"Unexpected batch marker: \" + msg);\n }\n\n const batch = JSON.parse(data) as Batch;\n if (batch.type !== \"start\" && batch.type !== \"end\") {\n throw new Error(\"Unexpected batch data: \" + msg);\n }\n\n return batch;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
sendChunked
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TFXFSMIH.js";
|
|
4
4
|
|
|
5
5
|
// src/provider/index.ts
|
|
6
6
|
import * as bc from "lib0/broadcastchannel";
|
|
@@ -210,6 +210,7 @@ var WebsocketProvider = class extends Observable {
|
|
|
210
210
|
connect = true,
|
|
211
211
|
awareness = new awarenessProtocol.Awareness(doc),
|
|
212
212
|
params = {},
|
|
213
|
+
isPrefixedUrl = false,
|
|
213
214
|
WebSocketPolyfill = DefaultWebSocket,
|
|
214
215
|
// Optionally provide a WebSocket polyfill
|
|
215
216
|
resyncInterval = -1,
|
|
@@ -226,7 +227,7 @@ var WebsocketProvider = class extends Observable {
|
|
|
226
227
|
const encodedParams = url.encodeQueryParams(params);
|
|
227
228
|
this.maxBackoffTime = maxBackoffTime;
|
|
228
229
|
this.bcChannel = serverUrl + "/" + roomname;
|
|
229
|
-
this.url = serverUrl + "/" + roomname + (encodedParams.length === 0 ? "" : "?" + encodedParams);
|
|
230
|
+
this.url = isPrefixedUrl ? serverUrl : serverUrl + "/" + roomname + (encodedParams.length === 0 ? "" : "?" + encodedParams);
|
|
230
231
|
this.roomname = roomname;
|
|
231
232
|
this.doc = doc;
|
|
232
233
|
this._WS = WebSocketPolyfill;
|
|
@@ -422,11 +423,11 @@ function generateUUID() {
|
|
|
422
423
|
function assertType(value, label, type) {
|
|
423
424
|
if (typeof value !== type) {
|
|
424
425
|
throw new Error(
|
|
425
|
-
`Invalid "${label}" parameter provided to
|
|
426
|
+
`Invalid "${label}" parameter provided to YProvider. Expected: ${type}, received: ${value}`
|
|
426
427
|
);
|
|
427
428
|
}
|
|
428
429
|
}
|
|
429
|
-
var
|
|
430
|
+
var YProvider = class extends WebsocketProvider {
|
|
430
431
|
id;
|
|
431
432
|
#params;
|
|
432
433
|
constructor(host, room, doc, options = {}) {
|
|
@@ -436,11 +437,12 @@ var YPartyKitProvider = class extends WebsocketProvider {
|
|
|
436
437
|
if (host.endsWith("/")) {
|
|
437
438
|
host.slice(0, -1);
|
|
438
439
|
}
|
|
439
|
-
const serverUrl = `${options.protocol || (host.startsWith("localhost:") || host.startsWith("127.0.0.1:") || host.startsWith("192.168.") || host.startsWith("10.") || host.startsWith("172.") && host.split(".")[1] >= "16" && host.split(".")[1] <= "31" ? "ws" : "wss")}://${host}${options.
|
|
440
|
+
const serverUrl = `${options.protocol || (host.startsWith("localhost:") || host.startsWith("127.0.0.1:") || host.startsWith("192.168.") || host.startsWith("10.") || host.startsWith("172.") && host.split(".")[1] >= "16" && host.split(".")[1] <= "31" ? "ws" : "wss")}://${host}${options.prefix || `/parties/${options.party || "main"}`}`;
|
|
440
441
|
const id = options.connectionId ?? generateUUID();
|
|
441
442
|
const { params, connect = true, ...rest } = options;
|
|
442
443
|
const baseOptions = {
|
|
443
444
|
...rest,
|
|
445
|
+
isPrefixedUrl: !!options.prefix,
|
|
444
446
|
connect: false
|
|
445
447
|
};
|
|
446
448
|
super(serverUrl, room, doc ?? new YDoc(), baseOptions);
|
|
@@ -466,7 +468,7 @@ var YPartyKitProvider = class extends WebsocketProvider {
|
|
|
466
468
|
this.url = nextUrl.toString();
|
|
467
469
|
super.connect();
|
|
468
470
|
} catch (err) {
|
|
469
|
-
console.error("Failed to open connecton to
|
|
471
|
+
console.error("Failed to open connecton to PartyServer", err);
|
|
470
472
|
throw err;
|
|
471
473
|
}
|
|
472
474
|
}
|
|
@@ -478,6 +480,6 @@ export {
|
|
|
478
480
|
messageAwareness,
|
|
479
481
|
messageAuth,
|
|
480
482
|
WebsocketProvider,
|
|
481
|
-
|
|
483
|
+
YProvider
|
|
482
484
|
};
|
|
483
|
-
//# sourceMappingURL=chunk-
|
|
485
|
+
//# sourceMappingURL=chunk-TXEGN7W6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"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 * 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\nimport { sendChunked } from \"../shared/chunking\";\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\nfunction assert(condition: unknown, message: string): asserts condition {\n if (!condition) {\n throw new Error(message);\n }\n}\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\n// @todo - this should depend on awareness.outdatedTime\nconst messageReconnectTimeout = 30000;\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 // ignore text messages\n return;\n }\n provider.wsLastMessageReceived = time.getUnixTime();\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n const encoder = readMessage(provider, new Uint8Array(event.data), true);\n if (encoding.length(encoder) > 1) {\n sendChunked(encoding.toUint8Array(encoder), websocket);\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 awarenessProtocol.removeAwarenessStates(\n provider.awareness,\n Array.from(provider.awareness.getStates().keys()).filter(\n (client) => client !== provider.doc.clientID\n ),\n provider\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 setupWS,\n math.min(\n math.pow(2, provider.wsUnsuccessfulReconnects) * 100,\n provider.maxBackoffTime\n ),\n provider\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 sendChunked(encoding.toUint8Array(encoder), websocket);\n // broadcast local awareness state\n if (provider.awareness.getLocalState() !== null) {\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 sendChunked(encoding.toUint8Array(encoderAwarenessState), websocket);\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 sendChunked(buf, ws);\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 */\n// eslint-disable-next-line deprecation/deprecation\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 _checkInterval: ReturnType<typeof setInterval> | number;\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 +\n \"/\" +\n roomname +\n (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 sendChunked(encoding.toUint8Array(encoder), this.ws);\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 awareness.on(\"update\", this._awarenessUpdateHandler);\n this._checkInterval = /** @type {any} */ setInterval(() => {\n if (\n this.wsconnected &&\n messageReconnectTimeout <\n time.getUnixTime() - this.wsLastMessageReceived\n ) {\n assert(this.ws !== null, \"ws must not be null\");\n // no message received in a long time - not even your own awareness\n // updates (which are updated every 15 seconds)\n this.ws.close();\n }\n }, messageReconnectTimeout / 10);\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 clearInterval(this._checkInterval);\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(\"update\", 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 connect() {\n this.shouldConnect = true;\n if (!this.wsconnected && this.ws === null) {\n setupWS(this);\n this.connectBc();\n }\n }\n}\n\nfunction generateUUID(): string {\n // Public Domain/MIT\n if (crypto && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n let d = new Date().getTime(); //Timestamp\n let d2 =\n (typeof performance !== \"undefined\" &&\n performance.now &&\n performance.now() * 1000) ||\n 0; //Time in microseconds since page-load or 0 if unsupported\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function (c) {\n let r = Math.random() * 16; //random number between 0 and 16\n if (d > 0) {\n //Use timestamp until depleted\n r = (d + r) % 16 | 0;\n d = Math.floor(d / 16);\n } else {\n //Use microseconds since page-load if supported\n r = (d2 + r) % 16 | 0;\n d2 = Math.floor(d2 / 16);\n }\n return (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\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.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 ?? generateUUID();\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 connect() {\n try {\n // get updated url parameters\n const nextParams =\n typeof this.#params === \"function\"\n ? await this.#params()\n : this.#params;\n // override current url parameters before connecting\n const urlParams = new URLSearchParams([[\"_pk\", this.id]]);\n if (nextParams) {\n for (const [key, value] of Object.entries(nextParams)) {\n // filter out null/undefined values\n if (value !== null && value !== undefined) {\n urlParams.append(key, value);\n }\n }\n }\n\n const nextUrl = new URL(this.url);\n nextUrl.search = urlParams.toString();\n this.url = nextUrl.toString();\n\n // finally, connect\n super.connect();\n } catch (err) {\n console.error(\"Failed to open connecton to PartyServer\", err);\n throw err;\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/provider/index.d.ts
CHANGED
|
@@ -67,6 +67,7 @@ declare class WebsocketProvider extends Observable<string> {
|
|
|
67
67
|
connect,
|
|
68
68
|
awareness,
|
|
69
69
|
params,
|
|
70
|
+
isPrefixedUrl,
|
|
70
71
|
WebSocketPolyfill, // Optionally provide a WebSocket polyfill
|
|
71
72
|
resyncInterval, // Request server state every `resyncInterval` milliseconds
|
|
72
73
|
maxBackoffTime, // Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)
|
|
@@ -77,6 +78,7 @@ declare class WebsocketProvider extends Observable<string> {
|
|
|
77
78
|
params?: {
|
|
78
79
|
[s: string]: string;
|
|
79
80
|
};
|
|
81
|
+
isPrefixedUrl?: boolean;
|
|
80
82
|
WebSocketPolyfill?: typeof WebSocket | null;
|
|
81
83
|
resyncInterval?: number;
|
|
82
84
|
maxBackoffTime?: number;
|
|
@@ -97,30 +99,28 @@ declare class WebsocketProvider extends Observable<string> {
|
|
|
97
99
|
type Params = Record<string, string | null | undefined>;
|
|
98
100
|
type ParamsProvider = Params | (() => Params | Promise<Params>);
|
|
99
101
|
type BaseProviderOptions = ConstructorParameters<typeof WebsocketProvider>[3];
|
|
100
|
-
type
|
|
101
|
-
NonNullable<BaseProviderOptions>,
|
|
102
|
-
"params"
|
|
103
|
-
> & {
|
|
102
|
+
type YProviderOptions = Omit<NonNullable<BaseProviderOptions>, "params"> & {
|
|
104
103
|
connectionId?: string;
|
|
105
104
|
party?: string;
|
|
105
|
+
prefix?: string;
|
|
106
106
|
params?: ParamsProvider;
|
|
107
107
|
protocol?: "ws" | "wss";
|
|
108
108
|
};
|
|
109
|
-
declare class
|
|
109
|
+
declare class YProvider extends WebsocketProvider {
|
|
110
110
|
#private;
|
|
111
111
|
id: string;
|
|
112
112
|
constructor(
|
|
113
113
|
host: string,
|
|
114
114
|
room: string,
|
|
115
115
|
doc?: Doc,
|
|
116
|
-
options?:
|
|
116
|
+
options?: YProviderOptions
|
|
117
117
|
);
|
|
118
118
|
connect(): Promise<void>;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
export {
|
|
122
122
|
WebsocketProvider,
|
|
123
|
-
|
|
123
|
+
YProvider as default,
|
|
124
124
|
messageAuth,
|
|
125
125
|
messageAwareness,
|
|
126
126
|
messageQueryAwareness,
|
package/dist/provider/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
WebsocketProvider,
|
|
3
|
-
|
|
3
|
+
YProvider,
|
|
4
4
|
messageAuth,
|
|
5
5
|
messageAwareness,
|
|
6
6
|
messageQueryAwareness,
|
|
7
7
|
messageSync
|
|
8
|
-
} from "../chunk-
|
|
9
|
-
import "../chunk-
|
|
8
|
+
} from "../chunk-TXEGN7W6.js";
|
|
9
|
+
import "../chunk-TFXFSMIH.js";
|
|
10
10
|
export {
|
|
11
11
|
WebsocketProvider,
|
|
12
|
-
|
|
12
|
+
YProvider as default,
|
|
13
13
|
messageAuth,
|
|
14
14
|
messageAwareness,
|
|
15
15
|
messageQueryAwareness,
|
package/dist/provider/react.d.ts
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import * as Y from "yjs";
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import YProvider from "./index.js";
|
|
4
4
|
|
|
5
5
|
import "lib0/decoding";
|
|
6
6
|
import "lib0/encoding";
|
|
7
7
|
import "lib0/observable";
|
|
8
8
|
import "y-protocols/awareness";
|
|
9
9
|
|
|
10
|
-
type
|
|
10
|
+
type UseYProviderOptions = {
|
|
11
11
|
host?: string | undefined;
|
|
12
12
|
room: string;
|
|
13
13
|
party?: string;
|
|
14
14
|
doc?: Y.Doc;
|
|
15
|
-
|
|
15
|
+
prefix?: string;
|
|
16
|
+
options?: ConstructorParameters<typeof YProvider>[3];
|
|
16
17
|
};
|
|
17
|
-
declare function useYProvider(
|
|
18
|
-
yProviderOptions: UseYPartyKitProviderOptions
|
|
19
|
-
): YPartyKitProvider;
|
|
18
|
+
declare function useYProvider(yProviderOptions: UseYProviderOptions): YProvider;
|
|
20
19
|
|
|
21
20
|
export { useYProvider as default };
|
package/dist/provider/react.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
2
|
+
YProvider
|
|
3
|
+
} from "../chunk-TXEGN7W6.js";
|
|
4
|
+
import "../chunk-TFXFSMIH.js";
|
|
5
5
|
|
|
6
6
|
// src/provider/react.tsx
|
|
7
7
|
import { useEffect, useState } from "react";
|
|
8
8
|
function useYProvider(yProviderOptions) {
|
|
9
|
-
const { host, room, party, doc, options } = yProviderOptions;
|
|
9
|
+
const { host, room, party, doc, options, prefix } = yProviderOptions;
|
|
10
10
|
const [provider] = useState(
|
|
11
|
-
() => new
|
|
11
|
+
() => new YProvider(
|
|
12
12
|
host || (typeof window !== "undefined" ? window.location.host : "dummy-domain.com"),
|
|
13
13
|
room,
|
|
14
14
|
doc,
|
|
15
15
|
{
|
|
16
16
|
connect: false,
|
|
17
17
|
party,
|
|
18
|
+
prefix,
|
|
18
19
|
...options
|
|
19
20
|
}
|
|
20
21
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/provider/react.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nimport
|
|
1
|
+
{"version":3,"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":";;;;;;AAAA,SAAS,WAAW,gBAAgB;AAerB,SAAR,aAA8B,kBAAuC;AAC1E,QAAM,EAAE,MAAM,MAAM,OAAO,KAAK,SAAS,OAAO,IAAI;AACpD,QAAM,CAAC,QAAQ,IAAI;AAAA,IACjB,MACE,IAAI;AAAA,MACF,SACG,OAAO,WAAW,cACf,OAAO,SAAS,OAChB;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,QACE,SAAS;AAAA,QACT;AAAA,QACA;AAAA,QACA,GAAG;AAAA,MACL;AAAA,IACF;AAAA,EACJ;AAEA,YAAU,MAAM;AACd,SAAK,SAAS,QAAQ;AACtB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,QAAQ,CAAC;AACb,SAAO;AACT;","names":[]}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ interface CallbackOptions {
|
|
|
12
12
|
debounceMaxWait?: number;
|
|
13
13
|
timeout?: number;
|
|
14
14
|
}
|
|
15
|
-
declare class YjsDocument<Env> extends Server<Env> {
|
|
15
|
+
declare class YjsDocument<Env = unknown> extends Server<Env> {
|
|
16
16
|
#private;
|
|
17
17
|
static callbackOptions: CallbackOptions;
|
|
18
18
|
readonly document: WSSharedDoc;
|
package/dist/server/index.js
CHANGED
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/index.ts"],"sourcesContent":["import * as decoding from \"lib0/decoding\";\nimport * as encoding from \"lib0/encoding\";\nimport debounce from \"lodash.debounce\";\nimport { Server } from \"partyserver\";\nimport * as awarenessProtocol from \"y-protocols/awareness\";\nimport * as syncProtocol from \"y-protocols/sync\";\nimport { applyUpdate, encodeStateAsUpdate, Doc as YDoc } from \"yjs\";\n\nimport { handleChunked } from \"../shared/chunking\";\n\nimport type { Connection, ConnectionContext } from \"partyserver\";\n\nconst wsReadyStateConnecting = 0;\nconst wsReadyStateOpen = 1;\nconst wsReadyStateClosing = 2; // eslint-disable-line\nconst wsReadyStateClosed = 3; // eslint-disable-line\n\nconst messageSync = 0;\nconst messageAwareness = 1;\nconst messageAuth = 2; // eslint-disable-line\n\nfunction updateHandler(update: Uint8Array, origin: unknown, doc: WSSharedDoc) {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeUpdate(encoder, update);\n const message = encoding.toUint8Array(encoder);\n doc.conns.forEach((_, conn) => send(doc, conn, message));\n}\n\nclass WSSharedDoc extends YDoc {\n conns: Map<Connection, Set<number>>;\n awareness: awarenessProtocol.Awareness;\n\n constructor() {\n super({ gc: true });\n\n /**\n * Maps from conn to set of controlled user ids. Delete all user ids from awareness when this conn is closed\n */\n this.conns = new Map();\n\n this.awareness = new awarenessProtocol.Awareness(this);\n this.awareness.setLocalState(null);\n\n const awarenessChangeHandler = (\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 // Origin is the connection that made the change\n ) => {\n const changedClients = added.concat(updated, removed);\n if (conn !== null) {\n const connControlledIDs =\n /** @type {Set<number>} */ this.conns.get(conn);\n if (connControlledIDs !== undefined) {\n added.forEach((clientID) => {\n connControlledIDs.add(clientID);\n });\n removed.forEach((clientID) => {\n connControlledIDs.delete(clientID);\n });\n }\n }\n // broadcast awareness update\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(this.awareness, changedClients)\n );\n const buff = encoding.toUint8Array(encoder);\n this.conns.forEach((_, c) => {\n send(this, c, buff);\n });\n };\n this.awareness.on(\"update\", awarenessChangeHandler);\n // @ts-expect-error - TODO: fix this\n this.on(\"update\", updateHandler);\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 closeConn(doc: WSSharedDoc, conn: Connection): void {\n if (doc.conns.has(conn)) {\n const controlledIds: Set<number> = doc.conns.get(conn)!;\n doc.conns.delete(conn);\n awarenessProtocol.removeAwarenessStates(\n doc.awareness,\n Array.from(controlledIds),\n null\n );\n }\n try {\n conn.close();\n } catch (e) {\n console.warn(\"failed to close connection\", e);\n }\n}\n\nfunction send(doc: WSSharedDoc, conn: Connection, m: Uint8Array) {\n if (\n conn.readyState !== undefined &&\n conn.readyState !== wsReadyStateConnecting &&\n conn.readyState !== wsReadyStateOpen\n ) {\n closeConn(doc, conn);\n }\n try {\n conn.send(m);\n } catch (e) {\n closeConn(doc, conn);\n }\n}\n\ninterface CallbackOptions {\n debounceWait?: number;\n debounceMaxWait?: number;\n timeout?: number;\n}\n\nexport class YjsDocument<Env> extends Server<Env> {\n static callbackOptions: CallbackOptions = {};\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n #ParentClass: typeof YjsDocument = Object.getPrototypeOf(this).constructor;\n readonly document = new WSSharedDoc();\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async onLoad(): Promise<void> {\n // to be implemented by the user\n return;\n }\n\n async onSave(): Promise<void> {}\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 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 this.#ParentClass.callbackOptions.debounceWait ||\n CALLBACK_DEFAULTS.debounceWait,\n {\n maxWait:\n this.#ParentClass.callbackOptions.debounceMaxWait ||\n CALLBACK_DEFAULTS.debounceMaxWait\n }\n )\n );\n }\n\n onMessage = handleChunked((conn, message) => {\n if (typeof message === \"string\") {\n console.warn(\n `Received non-binary message. Override onMessage on ${this.#ParentClass.name} to handle string messages if required`\n );\n return;\n }\n try {\n const encoder = encoding.createEncoder();\n // TODO: this type seems odd\n const decoder = decoding.createDecoder(message as 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 conn,\n // TODO: readonly conections\n false\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(this.document, conn, encoding.toUint8Array(encoder));\n }\n break;\n case messageAwareness: {\n awarenessProtocol.applyAwarenessUpdate(\n this.document.awareness,\n decoding.readVarUint8Array(decoder),\n conn\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 onClose(\n connection: Connection<unknown>,\n _code: number,\n _reason: string,\n _wasClean: boolean\n ): void | Promise<void> {\n closeConn(this.document, connection);\n }\n\n // TODO: explore why onError gets triggered when a connection closes\n\n onConnect(conn: Connection<unknown>, _ctx: ConnectionContext) {\n // conn.binaryType = \"arraybuffer\"; // from y-websocket, breaks in our runtime\n\n this.document.conns.set(conn, new Set());\n\n // send sync step 1\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, this.document);\n send(this.document, 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(this.document, conn, encoding.toUint8Array(encoder));\n }\n }\n}\n"],"mappings":"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","names":["encoder"]}
|
|
1
|
+
{"version":3,"sources":["../../src/server/index.ts"],"sourcesContent":["import * as decoding from \"lib0/decoding\";\nimport * as encoding from \"lib0/encoding\";\nimport debounce from \"lodash.debounce\";\nimport { Server } from \"partyserver\";\nimport * as awarenessProtocol from \"y-protocols/awareness\";\nimport * as syncProtocol from \"y-protocols/sync\";\nimport { applyUpdate, encodeStateAsUpdate, Doc as YDoc } from \"yjs\";\n\nimport { handleChunked } from \"../shared/chunking\";\n\nimport type { Connection, ConnectionContext } from \"partyserver\";\n\nconst wsReadyStateConnecting = 0;\nconst wsReadyStateOpen = 1;\nconst wsReadyStateClosing = 2; // eslint-disable-line\nconst wsReadyStateClosed = 3; // eslint-disable-line\n\nconst messageSync = 0;\nconst messageAwareness = 1;\nconst messageAuth = 2; // eslint-disable-line\n\nfunction updateHandler(update: Uint8Array, origin: unknown, doc: WSSharedDoc) {\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeUpdate(encoder, update);\n const message = encoding.toUint8Array(encoder);\n doc.conns.forEach((_, conn) => send(doc, conn, message));\n}\n\nclass WSSharedDoc extends YDoc {\n conns: Map<Connection, Set<number>>;\n awareness: awarenessProtocol.Awareness;\n\n constructor() {\n super({ gc: true });\n\n /**\n * Maps from conn to set of controlled user ids. Delete all user ids from awareness when this conn is closed\n */\n this.conns = new Map();\n\n this.awareness = new awarenessProtocol.Awareness(this);\n this.awareness.setLocalState(null);\n\n const awarenessChangeHandler = (\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 // Origin is the connection that made the change\n ) => {\n const changedClients = added.concat(updated, removed);\n if (conn !== null) {\n const connControlledIDs =\n /** @type {Set<number>} */ this.conns.get(conn);\n if (connControlledIDs !== undefined) {\n added.forEach((clientID) => {\n connControlledIDs.add(clientID);\n });\n removed.forEach((clientID) => {\n connControlledIDs.delete(clientID);\n });\n }\n }\n // broadcast awareness update\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageAwareness);\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(this.awareness, changedClients)\n );\n const buff = encoding.toUint8Array(encoder);\n this.conns.forEach((_, c) => {\n send(this, c, buff);\n });\n };\n this.awareness.on(\"update\", awarenessChangeHandler);\n // @ts-expect-error - TODO: fix this\n this.on(\"update\", updateHandler);\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 closeConn(doc: WSSharedDoc, conn: Connection): void {\n if (doc.conns.has(conn)) {\n const controlledIds: Set<number> = doc.conns.get(conn)!;\n doc.conns.delete(conn);\n awarenessProtocol.removeAwarenessStates(\n doc.awareness,\n Array.from(controlledIds),\n null\n );\n }\n try {\n conn.close();\n } catch (e) {\n console.warn(\"failed to close connection\", e);\n }\n}\n\nfunction send(doc: WSSharedDoc, conn: Connection, m: Uint8Array) {\n if (\n conn.readyState !== undefined &&\n conn.readyState !== wsReadyStateConnecting &&\n conn.readyState !== wsReadyStateOpen\n ) {\n closeConn(doc, conn);\n }\n try {\n conn.send(m);\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (e) {\n closeConn(doc, conn);\n }\n}\n\ninterface CallbackOptions {\n debounceWait?: number;\n debounceMaxWait?: number;\n timeout?: number;\n}\n\nexport class YjsDocument<Env = unknown> extends Server<Env> {\n static callbackOptions: CallbackOptions = {};\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n #ParentClass: typeof YjsDocument = Object.getPrototypeOf(this).constructor;\n readonly document = new WSSharedDoc();\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async onLoad(): Promise<void> {\n // to be implemented by the user\n return;\n }\n\n async onSave(): Promise<void> {}\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 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 this.#ParentClass.callbackOptions.debounceWait ||\n CALLBACK_DEFAULTS.debounceWait,\n {\n maxWait:\n this.#ParentClass.callbackOptions.debounceMaxWait ||\n CALLBACK_DEFAULTS.debounceMaxWait\n }\n )\n );\n }\n\n onMessage = handleChunked((conn, message) => {\n if (typeof message === \"string\") {\n console.warn(\n `Received non-binary message. Override onMessage on ${this.#ParentClass.name} to handle string messages if required`\n );\n return;\n }\n try {\n const encoder = encoding.createEncoder();\n // TODO: this type seems odd\n const decoder = decoding.createDecoder(message as 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 conn,\n // TODO: readonly conections\n false\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(this.document, conn, encoding.toUint8Array(encoder));\n }\n break;\n case messageAwareness: {\n awarenessProtocol.applyAwarenessUpdate(\n this.document.awareness,\n decoding.readVarUint8Array(decoder),\n conn\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 onClose(\n connection: Connection<unknown>,\n _code: number,\n _reason: string,\n _wasClean: boolean\n ): void | Promise<void> {\n closeConn(this.document, connection);\n }\n\n // TODO: explore why onError gets triggered when a connection closes\n\n onConnect(conn: Connection<unknown>, _ctx: ConnectionContext) {\n // conn.binaryType = \"arraybuffer\"; // from y-websocket, breaks in our runtime\n\n this.document.conns.set(conn, new Set());\n\n // send sync step 1\n const encoder = encoding.createEncoder();\n encoding.writeVarUint(encoder, messageSync);\n syncProtocol.writeSyncStep1(encoder, this.document);\n send(this.document, 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(this.document, conn, encoding.toUint8Array(encoder));\n }\n }\n}\n"],"mappings":"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","names":["encoder"]}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "y-partyserver",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-3f3b01e",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
|
-
"url": "git://github.com/threepointone/partyserver"
|
|
6
|
+
"url": "git://github.com/threepointone/partyserver.git"
|
|
7
7
|
},
|
|
8
8
|
"type": "module",
|
|
9
9
|
"exports": {
|
|
@@ -39,20 +39,20 @@
|
|
|
39
39
|
"license": "ISC",
|
|
40
40
|
"description": "",
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"lib0": "^0.2.
|
|
42
|
+
"lib0": "^0.2.95",
|
|
43
43
|
"lodash.debounce": "^4.0.8",
|
|
44
44
|
"y-protocols": "^1.0.6"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"@cloudflare/workers-types": "^4.
|
|
48
|
-
"partyserver": "0.0.0-
|
|
47
|
+
"@cloudflare/workers-types": "^4.20240718.0",
|
|
48
|
+
"partyserver": "0.0.0-3f3b01e",
|
|
49
49
|
"yjs": "^13.6.14"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@cloudflare/workers-types": "^4.
|
|
52
|
+
"@cloudflare/workers-types": "^4.20240729.0",
|
|
53
53
|
"@types/lodash.debounce": "^4.0.9",
|
|
54
|
-
"partyserver": "0.0.0-
|
|
55
|
-
"ws": "^8.
|
|
56
|
-
"yjs": "^13.6.
|
|
54
|
+
"partyserver": "0.0.0-3f3b01e",
|
|
55
|
+
"ws": "^8.18.0",
|
|
56
|
+
"yjs": "^13.6.18"
|
|
57
57
|
}
|
|
58
58
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/chunking.ts"],"sourcesContent":["// This file contains a shared implementation of chunking logic for binary\n// WebSocket messages. Because the PartyKit platform limits individual\n\nimport type { Connection } from \"partyserver\";\n\n// WebSocket messages to 1MB, we need to split larger messages into chunks.\nexport const CHUNK_MAX_SIZE = 1_000_000;\n\nconst BATCH_SENTINEL = \"y-pk-batch\";\nconst TRACE_ENABLED = false;\nconst trace = (...args: unknown[]) => TRACE_ENABLED && console.log(...args);\n\nlet warnedAboutLargeMessage = false;\n\ntype MessageData = ArrayBufferLike | string;\ntype MessageHandler = (conn: Connection, message: MessageData) => void;\ntype Batch = {\n id: string;\n type: \"start\" | \"end\";\n size: number;\n count: number;\n};\n\n/**\n * Takes an ArrayBuffer and sends it in chunks to the provided send function,\n * along with a start and end marker.\n *\n * 1. The sender splits the message into chunks of 1MB or less.\n * 2. The sender sends a chunk start marker\n * 3. The sender sends each chunk as a individual packet\n * 4. The sender sends a chunk end marker\n */\nexport const sendChunked = (data: Uint8Array, ws: WebSocket) => {\n if (data.byteLength <= CHUNK_MAX_SIZE) {\n ws.send(data);\n return;\n }\n\n if (!warnedAboutLargeMessage) {\n console.warn(\n \"[y-partykit]\",\n \"The Y.js update size exceeds 1MB, which is the maximum size for an individual update. The update will be split into chunks. This is an experimental feature.\",\n `Message size: ${(data.byteLength / 1000 / 1000).toFixed(1)}MB`\n );\n warnedAboutLargeMessage = true;\n }\n\n const id = (Date.now() + Math.random()).toString(36).substring(10);\n const chunks = Math.ceil(data.byteLength / CHUNK_MAX_SIZE);\n\n ws.send(\n serializeBatchMarker({\n id,\n type: \"start\",\n size: data.byteLength,\n count: chunks\n })\n );\n\n let sentSize = 0;\n let sentChunks = 0;\n for (let i = 0; i < chunks; i++) {\n const chunk = data.slice(CHUNK_MAX_SIZE * i, CHUNK_MAX_SIZE * (i + 1));\n ws.send(chunk);\n sentChunks += 1;\n sentSize += chunk.byteLength;\n }\n\n ws.send(\n serializeBatchMarker({\n id,\n type: \"end\",\n size: sentSize,\n count: sentChunks\n })\n );\n};\n\n/**\n * Creates a WebSocket message handler that can handle chunked messages.\n *\n * Reassembles the chunks into a single ArrayBuffer and pass it to the\n * provided receive function.\n *\n * 1. The server receives a chunk start marker\n * 2. The server pools each chunk until it receives a chunk end marker\n * 3. The server validates that the received data matches the expected size\n * 4. The server forwards the message to handlers\n */\nexport const handleChunked = (\n receive: (conn: Connection, data: MessageData) => void\n): MessageHandler => {\n let batch: ArrayBuffer[] | undefined;\n let start: Batch | undefined;\n\n return (connection, message) => {\n if (typeof message === \"string\") {\n return;\n }\n if (isBatchSentinel(message)) {\n const marker = parseBatchMarker(message);\n if (marker.type === \"start\") {\n batch = [];\n start = marker;\n }\n\n if (marker.type === \"end\") {\n if (batch) {\n try {\n // validate start and end markers match\n assertEquality(start?.id, marker.id, \"client id\");\n assertEquality(start?.count, marker.count, \"client counts\");\n assertEquality(start?.size, marker.size, \"client size\");\n\n // combine chunks into single buffer\n const size = batch.reduce(\n (sum, buffer) => sum + buffer.byteLength,\n 0\n );\n const bytes = new Uint8Array(size);\n let bytesWritten = 0;\n for (const chunk of batch) {\n bytes.set(new Uint8Array(chunk), bytesWritten);\n bytesWritten += chunk.byteLength;\n }\n\n // validate data as read matches expected\n assertEquality(marker.count, batch.length, \"received batch count\");\n assertEquality(marker.size, bytesWritten, \"client size\");\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore typescript hell\n receive(connection, bytes);\n } catch (e) {\n console.error(e);\n throw e;\n } finally {\n batch = undefined;\n start = undefined;\n }\n }\n }\n } else if (batch) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore typescript hell\n batch.push(message);\n } else {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore typescript hell\n receive(connection, new Uint8Array(message));\n }\n };\n};\n\nfunction assertEquality(expected: unknown, actual: unknown, label: string) {\n if (expected !== actual) {\n throw new Error(\n `Mismatching ${label}! Expected ${expected as string}, got ${actual as string}`\n );\n } else {\n trace(`Matching ${label}: ${expected as string}`);\n }\n}\n\n/** Checks whether a message is batch marker */\nfunction isBatchSentinel(msg: MessageData): msg is string {\n return typeof msg === \"string\" && msg.startsWith(BATCH_SENTINEL);\n}\n\n/** Encodes a batch marker message so that it can be safely parsed */\nfunction serializeBatchMarker(batch: Batch): string {\n return `${BATCH_SENTINEL}#${JSON.stringify(batch)}`;\n}\n\n/** Parses a batch marker messages and throws if its invalid */\nexport function parseBatchMarker(msg: string) {\n const [sentinel, data] = msg.split(\"#\", 2);\n if (sentinel !== BATCH_SENTINEL) {\n throw new Error(\"Unexpected batch marker: \" + msg);\n }\n\n const batch = JSON.parse(data) as Batch;\n if (batch.type !== \"start\" && batch.type !== \"end\") {\n throw new Error(\"Unexpected batch data: \" + msg);\n }\n\n return batch;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"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 * 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\nimport { sendChunked } from \"../shared/chunking\";\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\nfunction assert(condition: unknown, message: string): asserts condition {\n if (!condition) {\n throw new Error(message);\n }\n}\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\n// @todo - this should depend on awareness.outdatedTime\nconst messageReconnectTimeout = 30000;\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 // ignore text messages\n return;\n }\n provider.wsLastMessageReceived = time.getUnixTime();\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n const encoder = readMessage(provider, new Uint8Array(event.data), true);\n if (encoding.length(encoder) > 1) {\n sendChunked(encoding.toUint8Array(encoder), websocket);\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 awarenessProtocol.removeAwarenessStates(\n provider.awareness,\n Array.from(provider.awareness.getStates().keys()).filter(\n (client) => client !== provider.doc.clientID\n ),\n provider\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 setupWS,\n math.min(\n math.pow(2, provider.wsUnsuccessfulReconnects) * 100,\n provider.maxBackoffTime\n ),\n provider\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 sendChunked(encoding.toUint8Array(encoder), websocket);\n // broadcast local awareness state\n if (provider.awareness.getLocalState() !== null) {\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 sendChunked(encoding.toUint8Array(encoderAwarenessState), websocket);\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 sendChunked(buf, ws);\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 */\n// eslint-disable-next-line deprecation/deprecation\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 _checkInterval: ReturnType<typeof setInterval> | number;\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 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 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 =\n serverUrl +\n \"/\" +\n roomname +\n (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 sendChunked(encoding.toUint8Array(encoder), this.ws);\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 awareness.on(\"update\", this._awarenessUpdateHandler);\n this._checkInterval = /** @type {any} */ setInterval(() => {\n if (\n this.wsconnected &&\n messageReconnectTimeout <\n time.getUnixTime() - this.wsLastMessageReceived\n ) {\n assert(this.ws !== null, \"ws must not be null\");\n // no message received in a long time - not even your own awareness\n // updates (which are updated every 15 seconds)\n this.ws.close();\n }\n }, messageReconnectTimeout / 10);\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 clearInterval(this._checkInterval);\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(\"update\", 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 connect() {\n this.shouldConnect = true;\n if (!this.wsconnected && this.ws === null) {\n setupWS(this);\n this.connectBc();\n }\n }\n}\n\nfunction generateUUID(): string {\n // Public Domain/MIT\n if (crypto && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n let d = new Date().getTime(); //Timestamp\n let d2 =\n (typeof performance !== \"undefined\" &&\n performance.now &&\n performance.now() * 1000) ||\n 0; //Time in microseconds since page-load or 0 if unsupported\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function (c) {\n let r = Math.random() * 16; //random number between 0 and 16\n if (d > 0) {\n //Use timestamp until depleted\n r = (d + r) % 16 | 0;\n d = Math.floor(d / 16);\n } else {\n //Use microseconds since page-load if supported\n r = (d2 + r) % 16 | 0;\n d2 = Math.floor(d2 / 16);\n }\n return (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\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 YPartyKitProvider. 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 YPartyKitProviderOptions = Omit<\n NonNullable<BaseProviderOptions>,\n \"params\"\n> & {\n connectionId?: string;\n party?: string;\n params?: ParamsProvider;\n protocol?: \"ws\" | \"wss\";\n};\n\nexport default class YPartyKitProvider extends WebsocketProvider {\n id: string;\n #params?: ParamsProvider;\n\n constructor(\n host: string,\n room: string,\n doc?: YDoc,\n options: YPartyKitProviderOptions = {}\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.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.party ? `/parties/${options.party}` : \"/party\"}`;\n\n // use provided id, or generate a random one\n const id = options.connectionId ?? generateUUID();\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 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 connect() {\n try {\n // get updated url parameters\n const nextParams =\n typeof this.#params === \"function\"\n ? await this.#params()\n : this.#params;\n // override current url parameters before connecting\n const urlParams = new URLSearchParams([[\"_pk\", this.id]]);\n if (nextParams) {\n for (const [key, value] of Object.entries(nextParams)) {\n // filter out null/undefined values\n if (value !== null && value !== undefined) {\n urlParams.append(key, value);\n }\n }\n }\n\n const nextUrl = new URL(this.url);\n nextUrl.search = urlParams.toString();\n this.url = nextUrl.toString();\n\n // finally, connect\n super.connect();\n } catch (err) {\n console.error(\"Failed to open connecton to PartyKit\", err);\n throw err;\n }\n }\n}\n"],"mappings":"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","names":[]}
|