@crowdedkingdoms/crowdy-dsh 0.3.0 → 0.3.1-dev.1
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/dsh-web/BUILD.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "@crowdedkingdoms/crowdy-dsh",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"builtAt": "2026-09-
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"builtAt": "2026-09-13T20:32:20.481Z",
|
|
5
5
|
"source": {
|
|
6
6
|
"repository": "CrowdedKingdoms/crowdy-dsh",
|
|
7
|
-
"commit": "
|
|
7
|
+
"commit": "fefcd8ee55fc6df8b16a09f6db19de1e8a3189db",
|
|
8
8
|
"dirty": false
|
|
9
9
|
},
|
|
10
10
|
"upstream": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"crowdyjs": {
|
|
17
17
|
"name": "@crowdedkingdoms/crowdyjs",
|
|
18
|
-
"version": "17.0.1",
|
|
18
|
+
"version": "17.1.0-dev.1",
|
|
19
19
|
"source": "node_modules"
|
|
20
20
|
},
|
|
21
21
|
"files": {
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"manifest.webmanifest": "sha256:9b54d57eea00f2fdd1affe6e7999a4209a515755f12ac1a3299da2d55e178d4c",
|
|
113
113
|
"preview/bootstrap-CYECZNXt.js": "sha256:9f303a0485c0badfdd19fad0c357ef050c5b9a343744ab5bf0c70015e7d95092",
|
|
114
114
|
"preview/crowdy-boot-Cklh1qNl.js": "sha256:b21e8eb126e1cd8a52159d2d577e610df6c8af36a436f9ed5028cfabd11a85ff",
|
|
115
|
-
"preview/vfs-image.tar.gz": "sha256:
|
|
115
|
+
"preview/vfs-image.tar.gz": "sha256:721074e8f744bc811e7c9cf18d486682cce88264014412671b7d5436a834cce6",
|
|
116
116
|
"preview/worker-C8-_ANaz.js": "sha256:81099e5732dfe0c32bacd5897316b7956c5a0a22da01b4a0c6e21d0a3b9d9aa1"
|
|
117
117
|
}
|
|
118
118
|
}
|
|
Binary file
|
|
@@ -5814,6 +5814,44 @@ function validateChunkCoordinates(chunk) {
|
|
|
5814
5814
|
}
|
|
5815
5815
|
|
|
5816
5816
|
var RELAY_MAX_DATAGRAM_BYTES = 1232;
|
|
5817
|
+
var BUNDLE_HEADER_BYTES = 1;
|
|
5818
|
+
var BUNDLE_LENGTH_PREFIX_BYTES = 2;
|
|
5819
|
+
var RELAY_MAX_BUNDLE_MEMBERS = 32;
|
|
5820
|
+
var RELAY_MAX_BUNDLE_MEMBER_BYTES = RELAY_MAX_DATAGRAM_BYTES - BUNDLE_HEADER_BYTES - BUNDLE_LENGTH_PREFIX_BYTES;
|
|
5821
|
+
function bundleSizeOf(members) {
|
|
5822
|
+
let size = BUNDLE_HEADER_BYTES;
|
|
5823
|
+
for (const m of members)
|
|
5824
|
+
size += BUNDLE_LENGTH_PREFIX_BYTES + m.length;
|
|
5825
|
+
return size;
|
|
5826
|
+
}
|
|
5827
|
+
function packMessageBundle(members) {
|
|
5828
|
+
if (members.length === 0)
|
|
5829
|
+
throw new Error("MESSAGE_BUNDLE needs at least one member");
|
|
5830
|
+
if (members.length > RELAY_MAX_BUNDLE_MEMBERS) {
|
|
5831
|
+
throw new Error(`MESSAGE_BUNDLE holds at most ${RELAY_MAX_BUNDLE_MEMBERS} members`);
|
|
5832
|
+
}
|
|
5833
|
+
for (const m of members) {
|
|
5834
|
+
if (m.length === 0)
|
|
5835
|
+
throw new Error("MESSAGE_BUNDLE member cannot be empty");
|
|
5836
|
+
}
|
|
5837
|
+
if (members.length === 1)
|
|
5838
|
+
return members[0];
|
|
5839
|
+
const size = bundleSizeOf(members);
|
|
5840
|
+
if (size > RELAY_MAX_DATAGRAM_BYTES) {
|
|
5841
|
+
throw new Error(`MESSAGE_BUNDLE of ${size} bytes exceeds ${RELAY_MAX_DATAGRAM_BYTES}`);
|
|
5842
|
+
}
|
|
5843
|
+
const out = new Uint8Array(size);
|
|
5844
|
+
const view = new DataView(out.buffer);
|
|
5845
|
+
out[0] = WireMessageType.MESSAGE_BUNDLE;
|
|
5846
|
+
let off = BUNDLE_HEADER_BYTES;
|
|
5847
|
+
for (const m of members) {
|
|
5848
|
+
view.setUint16(off, m.length, true);
|
|
5849
|
+
off += BUNDLE_LENGTH_PREFIX_BYTES;
|
|
5850
|
+
out.set(m, off);
|
|
5851
|
+
off += m.length;
|
|
5852
|
+
}
|
|
5853
|
+
return out;
|
|
5854
|
+
}
|
|
5817
5855
|
var WireMessageType = {
|
|
5818
5856
|
MESSAGE_BUNDLE: 2,
|
|
5819
5857
|
GENERIC_ERROR_MESSAGE: 3,
|
|
@@ -6252,6 +6290,10 @@ function isSameEstate(current, candidate) {
|
|
|
6252
6290
|
const site = (h) => h.split(".").slice(-2).join(".");
|
|
6253
6291
|
return site(a) === site(b) && site(a).includes(".");
|
|
6254
6292
|
}
|
|
6293
|
+
function documentIsHidden() {
|
|
6294
|
+
const doc = globalThis.document;
|
|
6295
|
+
return doc?.visibilityState === "hidden";
|
|
6296
|
+
}
|
|
6255
6297
|
function base64UrlEncode(value) {
|
|
6256
6298
|
return btoa(value).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
6257
6299
|
}
|
|
@@ -6267,11 +6309,27 @@ var BinaryRelayTransport = class {
|
|
|
6267
6309
|
this.everReady = false;
|
|
6268
6310
|
this.retryTimer = null;
|
|
6269
6311
|
this.generation = 0;
|
|
6312
|
+
this.pendingMembers = [];
|
|
6313
|
+
this.pendingBytes = 0;
|
|
6314
|
+
this.bundleTimer = null;
|
|
6315
|
+
this.sendStats = {
|
|
6316
|
+
messagesSent: 0,
|
|
6317
|
+
framesSent: 0,
|
|
6318
|
+
bundlesSent: 0,
|
|
6319
|
+
bytesSent: 0,
|
|
6320
|
+
messagesDropped: 0
|
|
6321
|
+
};
|
|
6270
6322
|
this.url = config.url;
|
|
6271
6323
|
this.logger = config.logger ?? silentLogger;
|
|
6272
6324
|
this.retryAttempts = config.retryAttempts ?? 8;
|
|
6273
6325
|
this.retryInitialDelayMs = config.retryInitialDelayMs ?? 250;
|
|
6274
6326
|
this.retryMaxDelayMs = config.retryMaxDelayMs ?? 5e3;
|
|
6327
|
+
this.bundleSends = config.bundleSends ?? true;
|
|
6328
|
+
this.bundleWindowMs = Math.max(0, config.bundleWindowMs ?? 1);
|
|
6329
|
+
}
|
|
6330
|
+
/** Snapshot of the uplink counters. */
|
|
6331
|
+
stats() {
|
|
6332
|
+
return { ...this.sendStats };
|
|
6275
6333
|
}
|
|
6276
6334
|
/** True when the socket is open and the `ready` handshake completed. */
|
|
6277
6335
|
isReady() {
|
|
@@ -6290,6 +6348,7 @@ var BinaryRelayTransport = class {
|
|
|
6290
6348
|
}
|
|
6291
6349
|
disconnect() {
|
|
6292
6350
|
this.desired = false;
|
|
6351
|
+
this.flushSends();
|
|
6293
6352
|
if (this.retryTimer) {
|
|
6294
6353
|
clearTimeout(this.retryTimer);
|
|
6295
6354
|
this.retryTimer = null;
|
|
@@ -6316,7 +6375,11 @@ var BinaryRelayTransport = class {
|
|
|
6316
6375
|
this.appId = appId;
|
|
6317
6376
|
this.open();
|
|
6318
6377
|
}
|
|
6319
|
-
/**
|
|
6378
|
+
/**
|
|
6379
|
+
* Send one pre-serialized, signed Buddy message. With `bundleSends` it joins
|
|
6380
|
+
* the pending MESSAGE_BUNDLE and leaves with it (see {@link flushSends});
|
|
6381
|
+
* otherwise it is one BINARY frame right now.
|
|
6382
|
+
*/
|
|
6320
6383
|
sendFrame(frame) {
|
|
6321
6384
|
if (!this.isReady() || !this.ws) {
|
|
6322
6385
|
throw new CrowdyRealtimeError("Binary relay is not connected", {
|
|
@@ -6324,7 +6387,63 @@ var BinaryRelayTransport = class {
|
|
|
6324
6387
|
retryable: true
|
|
6325
6388
|
});
|
|
6326
6389
|
}
|
|
6390
|
+
if (frame.length === 0)
|
|
6391
|
+
return;
|
|
6392
|
+
this.sendStats.messagesSent += 1;
|
|
6393
|
+
if (!this.bundleSends) {
|
|
6394
|
+
this.transmit(frame, false);
|
|
6395
|
+
return;
|
|
6396
|
+
}
|
|
6397
|
+
if (frame.length > RELAY_MAX_BUNDLE_MEMBER_BYTES) {
|
|
6398
|
+
this.flushSends();
|
|
6399
|
+
this.transmit(frame, false);
|
|
6400
|
+
return;
|
|
6401
|
+
}
|
|
6402
|
+
const wouldBe = this.pendingBytes + BUNDLE_LENGTH_PREFIX_BYTES + frame.length;
|
|
6403
|
+
if (this.pendingMembers.length > 0 && (wouldBe > RELAY_MAX_DATAGRAM_BYTES || this.pendingMembers.length >= RELAY_MAX_BUNDLE_MEMBERS)) {
|
|
6404
|
+
this.flushSends();
|
|
6405
|
+
}
|
|
6406
|
+
if (this.pendingMembers.length === 0) {
|
|
6407
|
+
this.pendingBytes = bundleSizeOf([]);
|
|
6408
|
+
this.bundleTimer = setTimeout(() => {
|
|
6409
|
+
this.bundleTimer = null;
|
|
6410
|
+
this.flushSends();
|
|
6411
|
+
}, this.bundleWindowMs);
|
|
6412
|
+
}
|
|
6413
|
+
this.pendingMembers.push(frame);
|
|
6414
|
+
this.pendingBytes += BUNDLE_LENGTH_PREFIX_BYTES + frame.length;
|
|
6415
|
+
if (documentIsHidden())
|
|
6416
|
+
this.flushSends();
|
|
6417
|
+
}
|
|
6418
|
+
/**
|
|
6419
|
+
* Put the pending bundle on the wire now instead of at the end of the
|
|
6420
|
+
* window. Call it at the end of a frame when that frame's sends should not
|
|
6421
|
+
* wait. No-op when nothing is pending.
|
|
6422
|
+
*/
|
|
6423
|
+
flushSends() {
|
|
6424
|
+
if (this.bundleTimer) {
|
|
6425
|
+
clearTimeout(this.bundleTimer);
|
|
6426
|
+
this.bundleTimer = null;
|
|
6427
|
+
}
|
|
6428
|
+
const members = this.pendingMembers;
|
|
6429
|
+
if (members.length === 0)
|
|
6430
|
+
return;
|
|
6431
|
+
this.pendingMembers = [];
|
|
6432
|
+
this.pendingBytes = 0;
|
|
6433
|
+
if (!this.isReady() || !this.ws) {
|
|
6434
|
+
this.sendStats.messagesDropped += members.length;
|
|
6435
|
+
return;
|
|
6436
|
+
}
|
|
6437
|
+
this.transmit(packMessageBundle(members), members.length > 1);
|
|
6438
|
+
}
|
|
6439
|
+
transmit(frame, wrapped) {
|
|
6440
|
+
if (!this.ws)
|
|
6441
|
+
return;
|
|
6327
6442
|
this.ws.send(frame);
|
|
6443
|
+
this.sendStats.framesSent += 1;
|
|
6444
|
+
this.sendStats.bytesSent += frame.length;
|
|
6445
|
+
if (wrapped)
|
|
6446
|
+
this.sendStats.bundlesSent += 1;
|
|
6328
6447
|
}
|
|
6329
6448
|
open() {
|
|
6330
6449
|
const token = this.callbacks.getToken();
|
|
@@ -6523,6 +6642,8 @@ var RealtimeClient = class {
|
|
|
6523
6642
|
this.lbCookieStore = config.lbCookieStore;
|
|
6524
6643
|
this.wsUplinkMutations = config.wsUplinkMutations === true;
|
|
6525
6644
|
this.binaryTransport = config.binaryTransport === true;
|
|
6645
|
+
this.bundleSends = config.bundleSends ?? true;
|
|
6646
|
+
this.bundleWindowMs = config.bundleWindowMs ?? 1;
|
|
6526
6647
|
this.binaryRelayUrl = config.binaryRelayUrl ?? deriveBinaryRelayUrl(this.wsUrl);
|
|
6527
6648
|
this.session.onChange((token) => {
|
|
6528
6649
|
if (!this.desired)
|
|
@@ -6736,6 +6857,23 @@ var RealtimeClient = class {
|
|
|
6736
6857
|
usingBinaryTransport() {
|
|
6737
6858
|
return this.binaryTransport && !this.binaryUnavailable;
|
|
6738
6859
|
}
|
|
6860
|
+
/**
|
|
6861
|
+
* Put the binary relay's pending `MESSAGE_BUNDLE` on the wire now instead of
|
|
6862
|
+
* at the end of {@link RealtimeConfig.bundleWindowMs}. Call it at the end of
|
|
6863
|
+
* a frame when that frame's sends should not wait. No-op on the GraphQL
|
|
6864
|
+
* transport or when nothing is pending.
|
|
6865
|
+
*/
|
|
6866
|
+
flushSends() {
|
|
6867
|
+
this.binaryRelay?.flushSends();
|
|
6868
|
+
}
|
|
6869
|
+
/**
|
|
6870
|
+
* Uplink counters of the binary relay (messages, frames, bundles, bytes,
|
|
6871
|
+
* drops), or `null` when the relay has not been created. These are a local
|
|
6872
|
+
* diagnostic, not a bill.
|
|
6873
|
+
*/
|
|
6874
|
+
binaryRelayStats() {
|
|
6875
|
+
return this.binaryRelay?.stats() ?? null;
|
|
6876
|
+
}
|
|
6739
6877
|
/**
|
|
6740
6878
|
* Serialize (with the session signing context) and send one datagram over
|
|
6741
6879
|
* the binary relay. Throws `BINARY_RELAY_UNAVAILABLE` when the relay is not
|
|
@@ -6938,7 +7076,9 @@ var RealtimeClient = class {
|
|
|
6938
7076
|
retryAttempts: this.retryAttempts,
|
|
6939
7077
|
retryInitialDelayMs: this.retryInitialDelayMs,
|
|
6940
7078
|
retryMaxDelayMs: this.retryMaxDelayMs,
|
|
6941
|
-
logger: this.logger
|
|
7079
|
+
logger: this.logger,
|
|
7080
|
+
bundleSends: this.bundleSends,
|
|
7081
|
+
bundleWindowMs: this.bundleWindowMs
|
|
6942
7082
|
}, {
|
|
6943
7083
|
getToken: () => this.session.getToken(),
|
|
6944
7084
|
onNotification: (notification) => this.dispatch(notification),
|
|
@@ -15786,6 +15926,15 @@ var UdpAPI = class {
|
|
|
15786
15926
|
* @returns `true` once the session has been closed.
|
|
15787
15927
|
* @throws {CrowdyGraphQLError} on auth failures.
|
|
15788
15928
|
*/
|
|
15929
|
+
/**
|
|
15930
|
+
* Binary relay only: put the pending `MESSAGE_BUNDLE` on the wire now
|
|
15931
|
+
* instead of at the end of `realtime.bundleWindowMs`. Call it at the end of a
|
|
15932
|
+
* frame whose sends should not wait. No-op on the GraphQL transport, when
|
|
15933
|
+
* `realtime.bundleSends` is false, or when nothing is pending.
|
|
15934
|
+
*/
|
|
15935
|
+
flushSends() {
|
|
15936
|
+
this.subs.flushSends();
|
|
15937
|
+
}
|
|
15789
15938
|
async disconnect() {
|
|
15790
15939
|
if (this.subs.usingBinaryTransport()) {
|
|
15791
15940
|
this.subs.disconnect();
|
|
@@ -15905,6 +16054,7 @@ var UdpAPI = class {
|
|
|
15905
16054
|
const request = this.withSequence(input);
|
|
15906
16055
|
const wait = this.subs.waitForSequence(request.sequenceNumber, options.timeoutMs);
|
|
15907
16056
|
await this.sendActorUpdate(request);
|
|
16057
|
+
this.subs.flushSends();
|
|
15908
16058
|
return wait;
|
|
15909
16059
|
}
|
|
15910
16060
|
/**
|
|
@@ -15972,6 +16122,7 @@ var UdpAPI = class {
|
|
|
15972
16122
|
const request = this.withSequence(input);
|
|
15973
16123
|
const wait = this.subs.waitForSequence(request.sequenceNumber, options.timeoutMs);
|
|
15974
16124
|
await this.sendVoxelUpdate(request);
|
|
16125
|
+
this.subs.flushSends();
|
|
15975
16126
|
return wait;
|
|
15976
16127
|
}
|
|
15977
16128
|
/**
|
|
@@ -16030,6 +16181,7 @@ var UdpAPI = class {
|
|
|
16030
16181
|
const request = this.withSequence(input);
|
|
16031
16182
|
const wait = this.subs.waitForSequence(request.sequenceNumber, options.timeoutMs);
|
|
16032
16183
|
await this.sendAudioPacket(request);
|
|
16184
|
+
this.subs.flushSends();
|
|
16033
16185
|
return wait;
|
|
16034
16186
|
}
|
|
16035
16187
|
/**
|
|
@@ -16141,6 +16293,7 @@ var UdpAPI = class {
|
|
|
16141
16293
|
const request = this.withSequence(input);
|
|
16142
16294
|
const wait = this.subs.waitForSequence(request.sequenceNumber, options.timeoutMs);
|
|
16143
16295
|
await this.sendTextPacket(request);
|
|
16296
|
+
this.subs.flushSends();
|
|
16144
16297
|
return wait;
|
|
16145
16298
|
}
|
|
16146
16299
|
/**
|
|
@@ -16201,6 +16354,7 @@ var UdpAPI = class {
|
|
|
16201
16354
|
const request = this.withSequence(input);
|
|
16202
16355
|
const wait = this.subs.waitForSequence(request.sequenceNumber, options.timeoutMs);
|
|
16203
16356
|
await this.sendClientEvent(request);
|
|
16357
|
+
this.subs.flushSends();
|
|
16204
16358
|
return wait;
|
|
16205
16359
|
}
|
|
16206
16360
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crowdedkingdoms/crowdy-dsh",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1-dev.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -94,11 +94,11 @@
|
|
|
94
94
|
"crowdyDsh": {
|
|
95
95
|
"build": {
|
|
96
96
|
"package": "@crowdedkingdoms/crowdy-dsh",
|
|
97
|
-
"version": "0.3.
|
|
98
|
-
"builtAt": "2026-09-
|
|
97
|
+
"version": "0.3.1",
|
|
98
|
+
"builtAt": "2026-09-13T20:32:20.481Z",
|
|
99
99
|
"source": {
|
|
100
100
|
"repository": "CrowdedKingdoms/crowdy-dsh",
|
|
101
|
-
"commit": "
|
|
101
|
+
"commit": "fefcd8ee55fc6df8b16a09f6db19de1e8a3189db",
|
|
102
102
|
"dirty": false
|
|
103
103
|
},
|
|
104
104
|
"upstream": {
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
},
|
|
110
110
|
"crowdyjs": {
|
|
111
111
|
"name": "@crowdedkingdoms/crowdyjs",
|
|
112
|
-
"version": "17.0.1",
|
|
112
|
+
"version": "17.1.0-dev.1",
|
|
113
113
|
"source": "node_modules"
|
|
114
114
|
},
|
|
115
115
|
"files": {
|
|
@@ -206,7 +206,7 @@
|
|
|
206
206
|
"manifest.webmanifest": "sha256:9b54d57eea00f2fdd1affe6e7999a4209a515755f12ac1a3299da2d55e178d4c",
|
|
207
207
|
"preview/bootstrap-CYECZNXt.js": "sha256:9f303a0485c0badfdd19fad0c357ef050c5b9a343744ab5bf0c70015e7d95092",
|
|
208
208
|
"preview/crowdy-boot-Cklh1qNl.js": "sha256:b21e8eb126e1cd8a52159d2d577e610df6c8af36a436f9ed5028cfabd11a85ff",
|
|
209
|
-
"preview/vfs-image.tar.gz": "sha256:
|
|
209
|
+
"preview/vfs-image.tar.gz": "sha256:721074e8f744bc811e7c9cf18d486682cce88264014412671b7d5436a834cce6",
|
|
210
210
|
"preview/worker-C8-_ANaz.js": "sha256:81099e5732dfe0c32bacd5897316b7956c5a0a22da01b4a0c6e21d0a3b9d9aa1"
|
|
211
211
|
}
|
|
212
212
|
}
|