y-partyserver 0.0.0-eb347bc → 0.0.0-ebe3f6a

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 CHANGED
@@ -1,54 +1,155 @@
1
1
  ## y-partyserver
2
2
 
3
- > [!CAUTION]
4
- > This project is in its experimental early stages and is not recommended for production use.
3
+ > [!WARNING]
4
+ > This project is experimental and is not yet recommended for production use.
5
5
 
6
- A [Yjs](https://docs.yjs.dev/) backend for [PartyServer](https://npmjs.com/package/partyserver). Build collaborative text editors and more, powered by [Durable Objects](https://developers.cloudflare.com/durable-objects/)!
6
+ [//]: # "keep in sync with packages/y-partyserver/README.md"
7
+ [//]: # "keep in sync with docs/reference/y-partyserver.md"
7
8
 
8
- Step 1: Define your server as a subclass of `YjsServer`
9
+ `y-partyserver` is an addon library for `partyserver` designed to host backends for [Yjs](https://yjs.dev), a high-performance library of data structures for building collaborative software.
10
+
11
+ _This document assumes some familiarity with Yjs. If you're new to Yjs, you can learn more about it in the [official documentation](https://docs.yjs.dev)._
12
+
13
+ ## Setting up a Yjs Server
14
+
15
+ Like PartyServer, `YServer` is a class that extends `DurableObject` (as well as PartyServer's `Server`). The simplest Yjs backend can be set up like so:
9
16
 
10
17
  ```ts
11
- import { YjsServer } from "y-partyserver";
18
+ export { YServer as MyYServer } from "y-partyserver";
12
19
 
13
- // define your YjsServer Durable Object
14
- export default class Document extends YjsServer {
15
- // optionally load / save with a database
16
- async onSave() {
17
- // this.document is a Y.Doc instance
18
- // that you can serialise to your database
20
+ // then setup wrangler.toml and a default fetch handler
21
+ // like you would for PartyServer.
22
+ ```
23
+
24
+ ## Connecting from the client
25
+
26
+ Use the provider to connect to this server from your client:
27
+
28
+ ```ts
29
+ import YProvider from "y-partyserver/provider";
30
+ import * as Y from "yjs";
31
+
32
+ const yDoc = new Y.Doc();
33
+
34
+ const provider = new YProvider("localhost:8787", "my-document-name", yDoc);
35
+ ```
36
+
37
+ You can add additional options to the provider:
38
+
39
+ ```tsx
40
+ const provider = new YProvider(
41
+ /* host */
42
+ "localhost:8787",
43
+ /* document/room name */
44
+ "my-document-name",
45
+ /* Yjs document instance */
46
+ yDoc,
47
+ {
48
+ /* whether to connect to the server immediately */
49
+ connect: false,
50
+ /* the party server path to connect to, defaults to "main" */
51
+ party: "my-party",
52
+ /* the path to the Yjs document on the server
53
+ * This replaces the default path of /parties/:party/:room.
54
+ */
55
+ prefix: "/my/own/path",
56
+ /* use your own Yjs awareness instance */
57
+ awareness: new awarenessProtocol.Awareness(yDoc),
58
+ /* query params to add to the websocket connection
59
+ * This can be an object or a function that returns an object
60
+ */
61
+ params: async () => ({
62
+ token: await getAuthToken()
63
+ }),
64
+ /* the WebSocket implementation to use
65
+ * This can be a polyfill or a custom implementation
66
+ */
67
+ WebSocketPolyfill: WebSocket,
68
+ /* the interval at which to resync the document
69
+ * This is set to -1 by default to disable resyncing by polling
70
+ */
71
+ resyncInterval: -1,
72
+ /* Maximum amount of time to wait before trying to reconnect
73
+ * (we try to reconnect using exponential backoff)
74
+ */
75
+ maxBackoffTimeout: 2500,
76
+
77
+ /* Disable cross-tab BroadcastChannel communication */
78
+ disableBc: false
19
79
  }
80
+ );
81
+ ```
82
+
83
+ ## Usage with React
84
+
85
+ If you're using React, then you can use the hook version of the provider: `useYProvider`.
86
+
87
+ ```ts
88
+ import useYProvider from "y-partyserver/react";
89
+
90
+ function App() {
91
+ const provider = useYProvider({
92
+ host: "localhost:8787", // optional, defaults to window.location.host
93
+ room: "my-document-name",
94
+ party: "my-party", // optional, defaults to "main"
95
+ doc: yDoc, // optional!
96
+ options
97
+ });
98
+ }
99
+ ```
100
+
101
+ ### Persistence
102
+
103
+ By default, PartyKit maintains a copy of the Yjs document as long as at least one client is connected to the server. When all clients disconnect, the document state may be lost.
104
+
105
+ To persist the Yjs document state between sessions, you can configure onLoad and onSave methods:
106
+
107
+ ```ts
108
+ // server.ts
109
+ import { YServer } from "y-partyserver";
110
+
111
+ export class MyDocument extends YServer {
112
+ /* control how often the onSave handler
113
+ * is called with these options */
114
+ static callbackOptions = {
115
+ // all of these are optional
116
+ debounceWait: /* number, default = */ 2000,
117
+ debounceMaxWait: /* number, default = */ 10000,
118
+ timeout: /* number, default = */ 5000
119
+ };
20
120
 
21
121
  async onLoad() {
22
- // this is called ONCE when the server "starts" up
23
- // you can apply any state to this.document
122
+ // load a document from a database, or some remote resource
123
+ // and apply it on to the Yjs document instance at `this.document`
124
+ const content = (await fetchDataFromExternalService(
125
+ this.name
126
+ )) as Uint8Array;
127
+ if (content) {
128
+ Y.applyUpdate(this.document, content);
129
+ }
130
+ return;
24
131
  }
25
- }
26
132
 
27
- // wire it up to your fetch handler
28
- export {
29
- async fetch(request: Request): Promise<Response> {
30
- return (
31
- // this will route requests to /parties/document/:id
32
- // to the Document Durable Object
33
- (await Server.partyFetch(request, this.env)) ||
34
- new Response("Not Found", { status: 404 })
133
+ async onSave() {
134
+ // called every few seconds after edits, and when the room empties
135
+ // you can use this to write to a database or some external storage
136
+
137
+ await sendDataToExternalService(
138
+ this.name,
139
+ Y.encodeStateAsUpdate(this.document) satisfies Uint8Array
35
140
  );
36
141
  }
37
142
  }
143
+ ```
38
144
 
145
+ `onLoad` is called once when a client connects to the server. It should initialise the Yjs document instance at `this.document`. Once the document has been loaded, it's kept in memory until the session ends.
39
146
 
40
- ```
147
+ `onSave` is called periodically after the document has been edited, and when the room is emptied. It should be used to save the document state to a database or some other external storage.
41
148
 
42
- Step 2: Configure `wrangler.toml`
149
+ ## Learn more
43
150
 
44
- ```toml
45
- [[durable_objects.bindings]]
46
- name = "Document"
47
- class_name = "Document"
151
+ For more information, refer to the [official Yjs documentation](https://docs.yjs.dev/ecosystem/editor-bindings). Examples provided in the Yjs documentation should work seamlessly with `y-partyserver` (ensure to replace `y-websocket` with `y-partyserver/provider`).
48
152
 
49
- [[migrations]]
50
- tag = "v1" # Should be unique for each entry
51
- new_classes = ["Document"]
52
- ```
153
+ ### TODO:
53
154
 
54
- Step 3: Connect from your client. Check your editor's documentation for how to connect to a Yjs server.
155
+ readonly mode
@@ -11,7 +11,7 @@ var sendChunked = (data, ws) => {
11
11
  }
12
12
  if (!warnedAboutLargeMessage) {
13
13
  console.warn(
14
- "[y-partykit]",
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
  );
@@ -110,11 +110,11 @@ function serializeBatchMarker(batch) {
110
110
  function parseBatchMarker(msg) {
111
111
  const [sentinel, data] = msg.split("#", 2);
112
112
  if (sentinel !== BATCH_SENTINEL) {
113
- throw new Error("Unexpected batch marker: " + msg);
113
+ throw new Error(`Unexpected batch marker: ${msg}`);
114
114
  }
115
115
  const batch = JSON.parse(data);
116
116
  if (batch.type !== "start" && batch.type !== "end") {
117
- throw new Error("Unexpected batch data: " + msg);
117
+ throw new Error(`Unexpected batch data: ${msg}`);
118
118
  }
119
119
  return batch;
120
120
  }
@@ -123,4 +123,4 @@ export {
123
123
  sendChunked,
124
124
  handleChunked
125
125
  };
126
- //# sourceMappingURL=chunk-UKCMZSNL.js.map
126
+ //# sourceMappingURL=chunk-KQFBTVB7.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 // @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 // @ts-ignore typescript hell\n batch.push(message);\n } else {\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-UKCMZSNL.js";
3
+ } from "./chunk-KQFBTVB7.js";
4
4
 
5
5
  // src/provider/index.ts
6
6
  import * as bc from "lib0/broadcastchannel";
@@ -10,6 +10,7 @@ import * as math from "lib0/math";
10
10
  import { Observable } from "lib0/observable";
11
11
  import * as time from "lib0/time";
12
12
  import * as url from "lib0/url";
13
+ import { nanoid } from "nanoid";
13
14
  import * as authProtocol from "y-protocols/auth";
14
15
  import * as awarenessProtocol from "y-protocols/awareness";
15
16
  import * as syncProtocol from "y-protocols/sync";
@@ -210,6 +211,7 @@ var WebsocketProvider = class extends Observable {
210
211
  connect = true,
211
212
  awareness = new awarenessProtocol.Awareness(doc),
212
213
  params = {},
214
+ isPrefixedUrl = false,
213
215
  WebSocketPolyfill = DefaultWebSocket,
214
216
  // Optionally provide a WebSocket polyfill
215
217
  resyncInterval = -1,
@@ -225,8 +227,8 @@ var WebsocketProvider = class extends Observable {
225
227
  }
226
228
  const encodedParams = url.encodeQueryParams(params);
227
229
  this.maxBackoffTime = maxBackoffTime;
228
- this.bcChannel = serverUrl + "/" + roomname;
229
- this.url = serverUrl + "/" + roomname + (encodedParams.length === 0 ? "" : "?" + encodedParams);
230
+ this.bcChannel = `${serverUrl}/${roomname}`;
231
+ this.url = isPrefixedUrl ? serverUrl : `${serverUrl}/${roomname}${encodedParams.length === 0 ? "" : `?${encodedParams}`}`;
230
232
  this.roomname = roomname;
231
233
  this.doc = doc;
232
234
  this._WS = WebSocketPolyfill;
@@ -401,32 +403,14 @@ var WebsocketProvider = class extends Observable {
401
403
  }
402
404
  }
403
405
  };
404
- function generateUUID() {
405
- if (crypto && crypto.randomUUID) {
406
- return crypto.randomUUID();
407
- }
408
- let d = (/* @__PURE__ */ new Date()).getTime();
409
- let d2 = typeof performance !== "undefined" && performance.now && performance.now() * 1e3 || 0;
410
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
411
- let r = Math.random() * 16;
412
- if (d > 0) {
413
- r = (d + r) % 16 | 0;
414
- d = Math.floor(d / 16);
415
- } else {
416
- r = (d2 + r) % 16 | 0;
417
- d2 = Math.floor(d2 / 16);
418
- }
419
- return (c === "x" ? r : r & 3 | 8).toString(16);
420
- });
421
- }
422
406
  function assertType(value, label, type) {
423
407
  if (typeof value !== type) {
424
408
  throw new Error(
425
- `Invalid "${label}" parameter provided to YPartyKitProvider. Expected: ${type}, received: ${value}`
409
+ `Invalid "${label}" parameter provided to YProvider. Expected: ${type}, received: ${value}`
426
410
  );
427
411
  }
428
412
  }
429
- var YPartyKitProvider = class extends WebsocketProvider {
413
+ var YProvider = class extends WebsocketProvider {
430
414
  id;
431
415
  #params;
432
416
  constructor(host, room, doc, options = {}) {
@@ -436,11 +420,12 @@ var YPartyKitProvider = class extends WebsocketProvider {
436
420
  if (host.endsWith("/")) {
437
421
  host.slice(0, -1);
438
422
  }
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.party ? `/parties/${options.party}` : "/party"}`;
440
- const id = options.connectionId ?? generateUUID();
423
+ 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"}`}`;
424
+ const id = options.connectionId ?? nanoid(10);
441
425
  const { params, connect = true, ...rest } = options;
442
426
  const baseOptions = {
443
427
  ...rest,
428
+ isPrefixedUrl: !!options.prefix,
444
429
  connect: false
445
430
  };
446
431
  super(serverUrl, room, doc ?? new YDoc(), baseOptions);
@@ -466,7 +451,7 @@ var YPartyKitProvider = class extends WebsocketProvider {
466
451
  this.url = nextUrl.toString();
467
452
  super.connect();
468
453
  } catch (err) {
469
- console.error("Failed to open connecton to PartyKit", err);
454
+ console.error("Failed to open connecton to PartyServer", err);
470
455
  throw err;
471
456
  }
472
457
  }
@@ -478,6 +463,6 @@ export {
478
463
  messageAwareness,
479
464
  messageAuth,
480
465
  WebsocketProvider,
481
- YPartyKitProvider
466
+ YProvider
482
467
  };
483
- //# sourceMappingURL=chunk-UVQRROFJ.js.map
468
+ //# sourceMappingURL=chunk-W223QYN2.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 { 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\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 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 */\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}/${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 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 assertType(value: unknown, label: string, type: string) {\n // biome-ignore lint/suspicious/useValidTypeof: <explanation>\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 ?? 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 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":[]}
@@ -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 YPartyKitProviderOptions = Omit<
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 YPartyKitProvider extends WebsocketProvider {
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?: YPartyKitProviderOptions
116
+ options?: YProviderOptions
117
117
  );
118
118
  connect(): Promise<void>;
119
119
  }
120
120
 
121
121
  export {
122
122
  WebsocketProvider,
123
- YPartyKitProvider as default,
123
+ YProvider as default,
124
124
  messageAuth,
125
125
  messageAwareness,
126
126
  messageQueryAwareness,
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  WebsocketProvider,
3
- YPartyKitProvider,
3
+ YProvider,
4
4
  messageAuth,
5
5
  messageAwareness,
6
6
  messageQueryAwareness,
7
7
  messageSync
8
- } from "../chunk-UVQRROFJ.js";
9
- import "../chunk-UKCMZSNL.js";
8
+ } from "../chunk-W223QYN2.js";
9
+ import "../chunk-KQFBTVB7.js";
10
10
  export {
11
11
  WebsocketProvider,
12
- YPartyKitProvider as default,
12
+ YProvider as default,
13
13
  messageAuth,
14
14
  messageAwareness,
15
15
  messageQueryAwareness,
@@ -1,21 +1,20 @@
1
1
  import * as Y from "yjs";
2
2
 
3
- import YPartyKitProvider from "./index.js";
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 UseYPartyKitProviderOptions = {
10
+ type UseYProviderOptions = {
11
11
  host?: string | undefined;
12
12
  room: string;
13
13
  party?: string;
14
14
  doc?: Y.Doc;
15
- options?: ConstructorParameters<typeof YPartyKitProvider>[3];
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 };
@@ -1,20 +1,21 @@
1
1
  import {
2
- YPartyKitProvider
3
- } from "../chunk-UVQRROFJ.js";
4
- import "../chunk-UKCMZSNL.js";
2
+ YProvider
3
+ } from "../chunk-W223QYN2.js";
4
+ import "../chunk-KQFBTVB7.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 YPartyKitProvider(
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 YPartyKitProvider from \"./index\";\n\nimport type * as Y from \"yjs\";\n\ntype UseYPartyKitProviderOptions = {\n host?: string | undefined;\n room: string;\n party?: string;\n doc?: Y.Doc;\n options?: ConstructorParameters<typeof YPartyKitProvider>[3];\n};\n\nexport default function useYProvider(\n yProviderOptions: UseYPartyKitProviderOptions\n) {\n const { host, room, party, doc, options } = yProviderOptions;\n const [provider] = useState<YPartyKitProvider>(\n () =>\n new YPartyKitProvider(\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 ...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;AAcrB,SAAR,aACL,kBACA;AACA,QAAM,EAAE,MAAM,MAAM,OAAO,KAAK,QAAQ,IAAI;AAC5C,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,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":[]}
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":[]}
@@ -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 YServer<Env = unknown> extends Server<Env> {
16
16
  #private;
17
17
  static callbackOptions: CallbackOptions;
18
18
  readonly document: WSSharedDoc;
@@ -29,4 +29,4 @@ declare class YjsDocument<Env> extends Server<Env> {
29
29
  onConnect(conn: Connection<unknown>, _ctx: ConnectionContext): void;
30
30
  }
31
31
 
32
- export { YjsDocument };
32
+ export { type CallbackOptions, YServer };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  handleChunked
3
- } from "../chunk-UKCMZSNL.js";
3
+ } from "../chunk-KQFBTVB7.js";
4
4
 
5
5
  // src/server/index.ts
6
6
  import * as decoding from "lib0/decoding";
@@ -113,12 +113,10 @@ function send(doc, conn, m) {
113
113
  closeConn(doc, conn);
114
114
  }
115
115
  }
116
- var YjsDocument = class extends Server {
116
+ var YServer = class extends Server {
117
117
  static callbackOptions = {};
118
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
119
118
  #ParentClass = Object.getPrototypeOf(this).constructor;
120
119
  document = new WSSharedDoc();
121
- // eslint-disable-next-line @typescript-eslint/require-await
122
120
  async onLoad() {
123
121
  return;
124
122
  }
@@ -149,6 +147,7 @@ var YjsDocument = class extends Server {
149
147
  )
150
148
  );
151
149
  }
150
+ // @ts-ignore something something typescript
152
151
  onMessage = handleChunked((conn, message) => {
153
152
  if (typeof message === "string") {
154
153
  console.warn(
@@ -215,6 +214,6 @@ var YjsDocument = class extends Server {
215
214
  }
216
215
  };
217
216
  export {
218
- YjsDocument
217
+ YServer
219
218
  };
220
219
  //# sourceMappingURL=index.js.map
@@ -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;\nconst wsReadyStateClosed = 3;\n\nconst messageSync = 0;\nconst messageAwareness = 1;\nconst messageAuth = 2;\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\nexport interface CallbackOptions {\n debounceWait?: number;\n debounceMaxWait?: number;\n timeout?: number;\n}\n\nexport class YServer<Env = unknown> extends Server<Env> {\n static callbackOptions: CallbackOptions = {};\n\n #ParentClass: typeof YServer = Object.getPrototypeOf(this).constructor;\n readonly document = new WSSharedDoc();\n\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 // @ts-ignore something something typescript\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 unknown 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,26 +1,26 @@
1
1
  {
2
2
  "name": "y-partyserver",
3
- "version": "0.0.0-eb347bc",
3
+ "version": "0.0.0-ebe3f6a",
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": {
10
10
  ".": {
11
+ "types": "./dist/server/index.d.ts",
11
12
  "require": "./dist/server/index.js",
12
- "import": "./dist/server/index.js",
13
- "types": "./dist/server/index.d.ts"
13
+ "import": "./dist/server/index.js"
14
14
  },
15
15
  "./provider": {
16
+ "types": "./dist/provider/index.d.ts",
16
17
  "require": "./dist/provider/index.js",
17
- "import": "./dist/provider/index.js",
18
- "types": "./dist/provider/index.d.ts"
18
+ "import": "./dist/provider/index.js"
19
19
  },
20
20
  "./react": {
21
+ "types": "./dist/provider/react.d.ts",
21
22
  "require": "./dist/provider/react.js",
22
- "import": "./dist/provider/react.js",
23
- "types": "./dist/provider/react.d.ts"
23
+ "import": "./dist/provider/react.js"
24
24
  }
25
25
  },
26
26
  "scripts": {
@@ -35,22 +35,25 @@
35
35
  "collaboration",
36
36
  "text-editors"
37
37
  ],
38
- "author": "Sunil Pai <threepointone@gmail.com>",
38
+ "author": "Sunil Pai <spai@cloudflare.com>",
39
39
  "license": "ISC",
40
40
  "description": "",
41
41
  "dependencies": {
42
- "lib0": "^0.2.92",
42
+ "lib0": "^0.2.99",
43
43
  "lodash.debounce": "^4.0.8",
44
+ "nanoid": "^5.0.9",
44
45
  "y-protocols": "^1.0.6"
45
46
  },
46
47
  "peerDependencies": {
47
- "@cloudflare/workers-types": "^4.20240529.0",
48
+ "@cloudflare/workers-types": "^4.20240729.0",
49
+ "partyserver": "0.0.0-ebe3f6a",
48
50
  "yjs": "^13.6.14"
49
51
  },
50
52
  "devDependencies": {
51
- "@cloudflare/workers-types": "^4.20240529.0",
53
+ "@cloudflare/workers-types": "^4.20241230.0",
52
54
  "@types/lodash.debounce": "^4.0.9",
53
- "ws": "^8.11.0",
54
- "yjs": "^13.6.14"
55
+ "partyserver": "0.0.0-ebe3f6a",
56
+ "ws": "^8.18.0",
57
+ "yjs": "^13.6.21"
55
58
  }
56
59
  }
@@ -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":[]}