@genex-ai/multiplayer 0.17.9 → 0.17.11

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.
@@ -9,10 +9,10 @@ import {
9
9
  } from "./chunk-4R7C2TLH.js";
10
10
  import {
11
11
  connectAuthority
12
- } from "./chunk-MQYARUGU.js";
13
- import "./chunk-TEHGMFAG.js";
12
+ } from "./chunk-I3DNVGGC.js";
13
+ import "./chunk-BB6OIWQ2.js";
14
14
  import "./chunk-YWQ3ALYY.js";
15
- import "./chunk-ZDGSUR6E.js";
15
+ import "./chunk-5WENVWVO.js";
16
16
  import "./chunk-OD6NRSX2.js";
17
17
  import {
18
18
  firstpersonWorld
@@ -22,7 +22,7 @@ import {
22
22
  CloseCode,
23
23
  ServerMessage,
24
24
  isReservedEventType
25
- } from "./chunk-WEMRRIHH.js";
25
+ } from "./chunk-2CSX5WA6.js";
26
26
 
27
27
  // src/bridge-authority.ts
28
28
  import { getAuthorityRegions, getAuthorityUrls, getColyseusAuth } from "@genex-ai/embed-sdk";
package/dist/bridge.js CHANGED
@@ -15,14 +15,14 @@ import {
15
15
  joinPrivate,
16
16
  matchmake,
17
17
  roomOf
18
- } from "./chunk-DJ2XYETS.js";
19
- import "./chunk-TEHGMFAG.js";
18
+ } from "./chunk-OESKZODQ.js";
19
+ import "./chunk-BB6OIWQ2.js";
20
20
  import {
21
21
  Limits,
22
22
  RESERVED_SHARED_PREFIX,
23
23
  ServerMessage,
24
24
  isReservedEventType
25
- } from "./chunk-WEMRRIHH.js";
25
+ } from "./chunk-2CSX5WA6.js";
26
26
 
27
27
  // src/bridge.ts
28
28
  var version = 2;
@@ -55,7 +55,7 @@ var AuthorityJoinOption = {
55
55
  * refused with 400. */
56
56
  SUCCESSOR_CLOSED: "successorClosed"
57
57
  };
