@crowdedkingdoms/crowdy-dsh 0.4.13-test.1 → 0.4.14-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.
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "package": "@crowdedkingdoms/crowdy-dsh",
3
- "version": "0.4.13",
4
- "builtAt": "2026-10-24T23:04:25.889Z",
3
+ "version": "0.4.14",
4
+ "builtAt": "2026-10-25T16:52:47.441Z",
5
5
  "source": {
6
6
  "repository": "CrowdedKingdoms/crowdy-dsh",
7
- "commit": "e04cd33909e335ec360c653e557139378a7f1dbc",
7
+ "commit": "1213a03852cfce7e27430a54ac79c4052be4b99f",
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": "18.20.0-test.1",
18
+ "version": "18.21.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:1b14864b2df102de16cd3f5042abe4c12c80d672a0e0803b4a926a972836af48",
115
+ "preview/vfs-image.tar.gz": "sha256:a4d7d014dcc9a00451a6609b3856d835ed8557044a600fea7ccad72a6d0c1625",
116
116
  "preview/worker-C8-_ANaz.js": "sha256:81099e5732dfe0c32bacd5897316b7956c5a0a22da01b4a0c6e21d0a3b9d9aa1"
117
117
  }
118
118
  }
@@ -17443,6 +17443,10 @@ var UdpAPI = class {
17443
17443
  * the resolved notification then carries the retry's sequence number. A
17444
17444
  * send whose `sequenceNumber` you chose is not retried, and neither is the
17445
17445
  * timeout of an audio, text or event send, which is how those succeed.
17446
+ * - An actor or voxel update still waiting when the client reconnects or moves
17447
+ * to another instance is resent, with a fresh sequence number, as soon as
17448
+ * the new session is up, rather than at its timeout: its echo went to the
17449
+ * session the client left. That is the send's one retry.
17446
17450
  *
17447
17451
  * @param options - `timeoutMs`: how long to wait for the echo once the send
17448
17452
  * is accepted, in milliseconds; defaults to the client's realtime
@@ -17993,28 +17997,41 @@ var UdpAPI = class {
17993
17997
  * its echo times out: a game server from before the one that holds a
17994
17998
  * session's first messages refuses or drops them while the session's
17995
17999
  * permissions load. A send the server does not echo (audio, text, a client
17996
- * event) succeeds by timing out, so its timeout is never retried. Only when
17997
- * the SDK chose the sequence number, because the retry needs one of its own
17998
- * and a caller who chose theirs is correlating by it.
18000
+ * event) succeeds by timing out, so its timeout is never retried.
18001
+ *
18002
+ * A send the server echoes that is still waiting when a new session is
18003
+ * established is resent then, once, rather than at its timeout: its echo went
18004
+ * to the session the client left. That retry is the send's one retry.
18005
+ *
18006
+ * Only when the SDK chose the sequence number, because a retry needs one of
18007
+ * its own and a caller who chose theirs is correlating by it.
17999
18008
  */
18000
18009
  async sendAndWait(input, timeoutMs, echoed, send) {
18001
18010
  const epoch = this.subs.sessionEpoch();
18002
- const retryable = epoch !== this.confirmedEpoch && input.sequenceNumber == null;
18011
+ const ownSequence = input.sequenceNumber == null;
18012
+ const retryable = epoch !== this.confirmedEpoch && ownSequence;
18013
+ let sentEpoch = epoch;
18014
+ const again = () => {
18015
+ sentEpoch = this.subs.sessionEpoch();
18016
+ return this.sendOnceAndWait(this.withSequence({ ...input, sequenceNumber: void 0 }), timeoutMs, send, false);
18017
+ };
18003
18018
  try {
18004
- const echo = await this.sendOnceAndWait(this.withSequence(input), timeoutMs, send).catch((error) => {
18019
+ const echo = await this.sendOnceAndWait(this.withSequence(input), timeoutMs, send, echoed && ownSequence).catch((error) => {
18020
+ if (error instanceof SessionChanged)
18021
+ return again();
18005
18022
  if (!retryable || !isFirstSendFailure(error, echoed))
18006
18023
  throw error;
18007
- return this.sendOnceAndWait(this.withSequence({ ...input, sequenceNumber: void 0 }), timeoutMs, send);
18024
+ return again();
18008
18025
  });
18009
- this.confirmedEpoch = epoch;
18026
+ this.confirmedEpoch = sentEpoch;
18010
18027
  return echo;
18011
18028
  } catch (error) {
18012
18029
  if (!echoed && isTimeout(error))
18013
- this.confirmedEpoch = epoch;
18030
+ this.confirmedEpoch = sentEpoch;
18014
18031
  throw error;
18015
18032
  }
18016
18033
  }
18017
- async sendOnceAndWait(request, timeoutMs, send) {
18034
+ async sendOnceAndWait(request, timeoutMs, send, endOnNewSession) {
18018
18035
  const wait = this.subs.expectSequence(request.sequenceNumber, timeoutMs);
18019
18036
  try {
18020
18037
  await send(request);
@@ -18024,7 +18041,20 @@ var UdpAPI = class {
18024
18041
  }
18025
18042
  this.subs.flushSends();
18026
18043
  wait.start();
18027
- return wait.promise;
18044
+ if (!endOnNewSession)
18045
+ return wait.promise;
18046
+ const epoch = this.subs.sessionEpoch();
18047
+ let stop = () => void 0;
18048
+ const changed = new Promise((_, reject) => {
18049
+ stop = this.subs.onStatus((status) => {
18050
+ if (status !== "connected" || this.subs.sessionEpoch() === epoch)
18051
+ return;
18052
+ wait.cancel();
18053
+ reject(new SessionChanged());
18054
+ });
18055
+ });
18056
+ changed.catch(() => void 0);
18057
+ return Promise.race([wait.promise, changed]).finally(() => stop());
18028
18058
  }
18029
18059
  withSequence(input) {
18030
18060
  return {
@@ -18033,6 +18063,8 @@ var UdpAPI = class {
18033
18063
  };
18034
18064
  }
18035
18065
  };
18066
+ var SessionChanged = class extends Error {
18067
+ };
18036
18068
  function isFirstSendFailure(error, echoed) {
18037
18069
  return error instanceof CrowdyRealtimeError && (error.code === "UNAUTHORIZED" || echoed && isTimeout(error));
18038
18070
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@crowdedkingdoms/crowdyjs",
3
- "version": "18.20.0-test.1",
3
+ "version": "18.21.0-dev.1",
4
4
  "source": "node_modules"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdedkingdoms/crowdy-dsh",
3
- "version": "0.4.13-test.1",
3
+ "version": "0.4.14-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.4.13",
98
- "builtAt": "2026-10-24T23:04:25.889Z",
97
+ "version": "0.4.14",
98
+ "builtAt": "2026-10-25T16:52:47.441Z",
99
99
  "source": {
100
100
  "repository": "CrowdedKingdoms/crowdy-dsh",
101
- "commit": "e04cd33909e335ec360c653e557139378a7f1dbc",
101
+ "commit": "1213a03852cfce7e27430a54ac79c4052be4b99f",
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": "18.20.0-test.1",
112
+ "version": "18.21.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:1b14864b2df102de16cd3f5042abe4c12c80d672a0e0803b4a926a972836af48",
209
+ "preview/vfs-image.tar.gz": "sha256:a4d7d014dcc9a00451a6609b3856d835ed8557044a600fea7ccad72a6d0c1625",
210
210
  "preview/worker-C8-_ANaz.js": "sha256:81099e5732dfe0c32bacd5897316b7956c5a0a22da01b4a0c6e21d0a3b9d9aa1"
211
211
  }
212
212
  }