@fieldnotes/sync-server 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +265 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -13
- package/dist/index.d.ts +58 -13
- package/dist/index.js +271 -31
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -36,6 +36,7 @@ var import_sync = require("@fieldnotes/sync");
|
|
|
36
36
|
var MemoryHubBackend = class {
|
|
37
37
|
rooms = /* @__PURE__ */ new Map();
|
|
38
38
|
roomLayers = /* @__PURE__ */ new Map();
|
|
39
|
+
roomFog = /* @__PURE__ */ new Map();
|
|
39
40
|
room(id) {
|
|
40
41
|
let r = this.rooms.get(id);
|
|
41
42
|
if (!r) {
|
|
@@ -74,6 +75,26 @@ var MemoryHubBackend = class {
|
|
|
74
75
|
async applyLayerRecord(room, record) {
|
|
75
76
|
this.layers(room).set(record.id, record);
|
|
76
77
|
}
|
|
78
|
+
fog(room) {
|
|
79
|
+
let ledger = this.roomFog.get(room);
|
|
80
|
+
if (!ledger) {
|
|
81
|
+
ledger = new import_sync.FogLedger();
|
|
82
|
+
this.roomFog.set(room, ledger);
|
|
83
|
+
}
|
|
84
|
+
return ledger;
|
|
85
|
+
}
|
|
86
|
+
async fogSnapshot(room) {
|
|
87
|
+
return this.fog(room).snapshot();
|
|
88
|
+
}
|
|
89
|
+
async applyFogMeta(room, record) {
|
|
90
|
+
return this.fog(room).applyMeta(record);
|
|
91
|
+
}
|
|
92
|
+
async applyFogTile(room, record) {
|
|
93
|
+
return this.fog(room).applyTile(record);
|
|
94
|
+
}
|
|
95
|
+
async applyFogPatch(room, records) {
|
|
96
|
+
return this.fog(room).applyPatch(records);
|
|
97
|
+
}
|
|
77
98
|
};
|
|
78
99
|
|
|
79
100
|
// src/hub-fanout.ts
|
|
@@ -101,6 +122,7 @@ var DEFAULT_MAX_PENDING_AUTH_BYTES = 2 * 1024 * 1024;
|
|
|
101
122
|
var DEFAULT_MESSAGES_PER_SECOND = 120;
|
|
102
123
|
var DEFAULT_MESSAGE_BURST = 240;
|
|
103
124
|
var DEFAULT_PRESENCE_THROTTLE_MS = 50;
|
|
125
|
+
var DEFAULT_MAX_PRESENCE_LANES = 16;
|
|
104
126
|
function hasJsonDepthAtMost(message, maxDepth) {
|
|
105
127
|
let depth = 0;
|
|
106
128
|
let inString = false;
|
|
@@ -156,6 +178,16 @@ function isFanoutOp(op) {
|
|
|
156
178
|
if (o.kind === "remove") return typeof o.id === "string";
|
|
157
179
|
return o.kind === "clear";
|
|
158
180
|
}
|
|
181
|
+
var FALLBACK_PRESENCE_LANE = "";
|
|
182
|
+
var MAX_PRESENCE_LANE_LENGTH = 64;
|
|
183
|
+
function presenceLaneOf(data) {
|
|
184
|
+
if (typeof data !== "object" || data === null) return FALLBACK_PRESENCE_LANE;
|
|
185
|
+
const kind = data.kind;
|
|
186
|
+
if (typeof kind !== "string" || kind.length === 0 || kind.length > MAX_PRESENCE_LANE_LENGTH) {
|
|
187
|
+
return FALLBACK_PRESENCE_LANE;
|
|
188
|
+
}
|
|
189
|
+
return kind;
|
|
190
|
+
}
|
|
159
191
|
function isLayerOp(op) {
|
|
160
192
|
if (typeof op !== "object" || op === null) return false;
|
|
161
193
|
const k = op.kind;
|
|
@@ -177,6 +209,11 @@ function isPresenceOp(op) {
|
|
|
177
209
|
const k = op.kind;
|
|
178
210
|
return k === "presence" || k === "presence-leave";
|
|
179
211
|
}
|
|
212
|
+
function isFogOp(op) {
|
|
213
|
+
if (typeof op !== "object" || op === null) return false;
|
|
214
|
+
const k = op.kind;
|
|
215
|
+
return k === "fog-meta" || k === "fog-patch";
|
|
216
|
+
}
|
|
180
217
|
var SyncHub = class {
|
|
181
218
|
backend;
|
|
182
219
|
conns = /* @__PURE__ */ new Map();
|
|
@@ -190,22 +227,48 @@ var SyncHub = class {
|
|
|
190
227
|
fanoutUnsub;
|
|
191
228
|
authorize;
|
|
192
229
|
authorizeLayer;
|
|
230
|
+
authorizeFog;
|
|
193
231
|
canRead;
|
|
194
|
-
/** Fallback layer-record store for backends without layer persistence. */
|
|
195
232
|
memoryLayers = /* @__PURE__ */ new Map();
|
|
233
|
+
memoryFog = /* @__PURE__ */ new Map();
|
|
196
234
|
maxJsonDepth;
|
|
197
235
|
presenceThrottleMs;
|
|
198
|
-
|
|
199
|
-
|
|
236
|
+
maxPresenceLanes;
|
|
237
|
+
/**
|
|
238
|
+
* Presence throttle state keyed by connection, then by lane. A lane is the
|
|
239
|
+
* payload's `kind` (a non-empty string of at most 64 chars) or the reserved
|
|
240
|
+
* fallback lane `''`, so a rapid stream of one kind (awareness cursors) can
|
|
241
|
+
* never replace a pending frame of another kind (a ping, a path `cleared`).
|
|
242
|
+
* Within a lane the newest payload wins. The lane count per connection is
|
|
243
|
+
* capped by `maxPresenceLanes`, counting the fallback lane, so a client
|
|
244
|
+
* cannot mint timers by varying `kind`.
|
|
245
|
+
*/
|
|
246
|
+
presenceLanes = /* @__PURE__ */ new Map();
|
|
200
247
|
constructor(options = {}) {
|
|
201
248
|
this.backend = options.backend ?? new MemoryHubBackend();
|
|
249
|
+
const fogMethods = [
|
|
250
|
+
this.backend.fogSnapshot,
|
|
251
|
+
this.backend.applyFogMeta,
|
|
252
|
+
this.backend.applyFogPatch
|
|
253
|
+
];
|
|
254
|
+
if ((fogMethods.some(Boolean) || Boolean(this.backend.applyFogTile)) && !fogMethods.every(Boolean)) {
|
|
255
|
+
throw new Error(
|
|
256
|
+
"HubBackend fog support is an all-or-none capability: fogSnapshot, applyFogMeta, and applyFogPatch are required"
|
|
257
|
+
);
|
|
258
|
+
}
|
|
202
259
|
this.instanceId = options.instanceId ?? generateInstanceId();
|
|
203
260
|
this.fanout = options.fanout ?? new InMemoryHubFanout();
|
|
204
261
|
this.authorize = options.authorize;
|
|
205
262
|
this.authorizeLayer = options.authorizeLayer;
|
|
263
|
+
this.authorizeFog = options.authorizeFog;
|
|
206
264
|
this.canRead = options.canRead;
|
|
207
265
|
this.maxJsonDepth = options.maxJsonDepth ?? DEFAULT_MAX_JSON_DEPTH;
|
|
208
266
|
this.presenceThrottleMs = options.presenceThrottleMs ?? DEFAULT_PRESENCE_THROTTLE_MS;
|
|
267
|
+
const maxPresenceLanes = options.maxPresenceLanes ?? DEFAULT_MAX_PRESENCE_LANES;
|
|
268
|
+
if (!Number.isFinite(maxPresenceLanes) || maxPresenceLanes < 1) {
|
|
269
|
+
throw new RangeError("maxPresenceLanes must be a finite number of at least 1");
|
|
270
|
+
}
|
|
271
|
+
this.maxPresenceLanes = Math.floor(maxPresenceLanes);
|
|
209
272
|
this.fanoutUnsub = this.fanout.subscribe((payload) => this.onFanout(payload));
|
|
210
273
|
}
|
|
211
274
|
addConnection(conn) {
|
|
@@ -223,10 +286,7 @@ var SyncHub = class {
|
|
|
223
286
|
this.conns.delete(connId);
|
|
224
287
|
const room = conn.room;
|
|
225
288
|
const hadPresence = this.presenceConnections.delete(connId);
|
|
226
|
-
this.
|
|
227
|
-
const pendingPresence = this.pendingPresence.get(connId);
|
|
228
|
-
if (pendingPresence) clearTimeout(pendingPresence.timer);
|
|
229
|
-
this.pendingPresence.delete(connId);
|
|
289
|
+
this.clearPresenceLanes(connId);
|
|
230
290
|
const members = this.rooms.get(room);
|
|
231
291
|
if (members) {
|
|
232
292
|
members.delete(connId);
|
|
@@ -277,16 +337,19 @@ var SyncHub = class {
|
|
|
277
337
|
const all = await this.backend.snapshot(conn.room);
|
|
278
338
|
const elements = this.canRead ? all.filter((el) => this.mayRead(conn, el.audience)) : all;
|
|
279
339
|
const layers = await this.getLayerRecords(conn.room);
|
|
280
|
-
conn.
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
);
|
|
340
|
+
const fog = await this.getFogSnapshot(conn.room);
|
|
341
|
+
const snapshotOp = {
|
|
342
|
+
kind: "snapshot",
|
|
343
|
+
to: env.from,
|
|
344
|
+
elements
|
|
345
|
+
};
|
|
346
|
+
if (layers.length > 0) snapshotOp["layers"] = layers;
|
|
347
|
+
if (fog) snapshotOp["fog"] = fog;
|
|
348
|
+
conn.send(JSON.stringify({ from: HUB_FROM, op: snapshotOp }));
|
|
288
349
|
} else if (op.kind === "layer-upsert" || op.kind === "layer-remove") {
|
|
289
350
|
await this.processLayerOp(conn, op);
|
|
351
|
+
} else if (op.kind === "fog-meta" || op.kind === "fog-patch") {
|
|
352
|
+
await this.processFogOp(conn, op);
|
|
290
353
|
} else if (op.kind === "upsert" || op.kind === "remove" || op.kind === "clear") {
|
|
291
354
|
const id = op.kind === "upsert" ? op.element.id : op.kind === "remove" ? op.id : void 0;
|
|
292
355
|
const needCurrent = (this.authorize || this.canRead) && id !== void 0;
|
|
@@ -392,6 +455,121 @@ var SyncHub = class {
|
|
|
392
455
|
}
|
|
393
456
|
map.set(record.id, record);
|
|
394
457
|
}
|
|
458
|
+
// ── Fog processing ──
|
|
459
|
+
fogBackend() {
|
|
460
|
+
const { fogSnapshot, applyFogMeta, applyFogPatch } = this.backend;
|
|
461
|
+
if (!fogSnapshot || !applyFogMeta || !applyFogPatch) return null;
|
|
462
|
+
return {
|
|
463
|
+
fogSnapshot: fogSnapshot.bind(this.backend),
|
|
464
|
+
applyFogMeta: applyFogMeta.bind(this.backend),
|
|
465
|
+
applyFogPatch: applyFogPatch.bind(this.backend)
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
getFogLedger(room) {
|
|
469
|
+
let ledger = this.memoryFog.get(room);
|
|
470
|
+
if (!ledger) {
|
|
471
|
+
ledger = new import_sync2.FogLedger();
|
|
472
|
+
this.memoryFog.set(room, ledger);
|
|
473
|
+
}
|
|
474
|
+
return ledger;
|
|
475
|
+
}
|
|
476
|
+
async getFogSnapshot(room) {
|
|
477
|
+
const backend = this.fogBackend();
|
|
478
|
+
if (backend) return backend.fogSnapshot(room);
|
|
479
|
+
return this.getFogLedger(room).snapshot();
|
|
480
|
+
}
|
|
481
|
+
async applyFogMeta(room, record) {
|
|
482
|
+
const backend = this.fogBackend();
|
|
483
|
+
if (backend) return backend.applyFogMeta(room, record);
|
|
484
|
+
return this.getFogLedger(room).applyMeta(record);
|
|
485
|
+
}
|
|
486
|
+
async applyFogPatch(room, records) {
|
|
487
|
+
const backend = this.fogBackend();
|
|
488
|
+
if (backend) return backend.applyFogPatch(room, records);
|
|
489
|
+
return this.getFogLedger(room).applyPatch(records);
|
|
490
|
+
}
|
|
491
|
+
async processFogOp(conn, op) {
|
|
492
|
+
const current = await this.getFogSnapshot(conn.room);
|
|
493
|
+
if (this.authorizeFog) {
|
|
494
|
+
const allowed = await this.authorizeFog({
|
|
495
|
+
userId: conn.userId,
|
|
496
|
+
role: conn.role,
|
|
497
|
+
room: conn.room,
|
|
498
|
+
op,
|
|
499
|
+
current
|
|
500
|
+
});
|
|
501
|
+
if (!allowed) {
|
|
502
|
+
if (op.kind === "fog-meta") {
|
|
503
|
+
const correction = current?.meta ?? { version: 1, editor: HUB_FROM };
|
|
504
|
+
conn.send(
|
|
505
|
+
JSON.stringify({ from: HUB_FROM, op: { kind: "fog-meta", record: correction } })
|
|
506
|
+
);
|
|
507
|
+
} else if (current?.meta.definition) {
|
|
508
|
+
const corrections = op.tiles.map((t) => {
|
|
509
|
+
const existing = current.tiles.find((ct) => ct.x === t.x && ct.y === t.y);
|
|
510
|
+
return existing ?? {
|
|
511
|
+
generation: current.meta.definition?.generation ?? op.generation,
|
|
512
|
+
x: t.x,
|
|
513
|
+
y: t.y,
|
|
514
|
+
version: 1,
|
|
515
|
+
editor: HUB_FROM
|
|
516
|
+
};
|
|
517
|
+
});
|
|
518
|
+
conn.send(
|
|
519
|
+
JSON.stringify({
|
|
520
|
+
from: HUB_FROM,
|
|
521
|
+
op: {
|
|
522
|
+
kind: "fog-patch",
|
|
523
|
+
generation: current.meta.definition.generation,
|
|
524
|
+
tiles: corrections
|
|
525
|
+
}
|
|
526
|
+
})
|
|
527
|
+
);
|
|
528
|
+
} else {
|
|
529
|
+
conn.send(
|
|
530
|
+
JSON.stringify({
|
|
531
|
+
from: HUB_FROM,
|
|
532
|
+
op: {
|
|
533
|
+
kind: "fog-meta",
|
|
534
|
+
record: current?.meta ?? { version: 1, editor: HUB_FROM }
|
|
535
|
+
}
|
|
536
|
+
})
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
let outbound;
|
|
543
|
+
if (op.kind === "fog-meta") {
|
|
544
|
+
const result = await this.applyFogMeta(conn.room, op.record);
|
|
545
|
+
if (!result.accepted) {
|
|
546
|
+
if (result.correction) {
|
|
547
|
+
conn.send(
|
|
548
|
+
JSON.stringify({ from: HUB_FROM, op: { kind: "fog-meta", record: result.correction } })
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
outbound = op;
|
|
554
|
+
} else {
|
|
555
|
+
const { accepted, corrections } = await this.applyFogPatch(conn.room, op.tiles);
|
|
556
|
+
if (corrections.length > 0) {
|
|
557
|
+
const correctionGeneration = corrections[0]?.generation ?? op.generation;
|
|
558
|
+
conn.send(
|
|
559
|
+
JSON.stringify({
|
|
560
|
+
from: HUB_FROM,
|
|
561
|
+
op: { kind: "fog-patch", generation: correctionGeneration, tiles: corrections }
|
|
562
|
+
})
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
if (accepted.length === 0) return;
|
|
566
|
+
outbound = { kind: "fog-patch", generation: op.generation, tiles: accepted };
|
|
567
|
+
}
|
|
568
|
+
await this.fanout.publish(
|
|
569
|
+
JSON.stringify({ o: this.instanceId, room: conn.room, from: conn.id, op: outbound })
|
|
570
|
+
);
|
|
571
|
+
this.relayToRoom(conn.room, conn.id, JSON.stringify({ from: conn.id, op: outbound }));
|
|
572
|
+
}
|
|
395
573
|
mayRead(conn, audience) {
|
|
396
574
|
if (!this.canRead) return true;
|
|
397
575
|
return this.canRead({ userId: conn.userId, role: conn.role, room: conn.room, audience });
|
|
@@ -432,34 +610,63 @@ var SyncHub = class {
|
|
|
432
610
|
})
|
|
433
611
|
);
|
|
434
612
|
}
|
|
613
|
+
clearPresenceLanes(connId) {
|
|
614
|
+
const lanes = this.presenceLanes.get(connId);
|
|
615
|
+
if (!lanes) return;
|
|
616
|
+
for (const lane of lanes.values()) {
|
|
617
|
+
if (lane.pending) clearTimeout(lane.pending.timer);
|
|
618
|
+
}
|
|
619
|
+
this.presenceLanes.delete(connId);
|
|
620
|
+
}
|
|
435
621
|
schedulePresence(conn, data) {
|
|
436
622
|
if (this.presenceThrottleMs <= 0) {
|
|
437
623
|
this.broadcastClientPresence(conn, data);
|
|
438
624
|
return;
|
|
439
625
|
}
|
|
626
|
+
const lane = this.presenceLaneFor(conn.id, presenceLaneOf(data));
|
|
440
627
|
const now = Date.now();
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
628
|
+
if (lane.lastSentAt === void 0 || now - lane.lastSentAt >= this.presenceThrottleMs) {
|
|
629
|
+
if (lane.pending) {
|
|
630
|
+
clearTimeout(lane.pending.timer);
|
|
631
|
+
lane.pending = null;
|
|
632
|
+
}
|
|
633
|
+
lane.lastSentAt = now;
|
|
444
634
|
this.broadcastClientPresence(conn, data);
|
|
445
635
|
return;
|
|
446
636
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
existing.data = data;
|
|
637
|
+
if (lane.pending) {
|
|
638
|
+
lane.pending.data = data;
|
|
450
639
|
return;
|
|
451
640
|
}
|
|
452
641
|
const timer = setTimeout(
|
|
453
642
|
() => {
|
|
454
|
-
const pending =
|
|
455
|
-
|
|
643
|
+
const pending = lane.pending;
|
|
644
|
+
lane.pending = null;
|
|
456
645
|
if (!pending || !this.conns.has(conn.id)) return;
|
|
457
|
-
|
|
646
|
+
lane.lastSentAt = Date.now();
|
|
458
647
|
this.broadcastClientPresence(conn, pending.data);
|
|
459
648
|
},
|
|
460
|
-
this.presenceThrottleMs - (now - lastSentAt)
|
|
649
|
+
this.presenceThrottleMs - (now - lane.lastSentAt)
|
|
461
650
|
);
|
|
462
|
-
|
|
651
|
+
lane.pending = { data, timer };
|
|
652
|
+
}
|
|
653
|
+
presenceLaneFor(connId, requested) {
|
|
654
|
+
let lanes = this.presenceLanes.get(connId);
|
|
655
|
+
if (!lanes) {
|
|
656
|
+
lanes = /* @__PURE__ */ new Map();
|
|
657
|
+
this.presenceLanes.set(connId, lanes);
|
|
658
|
+
}
|
|
659
|
+
let key = requested;
|
|
660
|
+
if (key !== FALLBACK_PRESENCE_LANE && !lanes.has(key)) {
|
|
661
|
+
const named = lanes.size - (lanes.has(FALLBACK_PRESENCE_LANE) ? 1 : 0);
|
|
662
|
+
if (named >= this.maxPresenceLanes - 1) key = FALLBACK_PRESENCE_LANE;
|
|
663
|
+
}
|
|
664
|
+
let lane = lanes.get(key);
|
|
665
|
+
if (!lane) {
|
|
666
|
+
lane = { lastSentAt: void 0, pending: null };
|
|
667
|
+
lanes.set(key, lane);
|
|
668
|
+
}
|
|
669
|
+
return lane;
|
|
463
670
|
}
|
|
464
671
|
broadcastLeave(room, from) {
|
|
465
672
|
const message = JSON.stringify({ from, op: { kind: "presence-leave" } });
|
|
@@ -543,6 +750,25 @@ var SyncHub = class {
|
|
|
543
750
|
this.relayToRoom(env.room, void 0, JSON.stringify({ from: env.from, op }));
|
|
544
751
|
return;
|
|
545
752
|
}
|
|
753
|
+
if (isFogOp(op)) {
|
|
754
|
+
const previous = this.roomQueues.get(env.room) ?? Promise.resolve();
|
|
755
|
+
const operation = previous.then(async () => {
|
|
756
|
+
const accepted = await this.applyFanoutFogOp(env.room, op);
|
|
757
|
+
if (accepted) {
|
|
758
|
+
this.relayToRoom(
|
|
759
|
+
env.room,
|
|
760
|
+
void 0,
|
|
761
|
+
JSON.stringify({ from: env.from, op: accepted })
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
this.roomQueues.set(
|
|
766
|
+
env.room,
|
|
767
|
+
operation.catch(() => {
|
|
768
|
+
})
|
|
769
|
+
);
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
546
772
|
if (!isFanoutOp(op)) return;
|
|
547
773
|
const prevAudience = typeof env.prev === "string" ? env.prev : void 0;
|
|
548
774
|
const prevExisted = env.existed === true;
|
|
@@ -554,9 +780,17 @@ var SyncHub = class {
|
|
|
554
780
|
if (current && !(0, import_sync2.isNewerLayerRecord)(record, current)) return;
|
|
555
781
|
await this.applyLayerRecord(room, record);
|
|
556
782
|
}
|
|
783
|
+
async applyFanoutFogOp(room, op) {
|
|
784
|
+
if (this.backend.sharedAcrossInstances === true && this.fogBackend()) return op;
|
|
785
|
+
if (op.kind === "fog-meta") {
|
|
786
|
+
const result = await this.applyFogMeta(room, op.record);
|
|
787
|
+
return result.accepted ? op : null;
|
|
788
|
+
}
|
|
789
|
+
const { accepted } = await this.applyFogPatch(room, op.tiles);
|
|
790
|
+
return accepted.length > 0 ? { ...op, tiles: accepted } : null;
|
|
791
|
+
}
|
|
557
792
|
close() {
|
|
558
|
-
for (const
|
|
559
|
-
this.pendingPresence.clear();
|
|
793
|
+
for (const connId of [...this.presenceLanes.keys()]) this.clearPresenceLanes(connId);
|
|
560
794
|
this.fanoutUnsub();
|
|
561
795
|
}
|
|
562
796
|
};
|
|
@@ -645,9 +879,11 @@ function createSyncServer(options = {}) {
|
|
|
645
879
|
instanceId: options.instanceId,
|
|
646
880
|
authorize: options.authorize,
|
|
647
881
|
authorizeLayer: options.authorizeLayer,
|
|
882
|
+
authorizeFog: options.authorizeFog,
|
|
648
883
|
canRead: options.canRead,
|
|
649
884
|
maxJsonDepth: options.maxJsonDepth ?? DEFAULT_MAX_JSON_DEPTH,
|
|
650
|
-
presenceThrottleMs: options.presenceThrottleMs ?? DEFAULT_PRESENCE_THROTTLE_MS
|
|
885
|
+
presenceThrottleMs: options.presenceThrottleMs ?? DEFAULT_PRESENCE_THROTTLE_MS,
|
|
886
|
+
maxPresenceLanes: options.maxPresenceLanes
|
|
651
887
|
});
|
|
652
888
|
const maxMessageBytes = options.maxMessageBytes ?? DEFAULT_MAX_MESSAGE_BYTES;
|
|
653
889
|
const wss = options.server ? new import_ws.WebSocketServer({ server: options.server, maxPayload: maxMessageBytes }) : new import_ws.WebSocketServer({ port: options.port ?? 0, maxPayload: maxMessageBytes });
|