58
- var AUTHORITY_SDK_LABEL = "ts/0.17.9";
58
+ var AUTHORITY_SDK_LABEL = "ts/0.17.11";
59
59
  var AuthorityCaps = {
60
60
  /** Decodes and draws §17.10's physics bodies. A physics room refuses a join without it (426). An
61
61
  * SDK sends it only once its drawing passes `physics-draw.json` and, for an engine SDK, its own
@@ -19,7 +19,7 @@ import {
19
19
  JoinError,
20
20
  Limits,
21
21
  isReservedEventType
22
- } from "./chunk-WEMRRIHH.js";
22
+ } from "./chunk-2CSX5WA6.js";
23
23
 
24
24
  // src/authority/room-key.ts
25
25
  var AuthorityRoomLimits = {
@@ -31,6 +31,7 @@ var AuthorityRoomLimits = {
31
31
  MAX_WORLDS: 16
32
32
  };
33
33
  var ROOM_NOT_FOUND = 522;
34
+ var ROOM_NOT_FOUND_AS_SENT = 500;
34
35
  var inRange = (c, lo, hi) => c >= lo.charCodeAt(0) && c <= hi.charCodeAt(0);
35
36
  var isLowerOrDigit = (c) => inRange(c, "a", "z") || inRange(c, "0", "9");
36
37
  var KEY_MARKS = "._:-";
@@ -55,7 +56,7 @@ function matchKeyOf(value2) {
55
56
  if (value2 === void 0 || value2 === "") return "";
56
57
  return validMatchKey(value2) ? value2 : null;
57
58
  }
58
- var AuthorityJoinMethod = { JoinOrCreate: "joinOrCreate", Create: "create", JoinById: "joinById" };
59
+ var AuthorityJoinMethod = { JoinOrCreate: "joinOrCreate", Create: "create", JoinById: "joinById", Join: "join" };
59
60
  var AuthorityTargetRefusal = { BadMatchKey: "bad_match_key", BadCode: "bad_code", Conflict: "conflict" };
60
61
  function planAuthorityJoin(target) {
61
62
  const key = target.matchKey ?? "";
@@ -71,7 +72,7 @@ function planAuthorityJoin(target) {
71
72
  return { method: AuthorityJoinMethod.JoinOrCreate, options };
72
73
  }
73
74
  function nextCodeRegion(error, region, regions) {
74
- const elsewhere = error === JoinError.WRONG_REGION || error === ROOM_NOT_FOUND;
75
+ const elsewhere = error === JoinError.WRONG_REGION || error === ROOM_NOT_FOUND || error === ROOM_NOT_FOUND_AS_SENT;
75
76
  return elsewhere && region + 1 < regions ? region + 1 : null;
76
77
  }
77
78
  function selectMatchWorld(worlds, world, key) {
@@ -2,7 +2,7 @@ import {
2
2
  ClientReconnection,
3
3
  JoinError,
4
4
  PROTOCOL_VERSION
5
- } from "./chunk-WEMRRIHH.js";
5
+ } from "./chunk-2CSX5WA6.js";
6
6
 
7
7
  // src/join.ts
8
8
  import { Client as Client2 } from "@colyseus/sdk";
@@ -5,7 +5,7 @@ import {
5
5
  joinOptions,
6
6
  useSdkReconnection,
7
7
  waitForFirstState
8
- } from "./chunk-TEHGMFAG.js";
8
+ } from "./chunk-BB6OIWQ2.js";
9
9
  import {
10
10
  udpFastOpener
11
11
  } from "./chunk-YWQ3ALYY.js";
@@ -60,7 +60,7 @@ import {
60
60
  serverTick,
61
61
  tickInstant,
62
62
  validRoomCode
63
- } from "./chunk-ZDGSUR6E.js";
63
+ } from "./chunk-5WENVWVO.js";
64
64
  import {
65
65
  RemotePredict
66
66
  } from "./chunk-OD6NRSX2.js";
@@ -88,10 +88,18 @@ import {
88
88
  RoomType,
89
89
  ServerMessage,
90
90
  authorityCloseCodeOf
91
- } from "./chunk-WEMRRIHH.js";
91
+ } from "./chunk-2CSX5WA6.js";
92
92
 
93
93
  // src/authority/regions.ts
94
94
  var AUTHORITY_REFUSALS_PER_REGION = 2;
95
+ var AUTHORITY_MAX_PING_MS = 350;
96
+ var AUTHORITY_REGROUP_WAITS_MS = [2e3, 4e3, 9e3, 15e3, 3e4];
97
+ var RegionRule = {
98
+ /** A room with players in any region in reach, nearest first; else a new room in the nearest region. */
99
+ Players: "players",
100
+ /** The nearest region alone, whoever is elsewhere. */
101
+ Nearest: "nearest"
102
+ };
95
103
  var isUrl = (u) => typeof u === "string" && u.length > 0;
96
104
  function normalizeAuthorityRegions(regions, urls) {
97
105
  const out = [];
@@ -113,6 +121,9 @@ function regionProbePlan(urls, samples) {
113
121
  }
114
122
  var answered = (ms) => typeof ms === "number" && Number.isFinite(ms) && ms >= 0;
115
123
  function rankAuthorityRegions(regions, best) {
124
+ return rankWithLatency(regions, best).map((x) => x.pick);
125
+ }
126
+ function rankWithLatency(regions, best) {
116
127
  const heard = [];
117
128
  const silent = [];
118
129
  regions.forEach((r, index) => {
@@ -127,7 +138,17 @@ function rankAuthorityRegions(regions, best) {
127
138
  (ms === null ? silent : heard).push({ index, ms, pick: { region: r.region, url } });
128
139
  });
129
140
  heard.sort((a, b) => a.ms - b.ms || a.index - b.index);
130
- return [...heard, ...silent].map((x) => x.pick);
141
+ return [...heard, ...silent];
142
+ }
143
+ function planAuthoritySearch(regions, best, options = {}) {
144
+ const ranked = rankWithLatency(regions, best);
145
+ const create = ranked.map((x) => x.pick);
146
+ const pinned = typeof options.region === "string" ? ranked.find((x) => x.pick.region === options.region) : void 0;
147
+ if (pinned !== void 0) return { search: [], create: [pinned.pick] };
148
+ if (options.rule === RegionRule.Nearest) return { search: [], create };
149
+ const limit = answered(options.maxPingMs) ? options.maxPingMs : AUTHORITY_MAX_PING_MS;
150
+ const reach = ranked.filter((x) => x.ms !== null && x.ms <= limit).map((x) => x.pick);
151
+ return { search: reach.length >= 2 ? reach : [], create };
131
152
  }
132
153
  function capacityWalk(regionCount, delays) {
133
154
  const attempts = [{ region: 0, waitMs: 0 }];
@@ -151,6 +172,34 @@ function refusalKind(code) {
151
172
  if (typeof code !== "number" || code <= 0 || DEAD_PATH_REFUSALS.has(code)) return RefusalKind.NextRegion;
152
173
  return CAPACITY_REFUSALS.has(code) ? RefusalKind.Capacity : RefusalKind.Final;
153
174
  }
175
+ function planAuthorityRegroup(regions, best, options = {}, joined) {
176
+ if (options.rule === RegionRule.Nearest) return [];
177
+ if (typeof options.region === "string" && regions.some((r) => r.region === options.region)) return [];
178
+ const at2 = regions.findIndex((r) => r.region === joined);
179
+ if (at2 < 0) return [];
180
+ const limit = answered(options.maxPingMs) ? options.maxPingMs : AUTHORITY_MAX_PING_MS;
181
+ return rankWithLatency(regions, best).filter((x) => x.index < at2 && x.ms !== null && x.ms <= limit).map((x) => x.pick);
182
+ }
183
+ function authorityRegionOf(regions, url) {
184
+ return regions.find((r) => r.urls.includes(url))?.region;
185
+ }
186
+ async function measureAuthorityRegions(regions, options = {}) {
187
+ const best = regions.length <= 1 ? [] : await probeAuthorityRegions(regions, options);
188
+ return regions.map((r, i) => {
189
+ const heard = (best[i] ?? []).filter(answered);
190
+ return { region: r.region, pingMs: heard.length === 0 ? null : Math.min(...heard) };
191
+ });
192
+ }
193
+ var SearchRefusal = {
194
+ /** No room here (Colyseus's 521, no room matches the criteria), a dead path, a full or draining
195
+ * region: the next region is asked. */
196
+ Next: "next",
197
+ /** The server's answer about this player or game, which every region would repeat. */
198
+ Final: "final"
199
+ };
200
+ function searchRefusalKind(code) {
201
+ return refusalKind(code) === RefusalKind.Final ? SearchRefusal.Final : SearchRefusal.Next;
202
+ }
154
203
  function nextAttempt(state, regionCount, delays) {
155
204
  const refused = state.refused + 1;
156
205
  if (refused >= AUTHORITY_REFUSALS_PER_REGION && state.region + 1 < regionCount) {
@@ -164,10 +213,13 @@ function nextAttempt(state, regionCount, delays) {
164
213
  async function selectAuthorityRegions(regions, options = {}) {
165
214
  if (regions.length === 0) return [];
166
215
  if (regions.length === 1) return rankAuthorityRegions(regions, []);
216
+ return rankAuthorityRegions(regions, await probeAuthorityRegions(regions, options));
217
+ }
218
+ async function probeAuthorityRegions(regions, options) {
167
219
  const samples = Math.max(1, options.samples ?? RELAY_SELECT_DEFAULTS.SAMPLES);
168
220
  const plans = regions.map((r) => regionProbePlan(r.urls, samples));
169
221
  const results = await probeLatencies(plans, options);
170
- const best = regions.map(
222
+ return regions.map(
171
223
  (r, i) => r.urls.map((url) => {
172
224
  let min;
173
225
  plans[i]?.forEach((planned, n) => {
@@ -177,7 +229,10 @@ async function selectAuthorityRegions(regions, options = {}) {
177
229
  return min;
178
230
  })
179
231
  );
180
- return rankAuthorityRegions(regions, best);
232
+ }
233
+ async function selectAuthoritySearch(regions, search = {}, options = {}) {
234
+ if (regions.length <= 1) return planAuthoritySearch(regions, [], search);
235
+ return planAuthoritySearch(regions, await probeAuthorityRegions(regions, options), search);
181
236
  }
182
237
  async function probeLatencies(plans, options = {}) {
183
238
  const probe = options.probe ?? defaultProbe;
@@ -300,6 +355,8 @@ function survivingSession(first, deps) {
300
355
  const listeners = /* @__PURE__ */ new Map();
301
356
  let current = first;
302
357
  let left = false;
358
+ let rejoining = false;
359
+ let endWait = null;
303
360
  let physicsHash = null;
304
361
  let world = null;
305
362
  const fire = (event, ...payload) => {
@@ -312,6 +369,14 @@ function survivingSession(first, deps) {
312
369
  });
313
370
  };
314
371
  const rejoin = async (lostCode, lostReason) => {
372
+ rejoining = true;
373
+ try {
374
+ await replaceLostRoom(lostCode, lostReason);
375
+ } finally {
376
+ rejoining = false;
377
+ }
378
+ };
379
+ const replaceLostRoom = async (lostCode, lostReason) => {
315
380
  const startedAt = now();
316
381
  const lost = { roomId: current.code, matchKey: current.matchKey, closed: deps.closed };
317
382
  const regions = deps.targets.length;
@@ -362,6 +427,46 @@ function survivingSession(first, deps) {
362
427
  });
363
428
  };
364
429
  watch(first);
430
+ const regroupWait = (ms) => {
431
+ if (deps.sleep !== void 0) return deps.sleep(ms);
432
+ return new Promise((resolve) => {
433
+ const timer = setTimeout(done, ms);
434
+ timer.unref?.();
435
+ function done() {
436
+ clearTimeout(timer);
437
+ endWait = null;
438
+ resolve();
439
+ }
440
+ endWait = done;
441
+ });
442
+ };
443
+ const regroup = async (ask) => {
444
+ const waits = AUTHORITY_REGROUP_WAITS_MS;
445
+ let step = 0;
446
+ while (!left) {
447
+ await regroupWait(waits[Math.min(step, waits.length - 1)]);
448
+ if (left) return;
449
+ if (rejoining || current.players().size > 1) {
450
+ step = 0;
451
+ continue;
452
+ }
453
+ step += 1;
454
+ const next = await ask().catch(() => null);
455
+ if (next === null) continue;
456
+ if (left || rejoining || current.players().size > 1) {
457
+ await next.leave().catch(() => {
458
+ });
459
+ continue;
460
+ }
461
+ const empty = current;
462
+ adopt(next);
463
+ fire(RejoinEvent.Rejoined, { code: next.code, url: next.url, moved: true });
464
+ await empty.leave().catch(() => {
465
+ });
466
+ step = 0;
467
+ }
468
+ };
469
+ if (deps.regroup !== void 0) void regroup(deps.regroup.bind(deps));
365
470
  const own = {
366
471
  input,
367
472
  frame(frameNow) {
@@ -392,6 +497,7 @@ function survivingSession(first, deps) {
392
497
  },
393
498
  async leave() {
394
499
  left = true;
500
+ endWait?.();
395
501
  await current.leave();
396
502
  }
397
503
  };
@@ -5288,23 +5394,47 @@ function resimBudgetMs() {
5288
5394
  const agent = typeof navigator === "undefined" ? "" : String(navigator.userAgent ?? "");
5289
5395
  return /Mobi|Android|iPhone|iPad/i.test(agent) ? PHYS_RESIM_BUDGET_MS.mobile : PHYS_RESIM_BUDGET_MS.desktop;
5290
5396
  }
5291
- async function joinTargets(opts) {
5292
- if (opts.url) return [opts.url];
5397
+ async function joinTargets(opts, method) {
5398
+ if (opts.url) return { search: [], create: [opts.url], regroup: () => [] };
5293
5399
  const regions = normalizeAuthorityRegions(opts.regions, opts.urls);
5294
5400
  if (regions.length === 0) throw new Error("genex multiplayer: `urls` must contain at least one authority server URL");
5295
- const ranked = await selectAuthorityRegions(regions, opts.probe === void 0 ? {} : { probe: opts.probe });
5296
- return ranked.map((pick) => pick.url);
5401
+ const pool = method === AuthorityJoinMethod.JoinOrCreate;
5402
+ const options = {
5403
+ rule: pool ? opts.regionRule : RegionRule.Nearest,
5404
+ maxPingMs: opts.maxPingMs,
5405
+ ...method === AuthorityJoinMethod.JoinById ? {} : { region: opts.region }
5406
+ };
5407
+ const best = regions.length <= 1 ? [] : await probeAuthorityRegions(regions, opts.probe === void 0 ? {} : { probe: opts.probe });
5408
+ const plan = planAuthoritySearch(regions, best, options);
5409
+ return {
5410
+ search: plan.search.map((pick) => pick.url),
5411
+ create: plan.create.map((pick) => pick.url),
5412
+ regroup: (url) => planAuthorityRegroup(regions, best, options, authorityRegionOf(regions, url) ?? "").map((pick) => pick.url)
5413
+ };
5414
+ }
5415
+ async function joinWherePlayersAre(opts, plan, search, where) {
5416
+ for (const url of search) {
5417
+ try {
5418
+ return { room: await joinOnce(new Client(url), opts, { ...plan, method: AuthorityJoinMethod.Join }), url, ...where };
5419
+ } catch (err) {
5420
+ if (searchRefusalKind(errorCode(err)) === SearchRefusal.Final) explainAuthorityRefusal(err);
5421
+ }
5422
+ }
5423
+ return null;
5297
5424
  }
5298
5425
  async function joinAuthority(opts, target) {
5299
5426
  const plan = planAuthorityJoin(target);
5300
5427
  if ("refused" in plan) throw new TypeError(`genex multiplayer: this room cannot be asked for (${plan.refused})`);
5301
- const targets = await joinTargets(opts);
5428
+ const { search, create: targets, regroup: regroupOf } = await joinTargets(opts, plan.method);
5429
+ const regroup = plan.method === AuthorityJoinMethod.JoinOrCreate ? regroupOf : () => [];
5430
+ const found = await joinWherePlayersAre(opts, plan, search, { targets, regroup });
5431
+ if (found !== null) return found;
5302
5432
  const delays = opts.capacityRetryMs ?? CAPACITY_RETRY_MS;
5303
5433
  let state = { region: 0, refused: 0, step: 0 };
5304
5434
  for (; ; ) {
5305
5435
  const url = targets[state.region];
5306
5436
  try {
5307
- return { room: await joinOnce(new Client(url), opts, plan), url, targets };
5437
+ return { room: await joinOnce(new Client(url), opts, plan), url, targets, regroup };
5308
5438
  } catch (err) {
5309
5439
  if (plan.method === AuthorityJoinMethod.JoinById) {
5310
5440
  const region = nextCodeRegion(errorCode(err), state.region, targets.length);
@@ -5341,6 +5471,7 @@ function joinOnce(client, opts, plan) {
5341
5471
  };
5342
5472
  if (plan.method === AuthorityJoinMethod.JoinById) return client.joinById(plan.roomId, options);
5343
5473
  if (plan.method === AuthorityJoinMethod.Create) return client.create(RoomType.AUTHORITY, options);
5474
+ if (plan.method === AuthorityJoinMethod.Join) return client.join(RoomType.AUTHORITY, options);
5344
5475
  return client.joinOrCreate(RoomType.AUTHORITY, options);
5345
5476
  }
5346
5477
  function roomPreset(presetText) {
@@ -5409,15 +5540,33 @@ async function joinPrivateAuthority(code, opts) {
5409
5540
  function comingBack(session, opts, joined, closed) {
5410
5541
  if (opts.rejoin === false) return session;
5411
5542
  const others = joined.targets.filter((url) => url !== joined.url);
5543
+ const seatAt = async (url, plan) => {
5544
+ const room = await joinOnce(new Client(url), opts, plan);
5545
+ const next = attachAuthoritySession(useSdkReconnection(room), opts, url);
5546
+ await waitForFirstState(room, ClientReconnection.firstStateTimeoutMs);
5547
+ return next;
5548
+ };
5549
+ let here = joined.url;
5550
+ const pool = {
5551
+ method: AuthorityJoinMethod.Join,
5552
+ options: opts.matchKey === void 0 || opts.matchKey === "" ? {} : { matchKey: opts.matchKey }
5553
+ };
5554
+ const regroup = async () => {
5555
+ for (const url of joined.regroup(here)) {
5556
+ try {
5557
+ const next = await seatAt(url, pool);
5558
+ here = url;
5559
+ return next;
5560
+ } catch {
5561
+ }
5562
+ }
5563
+ return null;
5564
+ };
5412
5565
  return survivingSession(session, {
5413
5566
  closed,
5414
5567
  targets: [joined.url, ...others],
5415
- join: async (url, way, lost) => {
5416
- const room = await joinOnce(new Client(url), opts, rejoinPlan(way, lost));
5417
- const next = attachAuthoritySession(useSdkReconnection(room), opts, url);
5418
- await waitForFirstState(room, ClientReconnection.firstStateTimeoutMs);
5419
- return next;
5420
- }
5568
+ join: (url, way, lost) => seatAt(url, rejoinPlan(way, lost)),
5569
+ ...opts.regroup === false || joined.regroup(here).length === 0 ? {} : { regroup }
5421
5570
  });
5422
5571
  }
5423
5572
  function rejoinPlan(way, lost) {
@@ -6729,13 +6878,24 @@ function attachAuthoritySession(room, opts, url) {
6729
6878
 
6730
6879
  export {
6731
6880
  AUTHORITY_REFUSALS_PER_REGION,
6881
+ AUTHORITY_MAX_PING_MS,
6882
+ AUTHORITY_REGROUP_WAITS_MS,
6883
+ RegionRule,
6732
6884
  normalizeAuthorityRegions,
6733
6885
  regionProbePlan,
6734
6886
  rankAuthorityRegions,
6887
+ planAuthoritySearch,
6735
6888
  capacityWalk,
6736
6889
  RefusalKind,
6737
6890
  refusalKind,
6891
+ planAuthorityRegroup,
6892
+ authorityRegionOf,
6893
+ measureAuthorityRegions,
6894
+ SearchRefusal,
6895
+ searchRefusalKind,
6738
6896
  selectAuthorityRegions,
6897
+ probeAuthorityRegions,
6898
+ selectAuthoritySearch,
6739
6899
  REJOIN,
6740
6900
  SUCCESSOR_OPEN_MS,
6741
6901
  RejoinWay,
@@ -8,7 +8,7 @@ import {
8
8
  waitForFirstState,
9
9
  warnProtocolRefusal,
10
10
  withoutReconnection
11
- } from "./chunk-TEHGMFAG.js";
11
+ } from "./chunk-BB6OIWQ2.js";
12
12
  import {
13
13
  ClientMessage,
14
14
  ClientReconnection,
@@ -23,7 +23,7 @@ import {
23
23
  SEND_TIME_KEY,
24
24
  ServerMessage,
25
25
  isReservedEventType
26
- } from "./chunk-WEMRRIHH.js";
26
+ } from "./chunk-2CSX5WA6.js";
27
27
 
28
28
  // src/index.ts
29
29
  import { getStateCallbacks } from "@colyseus/sdk";
package/dist/index.js CHANGED
@@ -3,9 +3,9 @@ import {
3
3
  createPrivate,
4
4
  joinPrivate,
5
5
  matchmake
6
- } from "./chunk-DJ2XYETS.js";
7
- import "./chunk-TEHGMFAG.js";
8
- import "./chunk-WEMRRIHH.js";
6
+ } from "./chunk-OESKZODQ.js";
7
+ import "./chunk-BB6OIWQ2.js";
8
+ import "./chunk-2CSX5WA6.js";
9
9
  export {
10
10
  connect,
11
11
  createPrivate,
@@ -76,7 +76,7 @@ interface AuthorityDrainNotice {
76
76
  drainMs: number;
77
77
  }
78
78
  /** The SDK label this TypeScript client sends. tests hold it to package.json. */
79
- declare const AUTHORITY_SDK_LABEL = "ts/0.17.9";
79
+ declare const AUTHORITY_SDK_LABEL = "ts/0.17.11";
80
80
  /** Client capabilities (§17.10 *Joining*). */
81
81
  declare const AuthorityCaps: {
82
82
  /** Decodes and draws §17.10's physics bodies. A physics room refuses a join without it (426). An
package/dist/protocol.js CHANGED
@@ -50,7 +50,7 @@ import {
50
50
  isReservedEventType,
51
51
  roomKeyFor,
52
52
  slugOfRoomKey
53
- } from "./chunk-WEMRRIHH.js";
53
+ } from "./chunk-2CSX5WA6.js";
54
54
  export {
55
55
  AUTHORITY_ENCODER_BUFFER_BYTES,
56
56
  AUTHORITY_MAX_FRAME_BYTES,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/multiplayer",
3
- "version": "0.17.9",
3
+ "version": "0.17.11",
4
4
  "description": "The multiplayer client wrapper + shared room schema for genex.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",